Lesson 0006 · 系统设计 · Phase 2 数据层

分片与一致性哈希

⏱ 预计 30 分钟(含动手实验) 🎯 解决「写也扛不住、单机也装不下」 📖 前置:Lesson 0004 · Lesson 0005
与你的 Mission 的关系

Lesson 0004 的读写分离解决扩展;但最终都汇聚到主库——一条路走不通,就得把数据切开放。一致性哈希则是分布式系统的通用地基:Redis 集群、Dynamo、Cassandra、CDN、P2P 网络全都用它[1]。面试中「数据怎么分」的追问几乎必到。

§1 · 分片的三种切法

分片(sharding):把数据按某个键水平切开,每台机器负责一个分片。怎么决定「某条数据归谁」?三种策略:

策略机制主要代价
范围分片
Range-based
ID 1–1000 万在 A,1000–2000 万在 B;对范围查询友好热点:新数据都写最新段,最后一片被打爆
哈希分片
Hash-based
hash(user_id) % N;分布均匀扩容时 N 变了 → 几乎全部数据要搬家(见 §2)
查表分片
Directory
独立路由服务记录「哪条数据在哪」;最灵活查表服务本身是瓶颈和单点

§2 · 核心难题为什么需要一致性哈希

取模分片的天生缺陷:hash % 3 变成 hash % 4,原来所有 key 的归属几乎全部改变——扩容一台机器 = 搬家全部数据,期间缓存全部失效(雪崩,Lesson 0005)。

一致性哈希consistent hashing)的解法:把节点和 key 都放到一个 0 ~ 2³² 的上,key 顺时针找最近的节点。增删节点只影响相邻一段的数据,迁移量从「几乎全部」降到「约 K/N」[1]

别只看图——亲手玩一遍。下面的可视化里,黑边的小点就是这次变更中需要迁移的 key:

实验指南(30 秒一个结论)

① 点「添加节点」:观察迁移比例 ≈ 1/N(新节点只接管一小段);
② 点「移除节点」:同理,它的数据顺时针交给下家;
③ 看图例:不开虚拟节点时,三个节点的 key 占比可能差很远(随机位置的运气);
④ 打开「虚拟节点」:占比立刻变均匀——这就是 Dynamo/Cassandra 的工程答案。

虚拟节点 Virtual Nodes

物理节点少时,它们在环上的随机位置会撞出不均匀的分布(方差大)。解法:每个物理节点在环上放置 N 个「影子」(如 100 个),统计意义上分布立刻均匀;还能按机器算力分配不同数量的影子——新机器多放几个,老机器少放几个[1]

§3 · 分片键的选择比算法更重要

分片键(sharding key)一旦选定极难更改,是数据层最重要的决策。三条标准:

诚实标注失效边界

分片的代价清单要主动说:跨片 JOIN 基本告别、跨片事务要分布式协议(Lesson 0009 预告)、二级索引只覆盖本片。「什么时候才需要分片」本身就是权衡——很多系统在数据量到 TB 级之前,读写分离 + 缓存就够了。

§4 · 随堂检测

§5 · 检索练习

凭记忆回答:① 取模分片扩容时会发生什么?一致性哈希把代价从多少降到多少?② 虚拟节点解决什么问题?③ 分片键的三条标准?

核对参考答案

%N%N+1 → 几乎全部 key 归属改变(全量搬家 + 缓存全失效);一致性哈希把它降到约 K/N(加一台只迁 1/N)。② 物理节点少时环上位置随机导致分布不均;每节点放 N 个影子位置,统计均匀 + 按算力加权。③ 高基数、查询对齐(带分片键查)、抗倾斜。

§6 · 本周行动

行动任务(约 30 分钟)

① 找到你公司数据层(或 Redis 集群)的分片方式:取模?一致性哈希?分片键是什么?
② 用三条标准审一遍分片键:基数够吗?最频繁的查询带分片键吗?有倾斜风险吗?
③ 没有分片也不打算分?那就回答「数据量到多少时会需要」——给出数字和依据。

§7 · 延伸资源

💬 在可视化里发现反直觉的现象?或者你们业务的分片键拿不准?说出来一起推演。