logo头像
Snippet 博客主题

分库分表技术储备

本文于 865 天之前发表,文中内容可能已经过时。

背景

数据库,很容易成为应用系统的瓶颈。单机数据库的资源与处理能力有限,在高并发的分布式服务中,可采取分库分表突破单机局限。其实,在除了少数的公司流量大,大部分用不上分库分表,主从读写分离这样的架构已经可以满足业务的需求了,可是偏偏面试的时候,mains面试官喜欢问些这些逼格的玩意,我也特意琢磨了一下,并且记录下来技术方案,期待在以后的工作中,尽快落地。

是否需要分库分表?

当我们的表记录不超过百万级,不需要分库、分表。如果此时DB性能有问题,可以通过优化SQL,优化索引,增加DB服务器CPU/内存,读写分离。

我们做数据库切分设计的时候,优先垂直切分,读写分离,如果还不行的话,不得不才水平分库分表,切记过度设计。

分库分表的方案

  • 垂直拆分
    垂直分库:
    如今微服务盛行,根据业务来划分系统,我们也跟着业务来划分数据库,比如订单库,用户库,这样解决了单机DB服务器的局限。缺点是做查询,聚合数据的时候,需要通过系统之间的接口,聚拢数据再做处理,系统复杂度高。
    垂直分表:
    适合在做表设计的时候,表字段比较多,将一些不常用的,数据较大长度过长的字段拆到扩展表去。缺点就是不适合在运行中系统做拆分。

  • 水平拆分
    水平分表:
    当表数据超过百万了,那么我们可以采取根据ID的hash到不同分表,但是还是在同个库里面做拆分。缺点就是还是没有摆脱单机的资源局限,所以一般不推荐。

  • 水平分库分表:
    上面的方案,还是支撑不了我们的业务数据,我们才会采用,将单表的数据量切分到不同的服务器上,每台服务器都有相应的库与表,只是数据集合不同。

水平分库分表的切分策略

  • 根据ID或者时间范围切分,比如1-100000 A1库,100001-200000 A2库…
  • 根据ID/订单号的HASH,比如有4台数据库,%4=1分给A1,%4=2分给A2,%4=3分给A3,%4=0 分给4。
  • 根据时间切分,比如2018年的在A1库,2019年的在A2库。这样导致db负载分布不均匀,老数据比较访问量少,这样浪费了系统资源。

水平分库分表的成熟产品

分2种,一个代理模式的有corbar,Mycat,Sharding-jdbc
另一种非代理的TDDL 阿里的需要配合Diamond,Mysql官方的Fabric

分库分表面临的问题

  • 分布式事务
    分布式事务,有现成的产品支持,比如Jotm、Automikos 等来实现,两者均支持 spring 事务整合,但是在高性能高并发系统,不推荐使用。

  • 跨库JOIN,orderby,group by
    解决方案:
    数据库层面,冗余字段,加个查询常用的全量表。
    应用层面,通过系统间组合数据,再做相应的数据处理。

  • 扩容带来的数据迁移

    夜间停机
    影响业务运行,不过一般夜间执行,夜间在线的活跃用户超过1000的用户仅有几家吧。
    双写法
    在前面的一篇文章提到过如何平滑数据迁移不影响服务的可用性

总结下来是三步:
准备新库,加入双写代码
迁移历史数据
校验新旧库数据一致性,平滑切到新库。

如何校验数据一致性?
校验新旧库的数据量是否一样
取新旧库的1-50之间数据然后MD后比对,再取51-100的数据比对,哪里不一致做个标记,再次同步。

参考资源

MySQL 分库分表及其平滑扩容方案
58沈剑:数据库秒级平滑扩容架构方案