分库分表实战


背景

商品评价这一块,评价信息单表存储,主要包括一些基本评价信息,商品id,订单id,买家id和卖家id,当时DB量级已经达到上亿,会出现一些慢SQL

业务场景分析

根据分库分表,可以得出一个期待的结果

  • 独立的评价库,这个库只保存评价相关信息
  • 采用水平分表,将原表的数据,拆分到1024(数量可以自定义)张分表中(如果拆分合理,则单表数据在30W-40W)

需要考虑的问题就是如何水平拆分

  • 商品详情的评价查询:根据商品ID进行查询
  • 卖家管理端查询所有评价:根据卖家ID进行查询
  • 买家评价管理:根据买家ID进行查询
  • 订单列表的评价信息:根据订单ID进行查询

粗略可以设定两种方案:

  1. 上面四种场景,显然是根据商品ID查询的量最大,如果根据商品ID进行分表,那么商品的评价都落在一个分表中,此时查询不会出现跨表,但是另外三种查询会导致跨表;同样换成卖家ID也会导致其他三个查询跨表

2.建立一张附表,只保存如下信息

rateId:评价ID
itemId:商品ID
sellerId:卖家ID
buyerId:买家ID
orderId:订单ID

根据rateId进行分库分表,这样每次查询,先通过附表,查询对应的评价ID,然后拿rateId到分表去获取评价信息

设计与实现

方案设计

前面给了两种方式,一种根据商品ID进行分表,一个是建立一个附表然后根据rateId进行分表,首先是分表规则,我嗯选择最简单的额方式,根据id%12进行取模

分析两种方式的优劣

  1. itemID分表
    • 优点
      • 实现简单,无需附表,不用考虑数据不一致的问题
      • 可以支持详情评价列表复杂的排序逻辑
      • 性能更优能,少了一张附表
    • 缺点
      • 非itemId查询会跨表
      • hash不均匀,导致单表数量比较多 2.rateId分表方案
    • 优点
      • 支持前面的几种查询,不过要先查询出rateId
      • 但表数据量分布均匀
    • 缺点
      • 复杂查询条件支持不友好,排序、过滤需要依赖一些评价信息的场景
      • 插入和更新的时候,都需要同步更新附表,复杂度更高(需要满足表的事物)
      • 每次查询都需要通过附表查询rateId,效率比较低 方案选择 通过实际分析,选择了根据itemId进行分表查询,理由如下:
        • 业务逻辑简单,后续维护方便
        • 线上的sql,95%根据itemId进行查询
        • 上层有一层根据solr的搜索,因此根据buyerId,sellerId等可以走搜索,不需要进行db的多表联合查询
        • 附表虽然结构简单,但是单表的最终数量依然会很大 所以:
db	:rate000 ~ Rate003
table	:ItemRate0000 ~ ItemRate1023
其中映射规整:
tableIndex 	= itemId % 1024    	---> 分表名 如 ItemRate0122
dbndex 		= itemId % 1024 /256    ---> 分表名 如 ItemRate001

步骤计划

两种方式

  • 方案一:采用双写
    • 创建DB
    • 服务的sql改造,主要是所有的sql,都要有一个新的分库分表的方式
    • 线上开始双写(新增一条评价,即写入旧表,也写入新表)
    • 全量将旧表数据导入新表
    • 线上读流量切换到新表,验证是否有问题
    • 所有关注旧表binlog业务,全部迁移到关注新标的binlog(需要dba支持,新标有1024张,不可能关注全部topic,需要dba提供binlog整合)
    • 关闭双写,所有写操作直接切换到新表
  • 方案二:基于db的binlog实现的异步同步方式
    • 创建DB
    • 服务的sql改造,主要是所有的sql,都要有一个新的分库分表的方式
    • 开启增量,将某个时刻开始之后所有更新的数据,通过异步方式增量同步到新表
    • 开始全量,将之前的数据全部导入到新标
    • 线上读切换新表,验证服务是否有问题
    • 所有关注旧表binlog业务,全部迁移到关注新表binlog
    • 线上切换写操作到新表
    • 增量完毕后,关闭增量

两种方案本质上没有太大区别,第一种双写需要自己保障双写成功;后面增量的方式,一般DBA会有比较好的方案实现增量同步(一般选择第一种方案)

注意事项

  • 全量迁移,如果dba没有提供相关工具,只能自己写,可以找一台机器,部署服务利用jdbcTemplate扫表,实现全量数据插入
  • 双写需要注意双写失败
  • 数据最后需要对账比较

小结

  1. 分库分表
    • 一般而言,当量级达到百万时,就需要考虑分库分表了,不同业务有自己的独立的库
    • 根据表中某些列进行分表,将大表数据拆分到分表中
    • 大表拆分为小表
  2. 实现步骤
    • 创建DB
    • 服务的sql改造,主要是所有的sql,都要有一个新的分库分表的方式
    • 线上开始双写(新增一条评价,即写入旧表,也写入新表)
    • 全量将旧表数据导入新表
    • 线上读流量切换到新表,验证是否有问题
    • 关闭双写,写直接切换到新表



Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • 2379. Minimum Recolors to Get K Consecutive Black Blocks
  • 2471. Minimum Number of Operations to Sort a Binary Tree by Level
  • 1387. Sort Integers by The Power Value
  • 2090. K Radius Subarray Averages
  • 2545. Sort the Students by Their Kth Score