外观
一句话答案
将节点映射到哈希环,key 顺时针找最近节点,增删节点只影响相邻数据;虚拟节点解决数据倾斜。
核心要点
传统哈希取模的问题:
hash(key) % N(N = 节点数量)
当节点数量变化时(新增或下线一台机器):
N 变了 → 几乎所有 key 的映射都变了 → 大量缓存失效 → 缓存雪崩
例如:3 台变 4 台,约 75% 的 key 需要重新映射一致性哈希(Consistent Hashing)原理:
① 构建哈希环(Hash Ring):
将哈希值空间组织成一个 0 ~ 2^32-1 的环
② 节点映射到环上:
对每个节点的 IP/名称进行哈希,映射到环上的某个位置
③ Key 映射规则:
对 key 进行哈希 → 在环上顺时针找到第一个节点 → 该节点负责存储这个 key
示意图:
0
│
Node C ─●─── Key1 → 顺时针找到 Node A
│
2^32*3/4 ─────┼───── 2^32*1/4
│
Key3 ──● │ ●── Node A
│
│
Node B ─●─── Key2 → 顺时针找到 Node B
│
2^32/2
新增/删除节点时:
只影响该节点在环上相邻的一小段区间的 key 映射
大部分 key 的映射不变 → 最小化缓存失效为什么需要虚拟节点?
问题:节点数量少时,哈希环上节点分布不均匀 → 数据倾斜
示例(3 个节点,分布不均):
Node A 负责 60% 的环空间
Node B 负责 30% 的环空间
Node C 负责 10% 的环空间
→ 数据严重倾斜,Node A 压力巨大
解决方案——虚拟节点(Virtual Node):
每个物理节点映射为多个虚拟节点(如 150~200 个)
Node A → VN_A_1, VN_A_2, VN_A_3, ..., VN_A_150
Node B → VN_B_1, VN_B_2, VN_B_3, ..., VN_B_150
Node C → VN_C_1, VN_C_2, VN_C_3, ..., VN_C_150
虚拟节点均匀分散在哈希环上 → 各物理节点负责的数据量趋于均匀
效果:
虚拟节点数量越多 → 数据分布越均匀
一般 150~200 个虚拟节点/物理节点就能达到较好的均匀度一致性哈希的应用场景:
| 场景 | 说明 |
|---|---|
| 缓存集群分片 | Redis Cluster 之前的客户端分片(如 Jedis ShardedPool) |
| 负载均衡 | Nginx upstream 的 consistent_hash 模块 |
| 分布式存储 | Cassandra、Amazon Dynamo 的数据分片 |
| CDN 节点选择 | 根据内容 URL 哈希选择缓存节点 |
追问与易错
追问方向:
- 虚拟节点数量设多少?
- 怎么处理节点负载不均?
- Redis Cluster 为什么用哈希槽?
易错点:
- ❌ 一致性哈希完全均匀——没有虚拟节点时可能倾斜
- ❌ 混淆一致性哈希和哈希槽
💡 记忆锚点
想象一个钟表盘:节点是钟面上的刻度,数据沿顺时针找最近的刻度存放。加减一个刻度只影响相邻那一小段弧,不像取模法那样全盘洗牌。刻度太少分布不均怎么办?每个真刻度变出150个虚拟刻度均匀撒满表盘,数据就不会扎堆了。