背景
随着业务的增长,系统数据总量会不断的膨胀,增长量/率也可能在不断地提高,系统的库表结构调整就成为了需要提前思考和规划的问题。本篇文章,主要聊下在数据达到一定量后,数据表从单表至分表的调整方案。
分表原因
1.1 现状
为什么现在要分表?当前系统和很多系统一样,在服务初始并不能很好的对业务增长有较为准确的预判,便以单表的初始形态支撑系统的运行。
近几年随着业务的不断增长,我们也在不断的对当前系统 单表数据量,及平时的处理性能做持续的观测,眼看着数据量在千万的量级上快速增长、翻倍。乐观的是,索引较为完善,复杂查询场景较少,所以在日常的 SQL性能上还没有出现明显的问题。
随着公司的发展,今年又有新的业务需要接入我们的服务,可见,这会导致数据膨胀的进一步加快。单表的形态下,为支撑公司的不断发展,还能接入多少新的业务?还能支持业务量的快速增长?还能支撑系统平稳运行?
显然,此时系统对数据存储的容量 和 数据处理性能是有进一步要求的,于是我们便提前规划 数据表从单表至分表的调整问题。
1.2 预估
上面了解到,数据量在快速膨胀,我们在持续观测单表数据量的同时,也对未来3年的数据量做了预估,按照预估的结果,年底会到达亿数量级。
下面提供几种简单的预估方式:3倍冗余法;固定增量法;固定增率法。可以对未来一定时间内的数据量进行合理预估,有了这些数据做支撑,就可以比较直观的看出当前系统对单表拆分的必要程度。
① 固定增量,比较适用与业务更趋稳定的情况,按照每月的平均单量,就可以预估未来 N年 的量级。
② 固定增率,比较适用于业务平稳发展的情况,按照每月的平均增率,也可以预估未来 N年 的量级。
③ 3倍冗余,将平均日单量的三倍视作日单量,预计未来 N年 的量级。
要注意的是,以上的单量预估方法的估算结果,都无法完全真实的体现未来的事实走向。仅供实施者作为参考依据,进而结合实际情况采取更合适的方案。N的取值不宜过大,这样的数据才会尽可能的准确,避免时间及各种因素带来的干扰。
1.3 目的
“单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。”——阿里巴巴《Java 开发手册》
“MySQL 单表数据量大于 2000 万行,性能会明显下降。”——百度
就像很多关于单表数据存储量建议的声音一样,能看到很多数据值,事实上这些数据值的决定因素有很多,数据库的配置、机器的硬件、单条记录的大小...,所以上述数据值,只是预估,推荐值。
我们通过表的横向拆分,达到自己想要的目的即可。
1. 数据量上,合理的负载
2. 性能上,持续的 数据处理性能保障
3. 扩展上,更大的数据容量和业务访问量的支持
在分片方案中,首先需要挑选一款适合的分表中间件。
市场上有很多成熟的分表中间件,ShardingSphere-JDBC、TDDL、Cobar、MyCAT等。各有优缺点,网上资料较多,就不在这里赘述了。
不同的业务、系统基础条件的前提下,可以在了解各中间件的限制、优势后综合选择。以我们为例,鉴于ShardingSphere-JDBC足够轻量、支持多分片键、分片策略算法足够灵活的优势,又可以和内部系统保持一致的原因,最终选择这一中间件。
2.2 分片数量
既然要进行分片,那么要分成“几片”自然是需要考虑的问题,总不能拍脑袋的定。
分片数量可以从以下三个点出发考量。
第一:10 的倍数 or 2的N次方。
10倍数张表的优势,在于可以让人类非常直观直接的根据分片信息,锁定目标数据所在的具体物理表。
2N次方张表的优势,在于方便计算机的快速运算。甚至更灵活的缩容处理。
第二:合理的数量。
在决定分表的初期,实施者已经预估了 N年 后的单量,那么比较合适的分片数量,就可以按照单表 1000w OR 500w 的数据容量进行估算(分片数量 = N年后的总量 / 单表预期容量)。
第三:结合业务情况,未来的整体设计酌情考虑。
比如某个业务,我们没必要一直在 MySQL 中保留历史以来的所有数据,未来的大的走向是考虑冷热数据分离 + 热数据分表的 方式,那么分片数量只需要考虑支持到热数据的量级即可。
当然,结合业务自身,以及系统现实情况,分片的数量也可以考虑更多的因素。所以分出多少张表?这里还是需要结合各自的业务情况进行选择。
2.3 分片策略
分片策略是一个抽象的概念,通常包含分片键和分片算法。
以 ShardingSphere 为例,其提供了多种分片策略,我们选取了其中两种,ComplexShardingStrategy & InlineShardingStrategy 分别适用于两张不同的需要分片的表。(有兴趣的可以参阅 ShardingSphere官网)
2.3.1 分片键
分片键的选择需结合业务自身,常见的会有用户id 或 商户id等。
结合实践情况,业务中若有仅通过业务单号检索的情况,此时可能存在历史单号不带用户ID信息,新的单号带有用户ID信息,则可以业务单号 及 用户ID 多分片键的方式来处理。
2.3.2 分片算法
分片算法的定义同样和业务紧密相连,这里同样以 ShardingSphere为例,它支持简单的配置形式,利用Groovy的表达式进行计算,也支持灵活的定制,通过实现相应接口的具体实现类,来达到灵活计算的目的。
table_a | table_b | |
---|---|---|
分片数 | ||
2.3.3 注意点
单号着色
单号着色:指将分片键的部分信息作为单号的一部分,标记在单号上。
较为常见的需着色的单号有记录id,以及业务单号。
着色必要性:
① 便于产研人员根据相应 id 或 业务单号,直接锁定记录所在表
② 便于系统内部的性能优化
着色考量因素:
① 能够较容易的辨识 库号 和 表号
② 着色字符尽可能少
③ 着色字符的含义定义尽可能不受扩缩容影响(着色部分建议为 与分片键相关的计算因子,而不是直接的表号)
情况1:运营人员提供了某个问题业务单号,需要研发人员快速找到完整的库表数据,做进一步分析。
如果没有着色,可能就需要挨个表遍历查询条数据。
如果着色了,便可以很快的通过业务单号的部分信息,经过一些简单计算,锁定具体的物理表。
eg:业务单号 为 T123456789098765430064 ,在 mod 64 的分片算法中,可方便计算出它在 0表。
情况2:业务代码逻辑中,需要存在一些根据 主键id 对记录做相关操作的处理
此时,若id着色,即可快速通过着色信息,锁定具体的物理表。
eg:id 为 123456789098765430064 ,在 mod 128 的分片算法中,可方便计算出它在 64表。
数据偏斜
最大数据偏斜率 :(最大数据量 - 最小数据量) / 最小数据量。
一个良好的分库分表方案,数据应该比较均匀的分散在各个库表中。当实施分片时如果采用的分片策略不当,就会导致每个库表的增长步调不一致,长期以往,可能会造成单节点性能下降,单点风险,数据管理额外的成本问题,甚至可能再扩容时,增加处理复杂度。
单纯的单库分表,数据偏斜问题可以通过让分片因子足够散列,尽量解决这一问题。
如果是多库多表,库表的分片算法如果采取不当,就会导致严重的倾斜问题。可使用剔除公因式法、二次分片法、基因法等方法尽可能避免,有兴趣的可以进一步了解,这里不多赘述。
2.4 实施方案
单表拆分的实施,可以拆分成两块来说明,数据处理 & 功能处理。
数据处理:主要操作内容,是对数据(存量数据、增量数据)的一系列操作。这里大体分为以下三块。
目标数据 | 目的 | 选型 | 说明 | ||
---|---|---|---|---|---|
数据迁移 | |||||
功能处理:保障数据源平稳切换,虽不是必选,但也需要结合业务自身情况考虑不同程度的实现。
目的 | 说明 | |
---|---|---|
双数据源读写 | ||
2.4.1 数据双写 选型
代码处理(Dao代理) | 三方服务(DTS 迁移/同步) | 中间件(Canal) | ... | |
---|---|---|---|---|
实现方式 | Java 代理层实现 | 使用阿里云服务的数据同步 | 整合 Canal + MQ | |
同步双写 | 异步双写 | |||
优点 |
|
|
| |
缺点 |
|
|
2.4.2 数据迁移 选型
DTS 迁移 | 手工 迁移 | 不做迁移 | ... | |
---|---|---|---|---|
实现方式 | DBA 使用DTS服务执行迁移 | Job/代码手工 固定时间分批迁移 | ||
优点 |
|
| ||
缺点 |
|
|
|
此处列举了部分处理方式的选型可供参考,当然,如果系统业务接受,也可以选择不对历史数据做迁移。
2.4.3 数据核对
工具实现:DTS 服务,是可以支持到全量数据校验的。
自己实现:
同步核对 | ... | ||
---|---|---|---|
实现逻辑 | |||
上述图表仅为核对的方式,方案设计时需考虑 双写、迁移 两部分数据的核对 工作。
有核对,就需要提前考虑核对异常后的处理方式,无论是工具还是自己实现,一定是需要有报警、感知机制的。
至于感知后如何处理,还是建议人工介入代替数据自动抹平。
2.4.4 注意点
灰度处理
灰度切流 | |||
---|---|---|---|
| |||
|
停写处理
停写:停止服务的写入处理。
目的:保障写新时,新旧数据源数据一致。作用于数据源从单表,切换为分表短暂的前几分钟。
当在数据双写的选型中 选取了 中间件、服务等异步双写的处理方式时,不可避免会有数据同步延迟情况(单表写入了,分表还没被同步写入),预设此时切换数据源,该幂等的可能幂等不住了,存在的数据被上游查询不到了,无法正确的判定当前操作的合理性了,给到上游的信息是不准确的。
为了避免上面的问题,使用异步双写的时候,建议切换数据源前几分钟,进行停写处理,避免单表、分表数据不一致造成的业务问题。
2.5 实施方案概览
根据不同的业务类型、不同的实施方案选型、不同的中间件选型,分表最终成型的方案并不是固定的,可以形成很多种具体执行方案,在做方案设计时,选择适合自身业务,又简单的就好。这里仅列出几种大体方案概览,供参考。
配置说明 | ||
---|---|---|
2.5.1 方案X(双写选型 + 迁移选型)
2.5.2 方案一(Canal + DTS/手工)
阶段 | 读写处理 | 数据处理 | 目标 | 灰度 | 回滚 | Tips |
---|---|---|---|---|---|---|
1 | ||||||
|
2.5.3 方案二(DAO + DTS/手工)
阶段 | 读写处理 | 数据处理 | 目标 | 灰度 | 回滚 | Tips |
---|---|---|---|---|---|---|
写旧 & 读旧 | - | 确保 新代码 对业务无影响 | 市场 | 可 | 读写策略:写旧,读旧; | |
2 | 双写_旧 & 读旧 | - | 开始 双写_旧 & 读旧逻辑 | - | 读写策略:双写_旧,读旧; | |
双写_数据核对 同步/异步 | 开始 数据核对 ,确保 增量数据 写入分、单表一致 《技术设计》- 数据核对 - 双写数据核对部分 ,含对比异常措施 | 数据核对:每小时 | ||||
3 | 数据迁移 | 开始 并 完成 存量数据 迁移,确保 存量数据 迁移完毕 《技术设计》- 数据迁移,含实现逻辑、预计耗时 | - | 具体操作:DTS:DBA操作迁移,研发进行数据核对 手工:研发进行分批轮训迁移,对比操作 | ||
迁移_数据核对 同步/异步 | 开始 并 完成 存量数据 对比,确保 存量数据 无差异 《技术设计》- 数据核对 - 迁移数据核对部分,含对比异常措施 | 目标数据:[startID ~ maxID+N) 扩大范围防止漏数据 | ||||
4 | 双写_旧 & 双读_旧 | - | 确保 平稳读新(低流量时间段) 执行「双读_旧」策略,若不一致,发起告警 | 灰读 | 读写策略:双写_旧,双读_旧; | |
5 | 双写_新 & 双读_新 | 确保 平稳写新,写数据源切换 对业务无影响 (低流量时间段) | - | 读写策略:双写_新,双读_新; | ||
双写_数据核对 同步/异步 | 开始 数据核对,确保分表 增量数据 写入单表,新老表数据一致 《技术设计》- 数据核对 -双写数据核对部分 ,含对比异常措施 | 数据核对:同步(较短时间) 增:操作完成的返回,进行比对 改:操作完成的返回,进行比对 | ||||
6 | 写新 & 读新 | 处理/归档 | 历史数据:进行归档清理 旧逻辑代码:清理 | - | ||
注:
【写策略】:写旧、双写_旧、双写_新、写新;【读策略】:读旧、双读_旧、双读_新、读新; |
2.5.4 方案三(DTS + DTS)
阶段 | 读写处理 | 数据处理 | 目标 | 灰度 | 回滚 | Tips |
---|---|---|---|---|---|---|
1 | ||||||
|
2.5.5 方案四(先归档,再分表)
方案概述:先归档部分数据(20xx年xx月之前),再进行按期滚动归档(利用方案三/四/五,进行分表)
阶段 | 读写处理 | 数据处理 | 目标 | 灰度 | 回滚 | Tips |
---|---|---|---|---|---|---|
1 | ||||||
2.5.6 方案对比
选型 | 数据风险及应对策略 | 优点 | 缺点 | |
---|---|---|---|---|
方 案 一 | 双写:Canal 迁移:DTS/手工 | 风险
策略
以上措施,保障数据在读新、写新前,新旧两方数据抹平 |
|
|
方 案 二 | 双写:DAO 迁移:DTS/手工 |
|
| |
方 案 三 | 双写:DTS 迁移:DTS | 风险
策略
|
|
|
方 案 四 | 双写: 迁移:DTS/手工 |
|
| |
注: |
分表引入的问题
分页问题。有些业务需要支持分页检索。
报表业务
特殊查询实现 count;order by;group by;join
...
首先部分中间件是支持分页检索的,例如ShardingSphere。
其次也可以通过限定检索条件或范围,禁止跳页,ES的引入等方式来优化分页检索的性能。
很多公司都有报表等相关业务,这里需要数据中台或者数据仓库团队做友好的支撑。
首先,尽量避免 业务中的复杂查询;
其次,如果实在需要,场景上又对实时性要求不高的,可以走ES或者离线库去查询
结语
以上便是关于单表拆分的一部分内容介绍。篇幅有限,不足以铺开每个点面,希望能提供一些思路、灵感亦或论点给到读者;随想随笔,感谢浏览,欢迎一起交流沟通,共同进步。
关于领创集团