一句话定义
分区(Partition/Sharding)把一张大表的数据集按键切分到多个节点,使读写与存储水平扩展;关键决策是切分键、切分方式(Range/Hash/目录)与数据再平衡策略,代价是跨分区事务、连接与二级索引的复杂度。
为什么重要
- 单机容量与写入吞吐总有天花板,分区是绕不开的规模化手段——也是反范式(kp-008)在分布式下被强化的原因。
- 「选错分区键导致热点」是分库分表项目最常见的翻车点,且事后迁移代价巨大。
- 二级索引在分区世界有两种形态(本地/全局),直接决定跨分区查询能不能做、怎么做。
前置知识
kp-023(多节点与复制基础)。
核心概念
- 分区键(Partition Key):决定数据归属的列;与主键、查询模式强耦合。
- Range 分区:按键区间连续切分,范围查询友好、易生热点(最新区间最热)。
- Hash 分区:对键取散列模 N,分布均匀、范围查询失效(需扫全部分区)。
- 目录分区(Directory):查表服务决定归属,灵活但引入查询依赖。
- 再平衡(Rebalance):节点增减或负载倾斜时迁移分区;固定大分区数 + 均匀切分是主流(避免一致性哈希的细粒度抖动亦可)。
- 本地二级索引:索引随数据分区,查询需扇出到全部分区;全局二级索引:按索引列重新分区,读单点高效、写要跨分区双写。
- 请求路由:客户端直连、中间层代理(Proxy)、或 gossip 元数据路由。
原理与机制
分区与复制正交:每个分区内部再做主从复制(kp-023),形成「分片 × 副本」矩阵。再平衡的工程共识是不用 mod N(N 变化导致几乎全部数据迁移),而是固定较大分区数(如每个节点负责 10~100 个大分区)或按固定边界切分区间,节点加入时只是「分区分组」的重新分配,迁移量与数据量成正比而非与节点数乘积成正比。热点治理:按时间序写入的场景(消息、日志)Range 分区尾部必然热,对策是「时间 + 散列」复合键;明星用户写热点用「键加盐」拆分。跨分区操作的两个硬代价:事务需要 2PC(kp-018),二级索引需要二选一(本地扇出 vs 全局双写)。这也是 NewSQL(kp-026 引出的 Spanner 系)选择「Range 分区 + 共识组 + 分布式 MVCC」统一解决的背景。
实例或案例
订单系统按 user_id Hash 16 分片:单用户订单永远在同一分片,「我的订单」查询单分片完成;但「今日全平台订单报表」需扇出 16 片聚合。运营侧按时间查(不带头像 id)则只能靠全局二级索引或数仓。热点案例:某头部主播 ID 落在单分片并贡献 30% 写入——治理是拆出「大客户专线」:该用户数据单独分片或写缓冲削峰。再平衡案例:从 4 节点扩到 8 节点,采用固定 1024 个逻辑分区,每个节点搬走 128 个分区的数据,迁移期间双写路由由代理层按分区表灰度切换。
常见误区
- 用
user_id % 节点数做路由:扩容时数据几乎全部重排,必须用固定分区数或一致性哈希式映射。 - 分区键与查询键脱节:高频查询不带分区键,每条查询扇出全部分区,扩展收益归零。
- 以为分区能解决单分区热点:分区内热点要靠复合键加盐或业务拆分,分区数本身不救热键。
自测题
- Range 与 Hash 分区在「时间范围查询」上各表现如何? 答:Range 天然支持(区间即分区);Hash 打散键序,时间范围需扫全部分区再归并。
- 本地与全局二级索引的写放大差异? 答:本地索引随本分区一次写;全局索引要向「索引分区」额外发一次写(跨节点事务),写放大与失败面都更大。
公式或模型
负载均衡度:理想下每节点承载 Q / M 请求(Q 总请求、M 节点);热点偏斜度 skew = 分区峰值负载 × M / Q,> 3 即需治理。再平衡迁移量(固定分区数):迁移数据 ≈ 总数据量 / 新旧节点数的最小公倍关系,与节点数近似无关。
图示
直观类比
Range 分区像字典按首字母分卷:查「zh 开头的词」直接抽一本,但「最近新增的词」全堆在最后一卷;Hash 分区像把卡牌按花色散列洗进三个盒子:每个盒子厚度均匀,但「按顺序理牌」得把三个盒子全倒出来。
与其他知识点的关系
kp-008 的反范式在分区下从「优化项」变成「生存技能」;kp-018 的 2PC 承接跨分区事务;kp-026 的共识组为每个分区提供高可用;kp-027 的 NoSQL 家族按分区能力各有取舍。
延伸阅读
- 《数据密集型应用系统设计》(Martin Kleppmann)第 6 章
- 《数据库系统概念》(Abraham Silberschatz 等)分布式数据库章节