分库分表(Sharding)是应对海量数据存储和高并发访问的常用技术手段。当单机数据库的性能或存储达到瓶颈时,通过将数据分散到多个物理数据库或表中,从而提升系统的整体吞吐量。
为什么要分库分表?
- 单表性能瓶颈:随着数据量增大(如超过 500 万行或 2GB),索引 B+ 树层级加深,磁盘 IO 压力增大,查询性能显著下降。
- 单库并发瓶颈:单机数据库的连接数、IOPS、网络带宽等资源有限,难以支撑超高并发。
- 磁盘存储瓶颈:单机磁盘空间有限,无法容纳无限增长的数据。
拆分维度
1. 垂直拆分 (Vertical)
- 垂直分库:按业务模块拆分。例如将用户表、订单表、商品表分别存放在不同的数据库实例中。核心是专库专用。
- 垂直分表:按字段拆分。将一张表中不常用的、或者占用空间大的字段(如
text类型的描述信息)拆分到另一张扩展表中。核心是冷热分离。
2. 水平拆分 (Horizontal)
按行记录拆分。将同一个表的数据按某种规则分布到多个库或多个表中。
- 水平分库:将单表数据分散到不同的数据库实例,解决单库并发和存储瓶颈。
- 水平分表:将单表数据拆分为多张结构相同的表,解决单表性能瓶颈。
常见分片规则
| 规则 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| Hash 取模 | hash(key) % n | 数据分布均匀 | 扩容需数据迁移(可用一致性哈希优化) |
| 范围 (Range) | 按 ID 范围或时间段 | 扩容简单,无需迁移 | 易产生热点问题(如新数据全写在最后一个分片) |
| 映射表 (Lookup) | 独立存储映射关系 | 灵活,支持任意逻辑 | 增加额外网络开销,映射表本身易成瓶颈 |
带来的挑战与解决方案
- 分布式 ID:不能再依赖数据库自增 ID。需使用 Snowflake ID、UUID 或号段模式保证全局唯一。
- 跨节点 Join:无法直接在 SQL 中 Join。
- 解决:应用层组装、字段冗余、或者是使用 ER 表(将有关系的表分布在同一分片)。
- 跨节点聚合:
count,order by,group by等操作。- 解决:在各个分片并行执行后,由中间件或应用层进行结果合并 (Merge)。
- 分布式事务:跨库操作无法保证 ACID。
- 解决:使用两阶段提交 (2PC)、TCC、Saga 或本地消息表实现最终一致性。
常用中间件
- 客户端代理:ShardingSphere-JDBC (TDDL, Zebra)。
- 服务端代理:MyCat, ShardingSphere-Proxy, Atlas。