MySQL分库分表计算模型方法论
拆分需求:
1、单机存储容量瓶颈无法扩展,另外大表DDL时间长、风险高
2、高QPS瓶颈导致的数据库资源产生瓶颈(cpu、mem、io)
拆分模式:
1、垂直(纵向)切分:把单一的表拆分成多个表,并分散到不同的数据库实例上
2、水平(横向)切分:根据表中数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库实例上。
以下重点说水平切分下的方法论:
水平切分的优点如下:
-
单库单表的数据保持在一定数据量级,有助于性能的提高。
-
切分表结构相同,应用层改造较少,只需要提前设计或者增加路由规则即可。
-
提高业务系统的稳定性和吞吐能力。
水平切分的缺点如下:
-
依据切分规则切分后,数据相对分散,但跨库Join性能较差,跨节点join,中间层计算损耗大
-
分布式事务解决方案成本高或者妥协解决。
-
数据库扩容,运维成本高。
分库分表拆分方法:
1、按库分,如mycat
2、按库内分表,如kingshard
3、既分库又分表,如DRDS,Sharding Shpere......
分库分表常用规则:
1、range切分 优点:单表大小可控,天然水平扩展 缺点:产生热点 ,写入数据倾斜
2、hash切分,一般采用mod来切分 优点:数据均匀,无热点 缺点:重新计算hash,扩容缩容麻烦
分库分表基本概念:
物理分库:一个MySQL实例下包含多个库
物理分表:MySQL实例下每个库下多个表
逻辑库:中间件实例下的数据库,对应用透明,后边由一批物理分库组成
逻辑表:就是业务表,比如订单表、优惠券表,后边由一批物理分表组成
拆分多少分表合适,万能公式?
总分表数(
N
) = 总物理实例数(
X
)* 每个实例下的分库数(
Y
)* 每个分库下的分表数(
Z
)
-
实例数考虑QPS的吞吐能力
-
分库数考虑扩容拆分
-
分表数考虑数据分布,性能提升
业界一般:常规循序渐进扩容:短期(X小,Y大) 中期(X大,Y小) 长期 (X和Y适中 资源使用均衡),一般提前规划好总分表数,避免扩容对业务的影响,16<=总分表数(
N
)<=4096
拆分多少实例合适,万能公式?
物理QPS = ∑ 物理实例
i
的
QPS
,
i
∊ (1,
X
)
业界一般:总实例数是2的幂,需要看中间层的产品支持情况
分片表计算公式参考:
分片键选择,同一分片键走本地事务,跨分片-分布式事务需要业务酌情考虑,考虑合适的解决方案
分片表多少?一般根据总数据量大小,依据分片表数据类型可计算每行size,进而可以推倒出该表存储容量大小,一般建议,单个物理分表的容量不超过500万行数据。
物理分表数 = 向上取整(估算的总数据量 / (实例数 * 物理分库) / 建议的分表容量),如1亿行,后端实例数为4,物理分库为8,单个分表建议容量500万,计算如下:
物理分库上的物理分表数 = CEILING(100,000,000 / ( 4 * 8 ) / 5,000,000) = CEILING(0.625) = 1
结果为1,那么只分库即可,即每个物理分库上1个物理分表。
通常建议:当计算出的物理分表数等于1时,分库即可,无需再进一步分表,即每个物理分库上一个物理分表;若计算结果大于1,则建议既分库又分表,即每个物理分库上再建立多个物理分表
分库分表参考方案:
总实例数 |
实例下物理分库 |
每分库的物理分表 |
总分表数 |
---|---|---|---|
32 | 2 | 16 | 1024 |
8 | 4 | 32 | 1024 |
8 | 8 | 16 | 1024 |
32 | 32 | 1 | 1024 |
64 | 2 | 16 | 2048 |
128 | 2 | 16 | 4096 |
备注:运维角度考虑,分库一般也是2或者2个倍数,相对分表对半拆扩容,分库对半拆更加容易些,也决定扩容的次数,考虑扩容缩容风险高,运维成本高,最好一开始就确定好分库数和总分表数,当然有牛逼的中间件可以突破2的拆分,这需要重新数据分布和数据计算,这个另说
线性扩展能力与实际核心SQL和高频SQL有关:
分片键:与业务场景有关,需找到业务逻辑实体,核心SQL围绕该字段进行
带分片键影响:一般指SQL落在一个实例上,如等值查询、范围查询、in查询
不带分片键影响:一般指SQL落在多个后端实例上
中间件 |
SQL写法 |
翻倍扩容 |
SQL响应耗时 |
线性扩展 |
---|---|---|---|---|
QPS能力>后端MySQL能力 | SQL带分片键 | 弹性扩容MySQL实例翻倍 | 维持正常/提升 | QPS吞吐会翻倍 |
QPS能力>后端MySQL能力 | SQL不带分片键 | 弹性扩容MySQL实例翻倍 | 维持正常 | 无法提升 |
数据容量计算预估模型:
单表容量 |
单表大小 |
总分片数 |
总实例数 |
总分库数/每库分表数 |
总分表数 |
估算总数据量大小 |
总存储空间 |
扩容拆分 |
---|---|---|---|---|---|---|---|---|
100w | 10G | 128 | 32 | 8/16 | 4096 | 40亿+ | 40T+ | 按需拆分 |
128 | 64 | 4/16 | 4096 | 40亿+ | 按需拆分 | |||
64 | 16 | 8/16 | 2048 | 20亿+ | 20T+ | 按需拆分 | ||
64 | 64 | 1/32 | 2048 | 20亿+ | 一次到位,无需扩容 | |||
32 | 8 | 8/16 | 1024 | 10亿+ | 10T+ | 按需拆分 | ||
32 | 32 | 1/32 | 1024 | 10亿+ | 一次到位,无需扩容 |
以上是预估数据,SQL质量不同,会影响QPS吞吐,还是需要实际线上性能压测为准。
建议水平拆分,充分考虑未来容量增长,比如未来10年的容量规划,优先考虑按库分,数据容量过大,再考虑分库分表,架构简单就是美。
其他-分库分表带来的常见问题及解决方案参考:
分库分表避免/禁止跨库join解决方案:
1、创建全局数据字典表,数据很少变化,每个数据库创建一张,本地事务join
2、反范式设计,设计冗余字段,空间换时间,适合于依赖字段较少的场景
3、创建父子关联表,比如主订单表-子订单表,带分片键
备注:互联网业务一般都是简单查询,尽可能减少join操作,超过2个以上join建议从设计上考虑整改
分库分表多维度查询解决方案:
1、创建异步索引表,二次查找查询
2、创建以另一维度+分片键的全量数据copy,通过空间换时间,
3、通过实时数据同步工具,推送到另一数据库集群/大数据存储系统,满足运营/统计/客服大数据组的在线和离线需求,达到在线查询和离线查询的隔离
分布式事务解决方案,业界目前有如下三种主流解决方案 :
两阶段提交协议
优点:最大限度保证事务的原子性,最大限度保证数据一致性
缺点:由于事务管理者需要协调事务参与者,无法水平伸缩,属于阻塞协议,性能较差,极端情况下,不能快速反应请求方需求,对高并发性能要求高的忽略,适合于确定性的短事务的业务
最大努力TCC模式
适用场景:高性能分布式事务解决方案,适用于对性能有很高要求的场景。
1、Try阶段-检测预留资源,预执行
2、Confirm阶段-正式完成所有业务逻辑的执行
3、Cancel阶段-回滚Confirm阶段执行的所有操作,预留资源释放
备注:本地事务一个接口变成分布式事务的三个服务接口
最终补偿SAGA协议
适用场景:冲正补偿服务,适合于业务流程长、业务流程多,追求高性能、高吞吐,保证最终一致性
1、每个参与者本地提交事务,每个参与者需要提供正向操作和逆向回滚操作
2、分布式事务执行过程中,依次执行参与者的正向操作,正向操作成功,则分布式事务提交
3、如果正向操作中任何一个发生失败,依次执行参与者的回滚操作,回滚已提交的参与者,回归到原始状态
基于消息实现的分布式事务
适用场景:此场景除单机事务优先考虑使用的,适用于流程序列化业务,有事务发起方和事务跟随方的场景
1、创建本地事务,提交本地事务,主动推送消息/提交事务日志表
2、实时读取事务日志表,发送到MQ中
3、事务消费方从MQ取出,及时消费
微信分享/微信扫码阅读