分库分表的文章网上非常多,但是大多内容比较零散,以讲解知识点为主,没有完整地说明一个大表的切分、新架构设计、上线的完整过程。
因此,我结合去年做的一个大型分库分表项目,来复盘一下完整的分库分表从架构设计 到 发布上线的实战总结。
1.前言
为什么需要做分库分表。这个相信大家多少都有所了解。
海量数据的存储和访问成为了MySQL数据库的瓶颈问题,日益增长的业务数据,无疑对MySQL数据库造成了相当大的负载,同时对于系统的稳定性和扩展性提出很高的要求。
而且单台服务器的资源(CPU、磁盘、内存等)总是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。
目前来说一般有两种方案。
一种是更换存储,不使用MySQL,比如可以使用HBase、polarDB、TiDB等分布式存储。
如果出于各种原因考虑,还是想继续使用MySQL,一般会采用第二种方式,那就是分库分表。
文章开头就说了,网上分库分表文章很多,对知识点讲解比较多,因此,本文将不再过多赘述分库分表方案的范式处理。
而是专注于梳理分库分表从架构设计 到 发布上线的完整过程,同时总结其中的注意事项和最佳实践。包括:
- 业务重构
- 技术架构设计
- 改造和上线
- 稳定性保障
- 项目管理
尤其是各个阶段的最佳实践,都是血与泪凝聚的经验教训。
2.第一阶段:业务重构(可选)
对于微服务划分比较合理的分库分表行为,一般只需要关注存储架构的变化,或者只需要在个别应用上进行业务改造即可,一般不需要着重考虑“业务重构” 这一阶段,因此,这一阶段属于“可选”。
本次项目的第一大难点,在于业务重构。
而本次拆分项目涉及到的两张大表A和B,单表将近八千万的数据,是从单体应用时代遗留下来的,从一开始就没有很好的领域驱动/MSA架构设计,逻辑发散非常严重,到现在已经涉及50+个在线服务和20+个离线业务的的直接读写。
因此,如何保证业务改造的彻底性、全面性是重中之重,不能出现有遗漏的情况。
另外,表A 和 表B 各自有二、三十个字段,两表的主键存在一一对应关系,因此,本次分库分表项目中,还需要将两个表进行重构融合,将多余/无用的字段剔除。
2.1 查询统计
在线业务通过分布式链路追踪系统进行查询,按照表名作为查询条件,然后按照服务维度进行聚合,找到所有相关服务,写一个文档记录相关团队和服务。
这里特别注意下,很多表不是只有在线应用在使用,很多离线算法和数据分析的业务也在使用,这里需要一并的梳理好,做好线下跨团队的沟通和调研工作,以免切换后影响正常的数据分析。
2.2 查询拆分与迁移
创建一个jar包,根据2.1的统计结果,与服务owner合作将服务中的相关查询都迁移到这个jar包中(本项目的jar包叫projected),此处为1.0.0-SNAPSHOT版本。
然后将原本服务内的xxxMapper.xxxMethod( ) 全部改成projectdb.xxxMethod( )进行调用。
这样做有两个好处:
- 方便做后续的查询拆分分析。
- 方便后续直接将jar包中的查询替换为改造后 中台服务 的rpc调用,业务方只需升级jar包版本,即可快速从sql调用改为rpc查询。
这一步花了几个月的实际,务必梳理各个服务做全面的迁移,不能遗漏,否则可能会导致拆分分析不全面,遗漏了相关字段。
查询的迁移主要由于本次拆分项目涉及到的服务太多,需要收拢到一个jar包,更方便后期的改造。如果实际分库分表项目中仅仅涉及一两个服务的,这一步是可以不做的。
2.3 联合查询的拆分分析
根据2.2收拢的jar包中的查询,结合实际情况将查询进行分类和判断,把一些历史遗留的问题,和已经废弃的字段做一些整理。
以下举一些思考点。
1)哪些查询是无法拆分的?例如分页(尽可能地改造,实在改不了只能以冗余列的形式)
2)哪些查询是可以业务上join拆分的?
3)哪些表/字段是可以融合的?
4)哪些字段需要冗余?
5)哪些字段可以直接废弃了?
6)根据业务具体场景和sql整体统计,识别关键的分表键。其余查询走搜索平台。
思考后得到一个查询改造总体思路和方案。
同时在本项目中需要将两张表融合为一张表,废弃冗余字段和无效字段。
2.4 新表设计
这一步基于2.3对于查询的拆分分析,得出旧表融合、冗余、废弃字段的结果,设计新表的字段。
产出新表设计结构后,必须发给各个相关业务方进行review,并保证所有业务方都通过该表的设计。有必要的话可以进行一次线下review。
如果新表的过程中,对部分字段进行了废弃,必须通知所有业务方进行确认。
对于新表的设计,除了字段的梳理,也需要根据具体查询,重新设计、优化索引。
2.5 第一次升级
新表设计完成后,先做一次jar包内sql查询的改造,将旧的字段全部更新为新表的字段。
此处为2.0.0-SNAPSHOT版本。</