概述
我们上一讲供应链系统设计-供应链中台系统设计(七)- 商品中心设计篇中,对于什么是一个好的商品中心分别在业务标准方面和质量标准给了定义:
我们从业务的视角,暂且将一个好的商品中心的标准定义为以下三点:
1、需要构建商品标准体系,防止商品应用数据泛滥;
2、商品中心作为中台的一部分,应该抽象前台业务的共性需求,让中台商品能力复用最大化,以此来提高前端业务的效率;
3、商品生命周期需要保证围绕供应链进销存协同一致;
在系统质量标准上,好的标准定义为以下四点:
1、数据正确性。商品作为主数据,数据的正确性的重要是不言而喻,因此,需要有纠错的机制和能力;
2、海量的商品数据。根据SPU/CSPU/SKU/ITEM的概念,商品数据会随着业务的发展会不断的成倍增长;
3、高并发读请求。商品数据在某些场景下是典型的读多写少的访问场景,需要支撑前台业务高并发的读请求;
4、模型和系统稳定性要求高。商品中心作为最底层的主数据服务,几乎前台业务所有的应用都会依赖它,因此,领域模型的稳定性和系统的稳定性就非常重要。如果商品模型经常变化,经常性修改势必会影响到前台业务的稳定性。
不同的公司,不同的行业,不同的业务其实对于好的标准都会存在差异。因此,在这里的业务和质量标准不一定是使用其他公司和业务,在这里仅仅只是举例说明。
我们在 供应链系统设计-供应链中台系统设计(七)- 商品中心设计篇中,已从业务视角的一个好的商品中心如何来进行实现。
本文主要描述一下从系统质量的角度来看,如何来进行实现,一一进行描述,以便给大家提供一种实现的思路。
质量诉求实现
以下依次按商品中心数据正确性保证、海量数据存储、高并发场景读取和系统稳定性保障四个方面分别进行详细描述。
商品中心数据正确性保证
商品数据泛滥之前我们也聊过,为了避免泛滥,我们构建了SPU/CSPU/ITEM/SKU等概念,从并且也引用了相关的关系,如下图:
但是有这些模型概念还是不够的,最主要需要有一定的监管机制。随着业务的发展,SPU除了商品发布的规范化,会渐渐地腐化,SPU以及CSPU出现大量的重复的产品。
以Apple iPhone 4为例,产品库中存在大量重复的SPU。
同时,也容易出现SPU信息不准确的问题。
其实从上图,我们其实可以看出在SPU和CSPU这个维度还存在很多不标准或重复的情况。因此,从商品数据治理,聚焦到SPU和CSPU商品的治理。
为了大家更好的理解SPU和CSPU,在和大家简要的说明一下SPU和CSPU的概念,以便更好的进行理解。
SPU的英文全称是Standard Product Unit,即:标准产品单元。SPU 是一组可复用、易检索的标准化信息的集合,该集合描述了一个"产品"的特性。
SPU主要是对类目属性的一个补充说明,主要是通过关键属性、绑定属性以及销售属性等来决定。
关键性:用来决定和定义一个商品。例如:小米15手机,就决定了品牌是小米。
绑定属性:绑定属性可以被理解为是对产品核心特征的延伸和具体化,它们为产品的基本信息提供了额外的细节和说明。例如:Dell XPS 13,你需要查看这款笔记本电脑的绑定属性,这些属性会提供更多关于产品的具体信息,帮助你了解这款笔记本是否满足你的特定需求。
绑定属性可能包括:
- 处理器型号:Intel Core i7-1165G7
- 内存容量:16GB LPDDR4x
- 存储类型和容量:512GB NVMe SSD
- 屏幕分辨率:1920 x 1080 (Full HD)
- 显卡类型:Intel Iris Xe Graphics
- 操作系统:Windows 10 Home
- 电池寿命:最长可达8小时
- 尺寸和重量:11.6英寸 x 7.8英寸 x 0.58英寸,重量约2.64磅
通过查看这些绑定属性,你可以更清楚地了解这款笔记本的性能、存储能力、显示效果、图形处理能力、操作系统以及便携性等关键信息。
其实SPU很大程度上就是决定了商品的关键属性和绑定属性。SPU = 关键属性 + 绑定属性。
CSPU英文全称是Child Standard Product Unit,即子标准产品单元。SPU+销售属性确定唯一的CSPU。
例如:Dell XPS 13 + Intel Core i7 + 512GB,就是一个CSPU。是唯一确定可以售卖的最小单位。
以上就是SPU和CSPU的概念。
为什么需要治理SPU与CSPU?因为SPU与CSPU定义的是商品规范,从以上就可以看出,商品数据重复以及泛滥主要在SPU以及CSPU的上。因此,针对SPU+CSPU的治理,是非常有必要的。
因此,需要对于SPU/CSPU引入人工纠错和系统去重的能力,如下图所示:
一个商品信息管理流程,主要涉及两个概念:SPU(标准产品单元)和CSPU(定制化标准产品单元)。流程分为几个关键步骤:
-
信息纠错:当发现SPU或CSPU信息有误时,可以提交纠错请求,经过审核后更新信息。
-
创建SPU/CSPU:商户或运营人员创建新的SPU或CSPU,然后提交审核。
-
审核流程:新创建的SPU或CSPU需要经过商品运营的审核。
-
判重检查:审核通过后,系统会检查新商品是否与现有商品重复。
-
商品上架:审核和判重通过后,商品可以上架销售。
流程确保商品信息准确无误,避免错误信息误导消费者,防止重复商品上架,保持商品库的整洁和有序,提高商品管理的效率和质量。但是引入了流程,可能过于复杂,增加操作难度,审核和判重可能延迟商品上架时间。因此需要根据不同的业务场景利弊来进行流程复杂度以及自动化的程度。但是对于系统设计来说,纠错以及判重的能力是商品系统的核心能力,这些业务能力需要随着业务发展不断的迭代,是指与业务进行匹配,对于SPU/CSPU的商品的治理起到非常的作用。
商品中心海量商品数据存储
对于商品中心核心模型,我相信大家通过之前的了解其实核心模型主要是SPU/CSPU/ITEM/SKU,SPU/CSPU是整个平台进行共享的,而ITEM/SKU大部分都是商家创建的,所以ITEM/SKU的维度是商家级别的,SPU/CSPU的维度是平台级别的。因此,ITEM/SKU的数据会随着商户的增加,也会成倍的增加,如下图所示:
SPU/CSPU是平台级别的,ITEM/SKU是商户级别的。例如:淘宝的SPU/CSPU数量就巨大,淘宝作为全球最大的电商平台之一,涵盖了几乎所有的商品类别,从电子产品、服装、家居用品到食品等。每个大类下又有众多细分品类,每个细分品类下又有多个品牌和型号。例如,仅手机这一品类,就有苹果、华为、小米等多个品牌,每个品牌又有多个型号,每个型号又是一个SPU。
淘宝的SPU和CSPU数量都非常庞大,具体数量难以精确统计,但可以肯定的是,SPU数量可能达到数千万甚至上亿,而CSPU数量则可能达到数亿甚至更多。反映了淘宝平台上商品的丰富多样性和精细化管理。
基于商户级别的ITEM/SKU的量就更不说了,是非常恐怖的。因此,对于这样海量的数据我们如何来进行架构设计,是非常具有挑战的。
大家再往下想一层,基于SPU/CSPU/ITEM/SKU有没有衍生出来的其他相关的信息呢?如果在企业里面稍微有开发经验的同学都会想到,针对商品这类数据的增删改查,一定会留下记录的,以便出现问题可以进行追溯,对于一些非常重要的数据我们还要留下快照,以便后续除了问题可以进行紧急的恢复。如下图所示:
那这样就会越来越复杂了,操作日志和快速数据,往往会比SPU/CSPU/ITEM/SKU本身的信息要多上好几倍,这样对于数据存储来说就会有更大的挑战了。但是我们从数据本身的维度来切开进行针对性的处理。
核心数据与非核心数据
针对SPU/CSPU/ITEM/SKU、操作日志以及快照数据。我们需要确定那些是核心数据,那些是非核心数据。因为针对核心数据的存储和非核心数据的存储方式也是不一样,而且对于一些非核心数据也不需要联机事务OLTP的支持。因此,对于操作日志以及快照数据我们就认定非核心数据,不需要支持不需要联机事务OLTP的支持,只是业务在出现问题或纠纷的时候,需要进行查看。如下图所示
既然针对核心数据和非核心数据,最好的方式就是引入异构存储架构,对于核心数据采购一套存储架构,对于非核心数据采取另外一套架构,这样不仅仅就是业务场景对于技术的要求,也是运维成本上的优化,其实存储成本对于大规模的数据来说,也是非常高的成本。
对于核心数据来说,我们采取MYSQL来进行存储,因为核心数据,需要联机事务外,对于数据安全性、可靠性需要有比较强的要求。
对于非核心数据来说,商品操作日志,商品快照,我们都会放到其他的nosql数据存储里去,分别存储到hbase,mongodb。
核心数据存储方案
对于SPU/CSPU/ITEM/SKU的存储方案,且不说ITEM/SKU的数据量,就单单SPU/CSPU的数据量可能就会上亿,因此,我们在设计存储方案的时,需要为数据容量进行规划
数据容量规划
SPU/CSPU,对于一般中小平台来说,一般SPU在几百万的规模,如果CSPU再翻一个10倍。那么就是几千万,甚至上亿。我们还要考虑到后期如果业务出现爆发增长,或业务模式出现会变更后导致SPU/CSPU数据翻倍,因此,对于SPU/CSPU来说,我对于容量架构设计要求都需要支持上亿的数据。
我们在这边对于数据表进行简化,假设SPU/CSPU的数据表为:T_SPU_INFO,T_CSPU_INFO。
对于上亿的数据,而且支持联机事务,我们选择最主流程数据库,MYSQL。对于上亿的数据的读写,我们不可能存在一个库和一张表中,而且还需要考虑到单表的读写性能的问题。因此,需要针对MYSQL进行分库分表的设计。
对于上亿数据,我们暂且 8个库的一共64张订单表里去,每个表里会放1亿 / 64 = 150w左右的数据,每个表里才150w数据,数据量变少了,我们SQL读写性能会大幅度的提升,单库单表上亿数据全量复制到8库8表(64个表)中去。
分表需要解决的问题
**分表就是解决单表数据量读和写的瓶颈问题。**当单个数据库表的数据量达到数千万以及上亿条时,可能会对SQL查询性能产生显著影响,导致查询速度变慢。根据我的经验,当单表数据量达到几百万条时,性能就会开始下降,这时就有必要考虑进行分表操作了。
分表是指将一个表中的数据分散存储到多个表中。这样做的好处是,当你需要查询或操作某个用户的数据时,只需访问包含该用户数据的特定表,而不是整个大表。例如,可以根据用户ID来分表,将每个用户的数据存放在单独的表中。这样,每个表的数据量可以控制在一个合理的范围内,比如每个表不超过200万条记录。因此,我们上面数据容量规划的重要性也就凸显出来。
通过分表,可以有效地管理和优化数据库性能,确保查询操作的效率。这种方法有助于避免因数据量过大而导致的查询性能问题,使得数据库操作更加高效和可靠。
分库需要解决的问题
**分库其实就是解决单机硬件读和写的问题。**包括:单机磁盘读写的性能限制、单据网络带宽限制、单机内存限制,以及单机线程以及CPU的限制。
分库分表唯一ID设计
SPU/CSPU
ITEM/SKU
分库基于商户_ID的后三位对 8 进⾏hash取模。
库 = 商户_id 后三位 % 库数 8
表 = 商户_id 后三位 / 库数 8 % 单库表数 64
非核心数据存储方案
快照使用HBase来进行存储
HBase 是一个分布式、可扩展的大数据存储系统,它建立在 Hadoop 文件系统(HDFS)之上,非常适合写密集型应用。以下是 HBase 适用的一些典型场景:
-
写密集型应用:适用于每天写入量巨大、读操作相对较少的场景,如微信历史消息、游戏日志等。
-
快速随机访问需求:需要对单条记录或小范围数据进行快速查询的应用,HBase 支持基于 row key 的快速查询。
-
高性能和高可靠性要求:对性能和可靠性要求极高的应用,HBase 由于没有单点故障,因此具有很高的可用性。
-
数据量增长不可预估的应用:适用于数据量较大且增长量无法预估的应用,HBase 支持在线扩展,可以通过横向扩展来应对数据量的井喷式增长。
-
结构化和半结构化数据存储:适合存储结构化和半结构化数据,HBase 支持动态列和稀疏存储,列簇下的列可以动态扩展,且在列数据为空时不占用存储空间。
-
需要数据版本控制的应用:对于需要保留数据历史版本的应用,如快照记录。HBase 的多版本特性可以保留字段的旧版本数据,方便追踪和分析。
-
不支持复杂查询:HBase 不支持 SQL 风格的复杂查询,如 join 操作,因此适用于查询条件简单、不需要复杂关联查询的场景。
总的来说,HBase 适合于大数据环境下的写密集型应用,尤其是那些需要快速随机访问、对性能和可靠性要求高、数据量增长迅速且结构化或半结构化数据存储的场景。
HBASE的存储的逻辑结构
HBASE的存储的物理结构
我们来看看SPU/CSPU/ITEM/SKU的快照,如何商品快照呢?
商品快照是一种静态数据合集,它记录了用户下单时的商品信息,包括商品图片、标题、描述、服务等要素。这种快照通常用于解决交易纠纷,作为买卖双方发生交易的凭证,任何交易纠纷或者投诉都将以快照为准。
大多数电商平台做交易快照的初衷是为了解决交易纠纷,此外,交易快照还运用于法律诉讼场景,法院进行相关诉讼的裁定时,是认可交易快照作为证据的,但需要证明快照就是用户下单时的商品快照,无法被篡改。
因此,以上就是快照的作用。对于不同的商品,不同品类的商品。例如:手机品类,电冰箱品类,还是电视品类,有很多公共属性,例如:商品的基本信息等等,都是一样的,但是对于一些私有属性属性其实存在很大的差异,因此需要针对一些动态列实现。而Hbase则恰好很好的满足,因为不同的属性的字段可能不一样,并且HABSE还支持海量数据存储,所以,对于商品快照,我们则选用Hbase进行存储。
为什么商品快照需要用HBASE?
一句话:支持海量数据存储,由于HBASE的列式存储机制,为空的字段不占存储空间。
关于快照的rowkey设计
在使用Hbase商品快照,商品Id+snapshotType = hbase rowkey,key,就可以直接从海量数据分布式存储的hbase提取我们对应的订单快照数据,你可以指定你要提取哪一种快照数据,这个是一种设计,还有一种商品快照hbase表设计,商品Id = rowkey来进行设计,设计3个列族,第一个列族第一种snapshotType,第二个列族是第二种snapshotType,第三个列族以此类推这样子。
假设我们正在设计一个用于存储用户交易记录的HBase表。我们的目标是能够高效地查询特定用户在特定时间段内的交易记录。以下是一个详细的RowKey设计示例:
业务需求
-
需要存储用户的商品交易记录。
-
需要能够快速查询某个用户在特定时间段内的商品交易记录。
-
需要避免数据热点问题,确保数据均匀分布。
RowKey设计
为了满足上述需求,我们可以设计RowKey为以下格式:
RowKey = 商品ID(MD5) + "_" + 交易时间
详细说明
-
用户ID(MD5)
-
目的:确保RowKey的唯一性,并且通过MD5散列可以打乱用户ID的自然顺序,避免数据热点问题。有一些热门商品可能会被同时分到一个region下,会导致数据倾斜的问题,通过MD5打散后可以避免。
-
示例 :假设用户ID为
123456
,MD5散列后的值为827ccb0eea8a706c4c34a16891f84e7b
,我们可以取前8位作为散列值,即827ccb0e
。
-
-
交易时间
-
目的:利用HBase的排序特性,通过范围查询(Scan)快速获取某个用户在特定时间段内的交易记录。
-
格式 :使用时间戳(精确到毫秒),格式为
yyyyMMddHHmmssSSS
。 -
示例 :假设交易时间为
2024-01-18 12:34:56.789
,时间戳为20240118123456789
。
-
完整的RowKey示例
假设用户ID为123456
,交易时间为2024-01-18 12:34:56.789
,MD5散列后的值为827ccb0eea8a706c4c34a16891f84e7b
,取前8位作为散列值827ccb0e
。那么完整的
RowKey为:
plaintext复制
RowKey = 827ccb0e_20240118123456789
优势
-
唯一性:MD5散列值确保了RowKey的唯一性。
-
散列:MD5散列值打乱了用户ID的自然顺序,避免了数据热点问题。
-
排序:交易时间的格式确保了数据按时间顺序存储,便于通过范围查询(Scan)快速获取特定时间段内的交易记录。
-
查询效率:通过前缀查询(Prefix Scan)可以快速定位到特定用户的所有交易记录,再通过时间范围查询(Range Scan)可以进一步筛选出特定时间段内的记录。
快照使用MANGODB来进行存储
灵活的数据模型
-
文档结构:MongoDB 使用 BSON 格式的文档来存储数据,文档是键值对的集合,类似于 JSON 对象。这种灵活的数据模型允许单个集合中的文档不必具有相同的字段集,字段的数据类型也可以不同。这使得 MongoDB 非常适合存储半结构化数据,能够适应快速变化的业务需求。
-
嵌入式文档:MongoDB 支持嵌入式文档,可以将相关数据嵌入到单个文档中,而不是跨多个表进行规范化。这减少了 JOIN 操作的需要,提高了查询性能。
高性能
-
读写性能:MongoDB 优化了读写性能,特别是在处理大量数据时。它使用内存映射文件技术,将数据文件映射到内存中,提高了数据访问速度。此外,MongoDB 的索引机制也非常高效,支持多种索引类型,如单字段索引、复合索引、地理空间索引、全文索引等。
-
水平扩展:MongoDB 支持分片(Sharding),通过将数据分布在多个节点上,每个节点存储数据的一部分,MongoDB 能够水平扩展,处理更多的数据和更高的请求负载。
商品操作日志举例:更新ITEM的创建人的属性,MangoDB采后BSON的存储结果,是一种类JSON的存储结构。如下代码所示:
{
"_id": ObjectId("..."),
"user_id": ObjectId("..."),
"items": [
{
"product_id": ObjectId("..."),
"product_name": "Product A",
"operation": {"opt_type":"put","properties":"create_person",
"before_value":"张三","after_value":"李四"}
},
{
"product_id": ObjectId("..."),
"product_name": "Product B",
"operation": {"opt_type":"put","properties":"create_person",
"before_value":"王五","after_value":"赵六"}
}
]
}
通过MongoDB存商品操作日志信息的好处:其灵活的数据模型可轻松适应多样且多变的日志结构,高效写入性能得益于高并发写入支持与异步写入机制,能快速处理大量日志且不阻塞应用;强大查询功能借助丰富查询语言和索引优化,可按多种条件精准检索;数据可扩展性通过水平分片方便存储增长,副本集保障高可用性,即便面对海量日志数据,也能保证系统稳定、查询便捷且数据安全可靠,有效满足日志存储与管理需求。
总结下来就是:
-
灵活的数据模型:MongoDB 使用文档存储数据,每个文档可以是不同结构的,这使得存储半结构化数据更加容易。
-
高性能和可扩展性:MongoDB 支持水平扩展,可以方便地处理大量数据和高并发请求。
-
丰富的查询功能:MongoDB 支持丰富的查询语法和索引机制,使得数据的检索和分析更加高效。
-
高可用性:MongoDB 支持副本集,通过数据多副本和组件冗余提高了可靠性。
同时这样的设计也决定了MangoDB不适合以下的一些业务场景:
-
高度事务性系统:例如银行或会计这些金融系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。
-
传统的商业智能应用:针对特定问题的 BI 数据库会对产生高度优化的查询方式。对于此类应用,关系型可能是更合适的选择。
-
复杂的跨文档(表)级联查询:在查询条件复杂的情况下,相对于 RDBMS 并无明显优势,甚至没有优势或处于劣势。
有操作日志每次更新的可能更新的属性都会不一样,这样mangodb的BSON格式非常好的支持了灵活的存储需求,而且也支持水平数据横向扩展,因此,我们选取mangodb来作为商品操作日志的底层存储中间件。
MYSQL/HBASE/MANGODB优劣对比
特性 | HBase | MySQL | MongoDB |
---|---|---|---|
高性能和高可扩展性 | 非常适合 | 有限,需要优化 | 有限,需要分库分表 |
列式存储 | 支持 | 不支持 | 不支持 |
强一致性 | 支持 | 支持 | 最终一致性 |
大规模数据处理 | 支持 | 需要优化 | 需要分库分表 |
查询性能 | 简单查询高效 | 复杂查询高效 | 灵活查询高效 |
写入性能 | 高 | 有限 | 高 |
服务器成本 | 较低 | 较高 | 较高 |
总结
在海量数据场景下,异构存储架构是必然的,HBase由于其高性能、高可扩展性和列式存储特性,非常适合处理大规模的实时读写操作。MySQL在处理结构化数据和复杂查询方面(也不怎么擅长,耗CPU和内存)表现优异,但在扩展性和性能上有限。MongoDB适合存储动态和多变的数据模型,但在处理海量数据时性能和成本上不如HBase。
写在最后的话
1.数据正确性保证
-
SPU/CSPU 概念:SPU 是标准产品单元,CSPU 是子标准产品单元。
-
数据治理:引入人工纠错和系统去重机制,确保商品信息准确性和唯一性。
2. 海量数据存储
-
核心数据:SPU/CSPU/ITEM/SKU,使用 MySQL 存储,支持联机事务。
-
非核心数据:操作日志和快照,使用 HBase 和 MongoDB 存储,支持海量数据和高并发读写。
-
分库分表:将数据分散到多个库和表中,提升读写性能。
3. 非核心数据存储方案
-
快照存储:使用 HBase,支持海量数据存储。
-
操作日志存储:使用 MongoDB,支持高并发写入和灵活查询。
4. 优劣对比
特性 | HBase | MySQL | MongoDB |
---|---|---|---|
高性能和高可扩展性 | 非常适合 | 有限 | 有限 |
列式存储 | 支持 | 不支持 | 不支持 |
强一致性 | 支持 | 支持 | 最终一致性 |
大规模数据处理 | 支持 | 需要优化 | 需要分库分表 |
查询性能 | 简单查询高效 | 复杂查询高效 | 灵活查询高效 |
写入性能 | 高 | 有限 | 高 |
服务器成本 | 较低 | 较高 | 较高 |
5. 总结
-
异构存储架构:HBase 适合大规模实时读写,MySQL 适合结构化数据,MongoDB 适合动态数据。
-
业务场景匹配:选择合适的存储方案应根据具体业务需求和数据特性。
今天先就聊这里,本篇文章内容可能偏技术设计,业务知识不是非常多,因为本篇就是讨论的商品中心的质量诉求。我们在回顾在系统质量标准上,好的标准定义为以下四点:
1、数据正确性。商品作为主数据,数据的正确性的重要是不言而喻,因此,需要有纠错的机制和能力;
2、海量的商品数据。根据SPU/CSPU/SKU/ITEM的概念,商品数据会随着业务的发展会不断的成倍增长;
3、高并发读请求。商品数据在某些场景下是典型的读多写少的访问场景,需要支撑前台业务高并发的读请求;
4、模型和系统稳定性要求高。商品中心作为最底层的主数据服务,几乎前台业务所有的应用都会依赖它,因此,领域模型的稳定性和系统的稳定性就非常重要。如果商品模型经常变化,经常性修改势必会影响到前台业务的稳定性。
本篇文章,讲解了数据正确性和海量的数据数据存储的设计,下一篇文章,我们对于商品中心高并发场景读取和模型以及系统稳定性保障接着进行讨论,希望对大家有帮助。