专业书籍精读 · System Design Interview 卷一 · 第 5 章

设计一致性哈希

System Design Interview: An Insider's Guide · Vol 1 · Ch 5 · Alex Xu · 2020

EN →

这一章讲什么?

你网购的包裹要先进分拣中心:几个仓库排在那里,每个包裹按单号被分到其中一个。分拣规则要满足两件事——快(不用查册子,看一眼单号就知道去哪个仓库)、稳(下次找这个包裹,还得算到同一个仓库)。这一章讲的就是这条分拣规则,以及它在仓库数量变化时会出什么事。

先说个怪事

你大概觉得:本来 4 个仓库,新开第 5 个,那把大约五分之一的货挪过去就行了。可用最常见的那条规则,你得把差不多八成的货全部重新搬一遍——不是搬到新仓库,而是每个包裹都要换一个不同的旧仓库。开一个仓库,全城的货都得动。

旧世界为什么难

那条最常见的规则是:单号除以仓库数,看余数。4 个仓库,余数 0、1、2、3 各对应一个。简单又快。问题出在「仓库数」这三个字被写进了公式里:仓库从 4 变成 5,除数就从 4 变成 5,几乎每个包裹算出来的余数都变了——它们不是「大部分不动、少数搬去新仓库」,而是集体换了个位置。

后果很直接:分拣中心其实是缓存。平时几乎人人都能就近拿到东西;仓库一变,大家全找错地方,请求哗地一下全砸到后面那个又慢又金贵的总库上。压垮系统的不是新加的那台机器,是那次搬家本身。

核心机制:把仓库排成一圈

换个办法。把所有可能的单号想象成一条首尾相接的圆形跑道,每个包裹按单号落在跑道上某一点;仓库也按自己的名字落在跑道上某一点。规则改成一句话:包裹从自己的位置出发,顺着跑道往前走,遇到的第一个仓库就归它。

妙处在于:公式里再也没有「仓库数」这个东西了。新开一个仓库,就是往跑道上插一个新点——只有「从新点往回退到上一个仓库」的那一小段包裹需要挪,其余整条跑道上的包裹一个都不用动。关掉一个仓库同理:它那一段的包裹顺着跑道交给下一个仓库,别人不受影响。

还得打个补丁

光这样还不够均匀。仓库落在跑道上的位置是随机的,可能三个仓库挤在一起、留下一段特别长的空当归第四个——那个仓库就被撑爆了。补丁很土也很有效:让每个仓库在跑道上开几十上百个「分店」,名字带编号,各自算各自的落点。分店一多,长短弧被打散又摊平,每个仓库分到的总量自然就接近了——这就是「虚拟节点」。

诚实说一句代价:分店不是越多越好——一个仓库的货散在越多小段上,就跟越多的邻居搅在一起,某天两个仓库同时出事,波及面反而更大。

一句话记住

老办法把「仓库数」写进了公式,所以仓库一变,全城的货都要搬。一致性哈希把仓库排成一圈、只让每个包裹找顺时针方向最近的那一个,于是加减仓库只惊动一小段。再给每个仓库开一堆分店,把长短不一的弧摊匀。

想进到具体算法、量级和示意图? → 切到精读版