MySQL的主从模式主要为了解决读数据时的访问压力。但主从模式是无法解决海量数据存储的问题。要存储海量数据,需要依靠分库分表模式。
一、分库分表的时机
- 前提:项目业务数据逐渐增多,或业务发展比较迅速。单表的数据量达到500w~1000W或20G以上。
- 优化已经解决不了性能问题(主从读写分离、查询索引...)
- IO瓶颈(磁盘IO、网络IO)、CPU瓶颈(聚合查询,连接数太多)。
二、拆分策略
有两种分库分表策略:垂直拆分、水平拆分。
2.1 垂直拆分
垂直拆分包含两个维度:垂直分库、垂直分表。
2.1.1 垂直分库——结构不同,数据不同(库级别)
以表为依据,根据业务将不同表拆分到不同库中。就是现在分布式/微服务架构中,业务独享库的概念。
特点:
- 按照业务对数据分级管理、维护、监控、扩展。
- 在高并发下,提高磁盘IO和数据量连接数。
2.1.2 垂直分表——结构不同,数据不同(表级别)
问题背景: 当一张表由于字段过多时,会导致表中每行数据的体积变大。单行数据过大带来的后患:一方面会导致磁盘IO次数增多,影响数据的读写效率;另一方面结果集响应时还会占用大量网络带宽,影响数据的传输效率;再从内存维度来看,单行数据越大,缓冲区中能放下的热点数据页越小,当读写操作无法在内存中定位到相应的数据页,从而又会产生大量的磁盘IO。
以字段为依据,根据字段属性将不同字段拆分到不同表中。
- 拆分规则
- 把不常用的字段单独放在一张表中。
- 把text, blob等大字段拆分出来放在附表中。
- 特点
- 冷热数据分离,多表互不影响。
当一个表字段过多时,应当考虑垂直分表方案,将多余的字段拆分到不同的表中存储。
2.2 水平拆分
水平拆分包含两个维度:水平分库、水平分表。
2.2.1 水平分库——结构相同,数据不同(库级别)
将一个库的数据拆分到多个库中。是对同一个节点做横向扩展,也就是高可用集群的概念。
- 数据路由规则
- 根据id节点取模
- 按照id范围路由。节点1(1 - 100万),节点2(100万 - 200万)...
- 按照日期以周、月、季、年...分表
- 一致性哈希:根据某个具备唯一特性的字段值计算哈希值,然后再通过哈希值做取模分片。
- 特点
- 解决海量数据存储和高并发问题。
2.2.2 水平分表——结构相同,数据不同(表级别)
将一个表的数据拆分到多个表中(可以在同一个库内)。
-
数据路由规则
- 根据id节点取模
- 按照id范围路由。节点1(1 - 100万),节点2(100万 - 200万)...
-
特点
- 优化单一表数据量过大而产生的性能问题。
- 避免IO争抢并减少锁表的几率。
当一个表的数据过多时,或者数据增长速率过快时,应当考虑通过水平分表方案,来降低单表的数据行数。
三、分库分表带来的问题
分库之后带来的问题:
- 分布式事务一致性问题。
- 跨节点关联查询。
- 跨节点分页、排序函数。
- 主键避重。
要解决上述问题,可以使用分库分表中间件。
- sharding-sphere
- mycat
四、分库分表总结
分库方案能够在最大程度上提升数据存储层的性能,但一般在考虑选用分库方案时,应该优先考虑使用主从复制、双主热备的方案,如果前面两种方案依旧无法提供系统所需的吞吐量,再考虑选择垂直分库方案,按照业务属性去划分库结构,最后才应该考虑选择水平分库方案(同时也要记得考虑数据的增长速率情况)。
为什么要遵循这个顺序呢?
- 因为架构不能过度设计,选用主从复制、双主热备能够满足需求时,就选这两种方案,因为一方面能避免很多问题产生,同时实现起来也比较简单。
- 先考虑垂直分库,再考虑水平分库,是因为水平分库可以建立在垂直分库基础上,进一步对存储层做扩展,因此灵活性会更高,拓展性会更强。