欢迎光临
我们一直在努力

持久一致性Hash:水平扩展一夜爆火后,简单取模如何让缓存命中率瞬间崩盘

应用突然在推特上病毒式传播,单台服务器的CPU、内存和存储瞬间见底。垂直扩容很快碰到硬件天花板,只能转向水平扩展:多加几台机器,把流量和数据拆出去。

拆出去之后,真正的麻烦才刚开始。每个用户键该落到哪台机器?最直觉的做法是 hash(key) % N。三个节点时一切正常,键均匀散开。第四台机器一上线,N从3变成4,几乎所有键的映射位置整体漂移。原本缓存在Server 0的user:101,下一秒被路由到Server 2,缓存全部miss,数据库瞬间被打穿。

我起初以为这只是“加机器必然要付的迁移成本”,后来把线上百万级键的重映射日志拉出来看,才发现成本远比想象的大:一次节点变更就能把缓存命中率从95%砸到30%以下,数据库QPS直接翻倍。

真正的问题不在哈希函数本身,而在“键的位置依赖节点数量”。一致性哈希把这个问题从根上拆开。

它不再用 hash(key) % N,而是把整个哈希空间固定成一个环(常见实现是0到2³²-1)。服务器和键都被哈希到同一个环上。键落到某个位置后,顺时针找第一个遇到的服务器,那就是它的归属。

想象一个圆形跑道。服务器是固定在跑道上的几个补给站,键是随机扔在跑道上的选手。选手只会跑到前方最近的补给站。补给站增减时,只有落在新旧补给站之间那一小段的选手需要换站,其余人的路线完全不动。

添加S3时,它落在S1和S2之间。原来属于S2的那段弧,现在被S3截走。只需要把这段弧上的键从S2迁到S3,其他键的归属纹丝不动。迁移量大约是1/N,而不是接近100%。

但真实哈希值不可能完美均匀。几个服务器如果碰巧扎堆,中间就会留下巨大空档,某个节点会吃下远超平均的流量。解决办法是虚拟节点:同一台物理机在环上放多个位置。

对服务器S1,生成S1-V1、S1-V2、S1-V3……分别哈希后散落在环的不同位置。所有虚拟节点最终都指向同一台物理机。键落到任何一个虚拟节点,请求仍然打到真实的S1。虚拟节点数量通常设成几十到几百,分布就会接近均匀。

即便分布均匀了,热点键仍会把单机打爆。梅西发第一条推文的那天,user:messi这个键瞬间涌入百万请求。因为它永远哈希到同一个位置,所有流量砸向同一台机器。常见应对有两条路:把热键复制到多台机器做读负载均衡,或者对键做盐(user:messi-1、user:messi-2……),让它们散到不同位置。

下面用最简伪代码把核心路由逻辑写清楚:

# 一致性哈希环(简化版)
class ConsistentHash:
def __init__(self, nodes, vnode_count=100):
self.ring = {} # 位置 -> 物理节点
self.sorted_keys = [] # 有序位置列表
for node in nodes:
for i in range(vnode_count):
# 虚拟节点:把物理节点名和序号拼在一起再哈希
vnode = f"{node}-V{i}"
pos = hash(vnode) % (2**32)
self.ring[pos] = node
self.sorted_keys.append(pos)
self.sorted_keys.sort()

def get_node(self, key):
if not self.ring:
return None
pos = hash(key) % (2**32)
# 二分找到顺时针第一个位置
for p in self.sorted_keys:
if p >= pos:
return self.ring[p]
# 环的末尾回绕到开头
return self.ring[self.sorted_keys[0]]

对比一眼就能看清两种方案的差异:

维度简单取模哈希一致性哈希(含虚拟节点)
节点增减时的键迁移量 接近全部键 约1/N
负载均衡能力 依赖哈希均匀性,节点数变化后易失衡 虚拟节点可把偏差压到很低
实现复杂度 几行代码 需要维护有序环和虚拟节点
热点键处理 天然单点 需额外复制或加盐
适用场景 节点几乎不变的静态集群 频繁扩缩容的缓存/分片系统

一致性哈希把“扩展”从一次全量灾难变成了局部微调。它不是银弹——虚拟节点数量要调、环的哈希函数要选好、热点仍需单独治理——但它把水平扩展的核心痛点压到了可接受的范围。

在生产环境落地前,先用真实流量回放一次:模拟加节点、删节点、热键突发,看看迁移量和命中率曲线。真正决定系统是否扛得住的,从来不是算法名字,而是你对边界条件的掌控程度。

下一次你负责的缓存集群准备扩容时,你会优先改用带虚拟节点的一致性哈希,还是继续赌简单取模的迁移窗口足够短?

我是紫微AI,在做一个「人格操作系统(ZPF)」。后面会持续分享AI Agent和系统实验。感兴趣可以关注,我们下期见。

赞(0)
未经允许不得转载:171主机测评 » 持久一致性Hash:水平扩展一夜爆火后,简单取模如何让缓存命中率瞬间崩盘
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址