今天来系统梳理一下分布式系统中另一个核心命题:分片(Sharding)。
在分布式系统里,复制解决的是可用性和读扩展的问题,而当数据规模或写入吞吐量已经无法由单机承载时,分片几乎是不可回避的选择。
一、为什么需要分片?
我们进行分片最主要的原因是 可伸缩性(Scalability)。
通过分片:
- 可以把数据分散到多台机器上
- 把读写负载拆分并行处理
- 通过 水平扩展(Scale Out) 的方式支撑更大的数据量和更高的吞吐
但分片并不是免费的午餐,它也带来了一系列新的复杂性。
分片带来的问题
- 需要分区键:必须通过某个 key 才能快速定位数据在哪个分片
- 分片方案难以修改:一旦上线,调整成本通常非常高
- 对二级索引和关系型数据不友好
- 跨分片操作复杂,甚至需要分布式事务
因此,分片更适合 键值型或以主键访问为主的场景。
二、广义分片:面向多租户的分片
在广义上,分片并不只用于“技术层面的水平扩展”,它在 多租户系统(Multi-Tenant) 中同样非常重要。
典型场景包括:
在这些系统中,租户本身就是天然的分片单元。
面向多租户分片的常见收益
- 资源隔离:一个租户的高负载不会拖垮其他租户
- 权限隔离:降低越权访问的风险
- 基于单元(Cell-based)的架构:提升故障隔离能力
- 按租户备份与恢复:运维与应急处理更简单
- 法律合规性(如 GDPR):支持数据导出、删除
- 数据驻留:支持数据存放在特定地域
但这种方式也有前提:
- 每个租户的数据规模不能大到单机无法承载
- 否则就会回到“单租户内部再分片”的问题
三、狭义分片:键值数据的分片方式
更常见的讨论是 狭义上的分片 —— 对键值数据进行分片。
1️⃣ 按键的范围进行分片(Range Sharding)
直接在原始 key 上划定区间:
优点
缺点
- 热点问题
- 再平衡成本高
- 分片数量变化时需要拆分或合并分片
- 会引发大量数据迁移
2️⃣ 按键的哈希进行分片(Hash Sharding)
为了解决范围分片的热点问题,可以先对 key 做哈希,再基于哈希值分片。
哈希分片可以让键分布更加均匀,但实现方式并不只有一种。
常见的几种方案
(1)哈希取模节点数
CodeBlock Loading...
- 实现简单
- 但节点数变化会导致几乎所有数据重新分布
- 再平衡代价极高,实践中不推荐
(2)固定数量的分片
- 预先创建大量分片(如 1000 个)
hash(key) % shard_count- 再将分片映射到节点
优点
- 节点增减时只移动分片,不重新 hash key
- 再平衡成本可控
缺点
- 分片数一旦定死,很难调整
- 分片过大或过小都会带来问题
(3)按哈希范围分片
- 每个分片负责一个连续的哈希值区间
- 分片可以动态拆分或合并
- 数据量变化时适应性更强
(4)一致性哈希
- 将哈希空间抽象成一个环
- key 映射到顺时针遇到的第一个节点
- 节点变化时,只影响少量 key
一致性哈希在缓存系统、KV 存储中非常常见,本质上是一种“隐式分片”。
四、热点与倾斜:哈希也解决不了一切
即使使用哈希分片,也无法避免 业务层面的热点问题。
典型场景
这种情况下:
- 单个 key 的访问量极高
- 这个 key 被称为 热键
常见应对方式
- 应用层打散
- 在 key 前后加随机数
- 将写入分散到多个逻辑 key
- 热键独立分片
这些方案往往是 工程妥协,需要额外的读合并和运维成本。
五、再平衡:自动还是手动?
分片系统绕不开 再平衡(Rebalance)。
- 再平衡是昂贵操作
- 涉及大量数据迁移
- 会对系统性能产生显著影响
自动 vs 手动
在很多生产系统中:
再平衡过程中引入人为控制,反而是一种优势
六、请求路由:如何找到正确的分片?
从“请求一条数据”到“找到对应分片所在的节点”,中间还需要解决 请求路由 的问题。
常见三种方案
- 客户端连任意节点
- 引入独立路由层
- 客户端感知分片拓扑
面临的挑战
- 谁决定分片在哪个节点?
- 路由层是否是单点故障?
- 分片迁移期间如何保证请求正确?
常见解决方式
- 协调服务
- ZooKeeper、etcd
- 基于共识协议,防止脑裂
- 流言协议
- 用于无主系统
- 提供弱一致性保证(如 Cassandra)
七、分片与二级索引
分片通常依赖 主键 / 分区键,但很多业务场景需要通过 非主键字段查询。
例如:
查询所有“红色”的汽车
这就涉及二级索引,而二级索引在分片系统中是一个难题。
1️⃣ 本地二级索引
- 每个分片维护自己数据的索引
- 写入简单
- 查询需要 分散 / 聚集(Scatter-Gather)
问题
2️⃣ 全局二级索引
- 索引本身也进行分片
- 每个索引分片维护某一类值的 ID 列表
权衡
- 读更高效
- 写更复杂
- 可能需要分布式事务或接受最终一致性
总结
分片是分布式系统实现可伸缩性的核心手段,但它带来的复杂性远不止“数据拆开”这么简单。
- 分片方案一旦选错,后期代价极高
- 没有银弹,只有权衡
- 分片设计本质上是对业务访问模式的建模
理解分片,不只是理解一种算法,而是理解:
数据、负载、演化、运维之间的长期博弈