缓存机器要扩容。最直白的做法是 server = hash(key) % N——N 一变,几乎每一个键都换了机器,缓存全失效、全部回源。一致性哈希把节点和键都散在一个环上,键顺时针找第一个节点。下面这个开关在两者之间切。
只换一个表达式:server = hash(key) % N ⟶ 把节点和键都散在一个环上,键顺时针找第一个节点。键的分布、哈希函数、机器台数全不动。
⇒ N = 8 加到 9 台,取模要搬 89.0% 的键,环只搬 11.8%——差 7.5 倍。Akamai 1998 年成立,招股书里那个技术就是前一年这篇论文。
比 89% 更要命的是它的构成。新机器最终要承担 11.1% 的键——这部分非搬不可,谁来都得搬。可取模搬了 89.0%,其中白搬 77.8%:它们从一台老机器跑到另一台老机器,没有任何理由。
而环这一边,逐键数过:搬家却没搬到新机器的键是 0 个。⇒ 搬家的键恒等于新机器接管的键,一个都不多。这是个可以逐键验证的等式,不是一句宣称。
① 我写下「取模搬 87.5%」——实测 89.0%。正确的闭式解是 N/(N+1) 不是 (N−1)/N:我把 N 当成了旧的机器台数。
② 我写下「1/(N+1) 是搬家比例的理论下界」——它不是下界,是期望。N = 16 时实测 5.7%,低于 1/17 = 5.9%。新机器接管多少弧本身就是随机的。站得住的是上面那个恒等式,而它比「下界」这个说法更强:下界只给一个不等号,恒等式能逐键验。
③ 我写下「取模的负载几乎完美,变异系数 < 1%」——它是 √(N/K),随机器台数和键数变。N = 64、K = 65 536 时是 3.65%。
把 V 拖到 1:环上每台机器只有一个点,弧长随机得厉害,负载变异系数 119.3%——有的机器分到的键是别人的好几倍,而取模在同样条件下只有 3.65%。朴素的一致性哈希在静态均匀性上输得很难看。
把 V 拖回 100,变异系数降到 10.5%——正好是 1/√V。⇒ 它买的是「变化时的稳定」,代价是「静态时的均匀」,而虚拟节点就是拿内存把这个代价赎回来。⚠ 另外它只解决再平衡,不解决热点:一个被疯狂访问的键,在环上照样落在同一台机器上。