本文目录导读:
数据分片(Sharding)是指将一个大数据库中的数据水平切分到多个独立的数据库实例(节点)上,从而突破单机存储、性能或并发瓶颈。
做数据分片通常遵循以下步骤和原则:
第一步:确定分片键
这是最关键的一步,分片键决定了数据如何分布,直接影响查询性能和扩展性。
- 选择依据:选择查询频率最高、分布最均匀、业务中最核心的字段,面向用户的系统常用
user_id;面向订单的系统常用order_id或user_id。 - 原则:
- 均匀性:数据尽量均匀分布到各个分片,避免“热点”(某个分片数据量或访问量远大于其他分片)。
- 单一性:大多数业务查询都能带上这个分片键,减少跨分片查询。
第二步:选择分片算法
算法决定了如何根据分片键计算出数据应该去哪个库。
-
范围分片
- 原理:根据ID或时间范围划分,用户ID 1-1万的去分片1,1万-2万的去分片2;或者按月分片。
- 优点:扩展容易(增加分片只需调整范围);范围查询高效(可直接定位到连续分片)。
- 缺点:容易造成数据不均(如新用户全在最后一个分片)。
-
哈希分片
- 原理:对分片键计算哈希值,然后对分片数量取模(
hash(key) % N)。 - 优点:数据分布非常均匀,简单直接。
- 缺点:扩展困难,如果从N个分片扩展到N+1个,大部分数据需要重哈希(迁移),通常叫做“扩缩容陷阱”。
- 改进方案:一致性哈希,它引入虚拟节点,扩展时只影响少量相邻节点,大大减少了迁移数据量。
- 原理:对分片键计算哈希值,然后对分片数量取模(
-
地理位置分片
- 原理:根据用户或数据的地理位置分片,如按省、市、国家。
- 优点:天然符合地域性业务需求,利于就近访问和法规遵从。
- 缺点:容易导致热点(如北京数据量远大于西藏)。
-
时间/日期分片
- 原理:按时间维度(年、月、日)分片。
- 优点:适合日志、流水等时序数据;便于过期数据的归档和删除。
- 缺点:对实时查询和跨时间范围查询不友好,且易产生热数据集中于最新表。
第三步:选择分片架构
分片策略确定后,需要考虑如何管理分片,即分片的“路由”方式。
-
客户端分片(直连模式)
- 原理:应用程序直接连数据库,应用代码或轻量级中间件(如ShardingSphere-JDBC、TSharding)内置路由规则,计算后直接连接对应分片。
- 优点:性能高(无中间代理层)、部署简单。
- 缺点:分片逻辑写死在应用代码中,升级需要修改代码。
-
代理中间件分片(Proxy模式)
- 原理:应用程序连接一个代理服务器(如MyCAT、ShardingSphere-Proxy、Vitess、KingShard),代理解析SQL并路由到后端分片。
- 优点:应用无感知;支持多语言;便于管理、监控和账号权限控制。
- 缺点:引入网络开销;存在性能瓶颈和单点故障风险(可通过集群解决)。
-
分布式数据库原生分片
- 原理:使用原生支持分布式的数据库(如TiDB、CockroachDB、OceanBase、YugabyteDB)。
- 优点:自动分片、自动平衡、全ACID事务支持;开发者几乎不用关心分片细节。
- 缺点:学习和运维成本较高;硬件资源需求较大。
第四步:处理分片带来的挑战
分片解决了容量和性能问题,但引入了新的复杂性,需要配套方案:
-
分布式ID生成
- 分片后,自增ID无法全局唯一且需要分布式生成。
- 方案:雪花算法(Snowflake)、UUID(但太长,影响索引性能)、Redis自增、数据库号段模式。
-
跨分片查询 / 全局表
- 问题:
JOIN、ORDER BY、COUNT、GROUP BY等操作需要跨多个分片汇总。 - 方案:
- 全局表:将字典表、配置表等数据量小、变更少的表,在每个分片都复制一份(全量冗余),查询时在本地分片就能JOIN。
- 广播表:类似全局表,所有分片都存,插入/更新时同步到所有分片。
- 中间层聚合:在应用层或代理层,将查询下发到所有分片,然后合并结果并排序。
- 问题:
-
分布式事务
- 一个业务操作可能跨多个分片,传统数据库事务不再适用。
- 方案:
- XA(两阶段提交):强一致性,但性能较差。
- TCC(Try-Confirm-Cancel):业务侵入性强。
- Saga模式:通过补偿操作来保证最终一致性。
- Seata(阿里开源):AT模式,自动代理数据库SQL,对业务侵入低。
-
数据迁移与扩缩容
- 问题:分片数预先规划不足,需要扩容;或需要重新均衡数据。
- 方案:
- 停机迁移:简单粗暴,适用于可维护窗口。
- 双写迁移:同时写入旧库和新库,逐步追平并切换。
- 使用一致性哈希:减少迁移量。
- 使用原生分布式数据库:自动完成搬迁。
第五步:最佳实践建议
- 能不不分,尽量不分:分片带来的复杂度(跨分片查询、事务、运维)很高,在单表达到千万级或性能瓶颈之前,优先考虑读写分离、缓存、优化SQL、升级硬件。
- 选好分片键,减少跨片操作:尽量让80%以上的查询落在单一分片上。
- 冗余设计:高频的关联查询,优先用全局表或数据冗余来解决。
- 监控关键指标:监控每个分片的连接数、QPS(每秒查询率)、磁盘空间、慢查询,以便及时发现热点或倾斜。
- 保留二次分片能力:哈希法建议提前规划好分片总数(例如直接取2的N次方,用位运算代替取模),设计好哈希槽范围,方便未来静态扩展。
一个典型的分片设计流程
- 分析业务模型:找到主要查询和写入模式。
- 选择分片键:如上,常用
user_id。 - 选择算法:常用哈希(均匀但扩展麻烦)或日期(适合归档)。
- 设计架构:一般项目首选客户端分片(如ShardingSphere-JDBC)或原生分布式数据库(如TiDB)。
- 处理副作用:实现分布式ID(雪花算法)、处理跨库查询(中间层聚合)、解决跨库事务(AT模式)。
- 长期运维:监控分片健康度,做好扩缩容预案。
标签: 分片策略