分库分表
分库分表
分库
分库:将数据分散到多个数据库实例中,每个实例管理一部分数据。
分库的分类:
- 垂直分库:把单一数据库按照业务模块划分,不同的业务使用不同的数据库
- 水平分库:把同一张表按照某个字段的值划分到不同的数据库中
分表
分表:对单表进行拆分
分表的分类:
- 垂直分表:把单一表按照列进行拆分,不同的列放在不同的表中
- 水平分表:把单一表按照某个字段的值进行拆分
什么情况需要分库分表
- 单表数据量大,数据库读写速度慢
- 数据库中数据量大,备份和恢复时间长
- 并发访问量大,数据库连接数超过限制(应优先考虑其他性能优化方法,而非分库分表)
常见的分片算法
范围分片(Range Sharding)
按区间切。
比如按时间:
1 | 2024-01-01 ~ 2024-03-31 -> shard0 |
或者按 ID 范围:
1 | 0~1000万 -> shard0 |
优点:
- 范围查询极友好
- 按时间归档方便
- 易于冷热分离
缺点:
- 容易热点(最新数据打满一台机器)
- 数据分布不均
适用于日志、订单历史、时间序列数据。
哈希分片(Hash Sharding)
最经典。
1 | hash(key) % N |
例如:
1 | user_id % 8 |
优点:
- 数据均匀
- 实现简单
- 避免热点
缺点:
- 扩容灾难
从 %4 扩到 %8,几乎全部数据都要迁移。
一致性哈希(Consistent Hashing)
为了解决扩容问题。
最早被用在分布式缓存系统,比如 Memcached。
核心思想:
- 把机器映射到一个哈希环上
- key 也映射到环上
- 顺时针找到第一台机器
优点:
- 新增/删除节点只影响部分数据
- 迁移成本低
缺点:
- 实现复杂
- 数据均衡需要“虚拟节点”优化
映射表分片
使用一个独立的映射表来记录分片键和分片位置的对应关系。
优点:
- 灵活性高
- 可以支持复杂的分片规则
- 扩容相对简单
缺点:
- 需要维护映射表
- 查询时需要额外的映射表查询,增加了查询复杂度
地理位置分片(Geo Sharding)
按地区分。
1 | 华东 -> shard0 |
适合:
- 跨国业务
- 数据合规要求
业务维度分片(Vertical-like Horizontal Hybrid)
比如:
- 用户数据按 user_id 分片
- 订单数据按 user_id 分片
- 日志按时间分片
这其实是“业务主键驱动”的分片。
很多中间件支持,例如 Apache ShardingSphere。
分片键如何选择
分片键应具备以下特点:
- 具有共性,即大多数查询都包含这个字段,尽量减少单次查询所涉及的分片数量
- 具有离散型,即分布均匀,避免数据倾斜和热点问题
- 具有稳定性,即分片键的值不应频繁变更,否则会导致数据迁移和性能问题
- 具有可扩展性,即分片键的取值范围应足够大,以支持未来数据增长
分库分表问题
分布式事务问题
单库时,InnoDB 自带 ACID。
跨库之后:
- 本地事务失效
- 需要分布式事务(2PC、TCC、Saga)
两阶段提交(2PC)的核心问题是:
性能差 + 阻塞 + 协调成本高。
很多公司最后都会选择:
- 最终一致性
- 消息队列补偿
- 业务层幂等
强一致往往代价太高。
跨库Join失效
单库可以:
1 | select * from order o join user u on ... |
分库后:
- 不知道 user 在哪个库
- 无法直接 join
结果只能:
- 先查一张表
- 再查另一张
- 应用层聚合
数据库开始“退化”为 KV 存储。
全局主键问题
自增 ID 不再安全:
- 多个库会冲突
- 无法保证全局唯一
解决方案:
- 雪花算法(Snowflake,最早由 Twitter 提出)
- UUID
- 号段模式
但这些都会带来:
- 索引离散
- 页分裂增多
- 存储膨胀
扩容与数据迁移
如果你使用:
1 | user_id % 4 |
后来变成8台机器,几乎所有数据都要重新计算并迁移。
这叫做“重分片风暴”。
一致性哈希可以缓解,但复杂度会上升。
统计查询困难
例如:
1 | select count(*) from order; |
现在要:
- 所有分片分别统计
- 再聚合
如果是:
1 | order by create_time limit 10; |
你需要:
- 每个分片取前 10
- 再做二次排序
复杂度指数上升。
总结
- 分库就是将数据库中的数据分散到不同的数据库上。分表就是对单表的数据进行拆分,可以是垂直拆分,也可以是水平拆分。
- 引入分库分表之后,需要系统解决事务、分布式id、无法join操作问题。
- 现在很多公司都是用的类似于TiDB这种分布式关系型数据库,不需要我们手动进行分库分表(数据库层面已经帮我们做了),也不需要解决手动分库分表引入的各种问题,直接一步到位,内置很多实用的功能(如无感扩容和缩容、冷热存储分离)!如果公司条件允许的话,个人也是比较推荐这种方式!
- 如果必须要手动分库分表的话,
ShardingSphere是首选!ShardingSphere的功能完善,除了支持读写分离和分库分表,还提供分布式事务、数据库治理等功能。另外,ShardingSphere的生态体系完善,社区活跃,文档完善,更新和发布比较频繁。
