1. 普通 Hash 的问题
text
node = hash(key) % N当 N 变化(节点增/删)→ 几乎所有 key 重新映射 → 瞬间大规模缓存失效 → “雪崩”。
2. 一致性 Hash 原理
- 把整个 hash 空间(0 ~ 2³²-1)首尾相接成 闭环
- 每个节点计算 唯一 hash 落在环上
- 每个 key 顺时针找 第一个≥自己 hash 的节点
- 仅影响环上相邻区间,其他 key 保持不动
节点变动时 数据迁移量 ≈ 1/N,雪崩概率大幅下降。
3. 虚拟节点(Virtual Node)(面试重点)
问题:真实节点少 → 环上分布不均 → 数据倾斜 + 负载倾斜
解决:每个物理节点生成 k 个虚拟节点(k=150~200 常用)
virtualHash = hash("物理IP#序号")- 虚拟节点均匀散落在环上,整体负载方差↓k 倍
- 增删物理机时,多个虚拟节点间隔移除/加入,进一步平滑迁移量。
4. 代码片段(带虚拟节点,Java)
java
public class ConsistentHash {
private final SortedMap<Integer, String> ring = new TreeMap<>();
private final int virtualCnt;
public ConsistentHash(List<String> nodes, int virtualCnt) {
this.virtualCnt = virtualCnt;
for (String node : nodes) add(node);
}
private void add(String node) {
for (int i = 0; i < virtualCnt; i++)
ring.put(hash(node + "#" + i), node);
}
public String get(Object key) {
int h = hash(key);
SortedMap<Integer, String> tail = ring.tailMap(h);
int nodeHash = tail.isEmpty() ? ring.firstKey() : tail.firstKey();
return ring.get(nodeHash);
}
private int hash(Object o) { return o.hashCode() & 0x7fffffff; }
}5. 面试金句
“一致性哈希把 ‘全体重新映射’ 变成 ‘只动邻居’;
虚拟节点把 ‘物理少导致倾斜’ 变成 ‘虚拟多而均匀’, 最终让 增删节点时数据迁移量最小、负载最平滑。”