每日 3000万订单,如何分库分表?( 四 )


七、分库分表如何落地?
敲黑板......重点,重点,重点,重要的事情说三遍!!!
互联网业内有句经典名言"Talk is cheap.Show me your code",理论讲再多,无法付诸实际生产都是空谈 。
这里以某大厂社区电商订单业务的真实案例来分享如何落地分库分表 。
场景:社区电商下每日 3000 万下单场景
评估库和表的总数
一般评估的标准是:当前日订单峰值 M 支持最大的爆发增长速率 R 业务能支撑 Y 年发展 * 365 天/年,单表存储 1000 万数据按 。
预估数据总数:日订单 3000 万,一年按 365 天计数,最大支持日订单 10 倍的增长速度(即日订单量 1 亿),业务能支撑 10 年发展,因此,需要存储的总订单量 Total = 3000w 365 10 * 10 ≈ 10000 亿,万亿级 。
评估库和表的总数:每张表按 1000 万存储(库总数 表总数 = 10000 亿 / 1000 万),因此,库总数 表总数 = 10 万,组合方式有『1 个库 10 万张表、10 个库 1 万张表、100 个库 1000 张表 等』,整体来看,"100 个库 1000 张表"这种组合数据离散比较均匀,在计算机中,一般采用 2^n 来计数 。所以,100 个库 1000 张表可以比较接近 2^7 2^10 = 128 * 1024,所以最终 128 个库,每个库 1024 张表 。
分库分表字段的选择
在单库单表中,可以直接进行 join 查询和分页操作,分库分表后,数据会分到不同的数据库和表上,可能会导致跨库查询等问题,因此,分表字段的选择,决定了能否将原本需要进行分页的数据划分到同一张表上,从而避免跨库查询 。
So,如何选择分库分表字段?
有用过社区电商产品(橙心优选,美团优选,多多买菜,盒马邻里)的小伙伴应该知道,社区电商的模式是:当日购买,次日履约 。
为了保证履约的时效,用户在下单时,商城端都是把订单下到最近的仓库,因此,可以根据仓库编码来分库 。

每日 3000万订单,如何分库分表?

文章插图
 
在整个销售链路和履约链路中,有几个高发的订单查询场景,因此分表字段的选择必须满足这些场景:
用户视角:查询自己所有的订单,因此,可以通过 user_id 分表,把某用户所有的订单放到同一张表 。
团长视角:查询用户下给自己的所有订单,因此,可以通过 tuan_user_id 分表,把某团长的所有的订单放到同一张表 。
商家视角:查询用户下给自己的所有订单,因此,可以通过 merchant_id 分表,把某商家的所有的订单放到同一张表 。
客服视角:通过订单号查询某个订单,因此,通过 order_id 分表能够快速查询订单信息 。
上述 4 种场景都是订单表高发查询的场景,但是目前常用的分库分表中间件都只能支持一个分表字段,该如何解决上面 4 种查询问题呢?
通常的做法有:冗余数据和关系索引表 。
其实在计算中的世界很多时候都是时间和空间的一个权衡问题,是拿时间换空间,还是拿空间换时间?冗余数据和关系索引表就很好的体现了时间和空间的权衡关系 。
冗余数据:
相同的数据保存多份,每份数据使用不同的分表字段,从而满足各种查询需求 。如下图所示:通过 user_id、tuan_user_id、merchant_id、order_id 4 个字段来分表,因此需要冗余 4 份相同数据的 order 表 。
每日 3000万订单,如何分库分表?

文章插图
 
每日 3000万订单,如何分库分表?

文章插图
 
很显然,冗余数据是通过空间换时间的做法,优点是只要一次查询请求就能满足业务需求,缺点就是相同数据保存多份,浪费了空间,增加了成本 。
淘宝的订单表采用的是数据冗余,拆分买家库和卖家库两个库,一个订单,在买家和卖家库里都存储了一份 。
关系索引表:
它是指建立查询条件和基表分表键的索引关系 。如下图,订单表是基表,通过建立 user_id 和 order_id,tuan_user_id 和 order_id,merchant_id 和 order_id 的关系索引表来满足几种查询场景:
每日 3000万订单,如何分库分表?

文章插图
 
很显然,关系索引表是通过时间换空间的做法,优点是相对数据冗余法节省了空间和成本,缺点是多了一次索引表的查询,因此时间相对就增加了 。该方式额外增加的时间在高并发特别大的场景就能显现出来 。
因此,最后分库分表模型是根据仓库编码 warehouse_code 来分库,根据分表字段路由到 order 表,如下图:


推荐阅读