已发布·持续改进
Algorithm
一致性哈希把键分配到多台服务器上,使增删节点时只迁移必要的键,广泛用于分布式缓存、存储和负载均衡。
一致性哈希(consistent hashing)是一种把键分布到多台服务器上的方法,由 Karger 等人于 1997 年为分布式 Web 缓存提出。它把哈希值空间看作一个环,服务器和键都放在同一个环上,每个键归属于从它出发顺时针遇到的第一台服务器。为每台服务器在环上放置多个点(虚拟节点)可以让负载更均匀。
使用 hash(key) % N 时,服务器数量一变,几乎所有键的位置都会改变,缓存命中率骤降,还会产生大量数据迁移。一致性哈希在新增一台服务器时平均只迁移全部键的 1/(N+1),而且只迁往新服务器,因此可以在运行中方便地扩容和缩容。Memcached 客户端的 ketama、Amazon 的 Dynamo 论文、Cassandra 以及 Nginx 和 HAProxy 的一致性哈希选项都基于这一原理。
建议先算一算 mod-N 分片会迁移多少键,再用有序数组和二分查找实现哈希环。接着测量虚拟节点数量增加时负载偏差如何缩小,并比较副本选择、Rendezvous 哈希和跳跃一致性哈希。打好这些基础后,在系统设计面试中也能清楚地说明各种取舍。
增删节点时期望只迁移约 1/(N+1) 的键,已有节点之间不会互相交换键。
把哈希空间看作一个圆,键归属于顺时针方向的第一个节点。查找就是在有序位置上做二分查找。
每个节点在环上放置多个点,以减小负载偏差,并用点的数量表示服务器容量的差异(权重)。
沿顺时针方向选取 R 个不同节点存放副本;Rendezvous 哈希和跳跃一致性哈希以其他方式实现同样的目标。
用 MD5 摘要的前 8 个字节作为环上的位置,每个节点有 100 个虚拟节点,通过 bisect.insort 插入有序列表。get 用 bisect_left 找到位置不小于键哈希的第一个点,越过末尾时回到开头。加入节点 D 后只有约四分之一的键迁移,再把它移除,所有键都会回到原来的节点。
consistent_hashing.py
import bisect
import hashlib
def h(key: str) -> int:
return int.from_bytes(hashlib.md5(key.encode()).digest()[:8], "big")
class HashRing:
def __init__(self, nodes=(), vnodes=100):
self.vnodes = vnodes
self.points = [] # sorted hash positions on the ring
self.owner = {} # position -> physical node
for node in nodes:
self.add(node)
def add(self, node):
for i in range(self.vnodes):
p = h(f"{node}#{i}")
bisect.insort(self.points, p)
self.owner[p] = node
def remove(self, node):
for i in range(self.vnodes):
p = h(f"{node}#{i}")
self.points.pop(bisect.bisect_left(self.points, p))
del self.owner[p]
def get(self, key):
if not self.points:
raise LookupError("ring is empty")
i = bisect.bisect_left(self.points, h(key)) % len(self.points)
return self.owner[self.points[i]]
ring = HashRing(["A", "B", "C"])
keys = [f"user:{n}" for n in range(10_000)]
before = {k: ring.get(k) for k in keys}
ring.add("D")
moved = sum(before[k] != ring.get(k) for k in keys)
print(f"moved {moved / len(keys):.1%} of keys") # about 25%
ring.remove("D")
print(all(ring.get(k) == before[k] for k in keys)) # True
python consistent_hashing.py共六章,带你从安装一步步了解 一致性哈希 的核心概念。
在这里提问、分享经验,交流关于 一致性哈希 的看法。
还没有讨论。来发起第一个吧。
0 条评论
登录 · 登录后即可发表评论。
来发表第一条评论吧。