MySQL 分库分表
基础
分库分表的定义
分库
- 垂直分库
按照业务模块进行切分,将不同模块的表切分到不同的数据库中
好处是既能独立变更,又能隔绝相互影响
分表
- 垂直分表
大表拆小表,基于列字段进行,一般是因为表设计不合理需要进行拆分 - 水平分表
针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE、HASH 取模等)
,切分到多张表里,但是这些表还在同一个数据库中,因此库级别的数据库操作仍存在 IO 瓶颈,不建议采用 - 水平分库分表
将单张表的数据切分到多个服务器上去,每个服务器具有相同的数据库和表,只是表中数据集合不同
水平分库分表能够有效缓解单机和单库的性能瓶颈和压力,突破 IO、连接数、硬件资源等的瓶颈
分区和分片的区别
分区和分片
- 分区(Partition)
数据库分区基本上都是数据对象级别的处理,比如表和索引的分区,每个子数据集上能够有不同的物理存储属性,但还是单个数据库范围内的操作 - 分片(Sharding)
从分区的思想而来,但是能够跨数据库,甚至跨越物理机器
在分表时,一般采用分片方案,即把数据存放在多个物理机器上- 分区(Partition)
分片策略
- 按照哈希切片
- mod-long: 用于分区列为数值的 hash 分区
分片列 id = 分区列值 % 分片数
- mod-long-by-hash: 用于分区列为字符串的 hash 分区
分片列 id = hash(分区列值) % 分片数
- 按照范围切片
- range: 建表是创建分区规则,根据分区规则就可以确定分区列的值在哪个分区上
一般分区列为时间或者数值,如下:如果分区列值为 1500000,则分片列 id 为 1date_range:
0: 1000000
1: 2000000
2: 3000000
3: 4000000
4: maxvalue
- range: 建表是创建分区规则,根据分区规则就可以确定分区列的值在哪个分区上
分库分表中间件
- 客户端分片
即在使用数据库的应用层直接操作分片逻辑,分片规则需要在同一个应用的多个节点间进行同步,每个应用层嵌入一个操作切片的逻辑实现(比如当当网的 Sharding JDBC) - 代理分片
在应用层和数据库层中间添加一个代理层,把分片的路由规则配置在代理层,代理层对外提供与 JDBC 兼容的接口给应用层,在业务实现之后,在代理层配置路由规则即可,Mycat 即基于此方案实现 - 支持事务的分布式数据库
支持分布式事务的框架,目前有 OceanBase、TiDB 框架,这些框架将可伸缩特定和分布式事务的实现包装到分布式数据库内部实现,对使用者透明
缺点是对事务的支持不如关系型数据库,适用于大数据日志系统、统计系统、查询系统、社交网站等
- 补充
支持事务的分布式数据库已经算是另外的数据库选型了,跟 MySQL 无关
分布式事务
- 分片意味数据分布在多台物理服务器上,引入了分布式事务问题
- 在引入分布式事务问题之后,对 MySQL 的操作与正常的单表操作不同
- 分片版本不维护自增和主键唯一,业务可自行维护唯一键,意味着不同分片的主键 ID 可能会重复
- 不支持跨分片事务写,可以跨分片事务读
如果确保事务操作的内容在同一个分片内,就不是分布式事务,和单机行为一致
一个事务涉及多个分片叫跨节点事务,单分片事务支持 - update 和 insert 必须带分片列
- 总结
操作同一个分片无影响,操作不同分片需要看中间件支持程度
如果使用中间件,即使是同一个分片,尽量不使用特殊的 SQL,有些中间件可能无法支持,比如 insert not exists
是否选择分库分表
- 考虑做分库分表考虑的几个要素
- 空间:单个物理实例无法支撑数据存储需求,单台物理机无法通过加盘的方式扩容
- 主库性能:受限于单个主库的 CPU/内存/磁盘IOPS 的影响,接近或者达到上限后需要拆分
- 容灾:减少单个主库宕机对于写入的影响
- 针对性的方案
- 空间
- 删除历史数据清空空间
- 修改存储模型降低对于 MySQL 磁盘的占用
- 改用空间压缩比更高的存储
- 主库性能
- 通过读写分离的方式,降低写库的读请求量,提升对于写入的支撑
- 优化数据写入模型,减少批量写入(削峰)
- 容灾
- 如果业务对于读高可用的要求较高,一般做读写分离,将重要请求路由至读库。读库数量一般多于写库,在代理层面做容灾的自动切换
- 在集群整体的角度上,分库分表实际上会扩大故障率,某些场景下,单个节点故障可能导致代理整个不可用,从而放大故障的影响范围