什么是一致性哈希?它解决了什么问题?
简化版
普通哈希用 hash(key) % N 把数据分到 N 台机器上,一旦增减机器 N 变了,几乎所有 key 的落点都变,缓存大面积失效。一致性哈希把哈希值空间组织成一个 0 ~ 2³²−1 的环,机器和 key 都映射到环上,key 顺时针找到的第一台机器就是它的归属。增减一台机器只影响环上相邻的一小段 key,其余不动。再配合虚拟节点让分布更均匀。
详细版
普通取模的痛点:节点 = hash(key) % N。3 台机器变 4 台,% 3 变 % 4,几乎每个 key 的结果都变了,缓存全部失效、数据全部要迁移——在分布式缓存里这是灾难(缓存雪崩)。
一致性哈希的做法:
- 想象一个首尾相接的哈希环,范围
0 ~ 2³²−1。 - 把每台机器(用 IP/名字哈希)放到环上一个点。
- 每个 key 也哈希到环上一个点,顺时针走,遇到的第一台机器就是它的存储节点。
好处:增删一台机器,只有「它到上一个节点之间」的这段 key 需要迁移,其他 key 归属不变。迁移量从「几乎全部」降到「1/N 左右」。
虚拟节点:真实节点少时,环上分布不均,容易某台机器负载过重。给每台机器在环上放很多个「虚拟副本」(如 node1#1、node1#2…),让分布更均匀,也让某台宕机时它的负载均摊给其余多台,而不是全压给下一台。
完整版教学
一、普通哈希取模的致命问题
分布式缓存/分库分表常用 hash(key) % N 决定数据放哪台。它在节点数固定时挺好,但节点数一变就崩:
- 3 台扩到 4 台:
hash % 3→hash % 4,绝大多数 key 落点改变。 - 后果:请求打到新机器,缓存里没有 → 全部穿透到数据库 → 缓存雪崩,数据库被打垮。
根源是「取模」把「节点总数 N」直接绑进了计算,N 一变全盘皆变。
二、哈希环怎么把影响范围缩小
一致性哈希不再对 N 取模,而是把 key 和节点都映射到一个固定大小的环(2³² 个点,与节点数无关)。key 顺时针找最近节点。
- 加一台机器 M:M 插到环上某个位置,只有「从 M 逆时针到上一个节点」这段原本属于 M 后继节点的 key,现在改归 M。其余 key 完全不受影响。
- 删一台机器:它负责的那段 key 顺时针顺延给下一个节点,别的不动。
因为环的大小固定、和节点数无关,节点增减只搅动局部,这就是「一致性」的含义——尽量保持已有映射不变。
三、数据倾斜与虚拟节点
只有少数几个真实节点时,它们在环上可能挤在一起,导致某台机器覆盖的弧段特别长、负载过重——数据倾斜。
解决办法是虚拟节点:每个真实节点在环上放 N 个虚拟副本(对 节点名+编号 分别哈希)。比如 3 台机器各放 150 个虚拟节点,环上就有 450 个点,分布均匀得多。查找时 key 找到虚拟节点,再映射回它对应的真实节点。
虚拟节点还有个好处:某台机器宕机时,它那些虚拟节点分散在环各处,负载会均摊给多台其他机器,而不是全部压给环上的单一后继节点。
四、典型应用场景
- 分布式缓存:memcached、Redis 集群的数据分片,避免扩缩容时缓存全失效。
- 负载均衡:把请求按会话 key 稳定路由到某台后端(一致性哈希负载均衡)。
- 分布式存储 / 一致性哈希路由:Dynamo、Cassandra 等用它决定数据副本落点。
五、面试怎么答出层次
按「问题 → 方案 → 优化」三层讲:① 普通取模在节点变化时全量失效(讲清雪崩);② 哈希环把影响范围缩到相邻一段(讲清顺时针归属和只迁移局部);③ 虚拟节点解决数据倾斜、并让宕机负载均摊。三层都点到,就是满分答案。
六、常见误区与追问
| 方案 | 节点变化影响范围 | 主要问题 |
|---|---|---|
普通取模 hash(key)%N | 大量 key 重新映射 | 扩缩容代价大 |
| 一致性哈希 | 只影响相邻区间 | 可能数据倾斜 |
| 一致性哈希 + 虚拟节点 | 影响范围小且更均匀 | 维护映射更复杂 |
hash ring:
nodeA
/ \
key1 nodeB
\ /
nodeC
key 沿顺时针找到第一个节点作为归属节点
记忆钩子:一致性哈希不是让数据永远不迁移,而是把节点增删时的迁移范围从“全局大洗牌”缩小到“环上局部区间”。
数字例子:原来有 4 台机器,用普通取模时从 N=4 扩到 N=5,很多 key 的 hash%N 都会变化,可能大部分缓存失效。用一致性哈希新增一台节点 D,只会接管它在环上前一个节点到 D 之间的那段 key,其他区间不变。虚拟节点可以把一台物理机拆成 100 个点,减少某台机器区间过大的倾斜。
- 误区:一致性哈希扩容时完全不迁移数据。 它仍然会迁移新增节点负责区间内的数据,只是影响范围更小。
- 误区:没有虚拟节点也一定均匀。 物理节点少时,环上位置可能不均匀,导致某些节点负责过大区间。
- 误区:一致性哈希只用于缓存。 它常用于缓存、分布式存储、负载路由等需要稳定映射的场景。
- 追问:虚拟节点解决什么问题? 让物理节点在环上有多个位置,平滑数据分布和负载。
- 追问:节点下线时数据怎么迁移? 下线节点负责的区间通常顺时针交给下一个节点。
- 追问:和分片取模相比核心优势是什么? 节点数变化时,不需要让绝大多数 key 重新映射。
七、加强记忆
一致性哈希用固定大小的哈希环代替 hash % N,key 顺时针找到第一个节点归属。节点增减只影响环上相邻一小段(约 1/N),避免了普通取模「扩缩容全量缓存失效/雪崩」的问题。真实节点少会数据倾斜,用虚拟节点(每台放多个环上副本)让分布均匀、宕机负载均摊。常用于分布式缓存和分片。