一致性哈希 (Consistent Hashing)
Published: Mon Feb 16 2026 | Modified: Sat Feb 07 2026 , 3 minutes reading.
一致性哈希:平衡之環
演算法背後的故事:營火晚會的邏輯
想像一群童子軍(10 個人)圍成一個大圈坐在營火旁。每個人負責捕捉飛入她們那一段圓弧區域的「螢火蟲」。
如果有第 11 個童子軍加入,大家只需要稍微挪動一下位置。只有新成員左右兩邊的兩名童子軍需要交出她們的一小部分管轄區域。剩下的 8 名童子軍手裡的螢火蟲完全不需要動位置。
現在,想像如果她們使用嚴格的編號系統:「如果螢火蟲的 ID 是 ,那麼編號為 的人負責捕捉。」 如果第 11 個人加入,公式變成了 。突然之間,營地裡幾乎每一隻螢火蟲都必須移交給不同的人。這就是再哈希災難 (Rehash Disaster)。
1997 年,麻省理工學院 (MIT) 的 David Karger 及其團隊提出了 一致性哈希 (Consistent Hashing)。她確保了當集群規模變化時,只有 的數據需要搬家。
為什麼需要它?
一致性哈希是分散式系統可擴展性 (Scalability) 的基石。
- 分散式快取 (Memcached/Redis): 增加一台快取伺服器不應該導致全量快取失效。
- 負載均衡: 將 Web 請求均勻分布在一組伺服器上。
- 分散式資料庫 (Cassandra/DynamoDB): 將數十億行數據分散到數百個節點上。
演算法是如何「思考」的
這個演算法像是一個環形架構師。
- 哈希環: 她將所有可能的哈希值想像成一個閉合的圓環。
- 節點入駐: 她將伺服器(節點)的 ID 進行哈希,並放置在環上的隨機點。
- 數據落位: 她將數據(如用戶 ID)進行哈希,也放置在環上。
- 順時針規則: 沿著環順時針方向走,數據遇到的第一個節點就是她的負責人。
- 虛擬節點: 為了防止某個節點「運氣不好」分配到過多數據,她為每個伺服器創建了許多「虛擬節點」——即散佈在環上各處的替身,以確保數據分配絕對均勻。
工程決策:最小擾動
- 節點增加: 當新節點加入時,她只從其逆時針方向的緊鄰鄰居那裡「分擔」一部分數據。
- 節點移除: 當某個節點故障時,她的數據只需「順延」給環上的下一個鄰居。
- 穩定性: 在一個擁有 1000 個節點的系統中,增加 1 個節點僅會擾動 0.1% 的數據。而如果沒有一致性哈希,這個數字將接近 99.9%。
實作參考 (Python)
import hashlib
class ConsistentHashRing:
def __init__(self, nodes=None, replicas=3):
self.replicas = replicas # 虛擬節點數量
self.ring = {}
self.sorted_keys = []
if nodes:
for node in nodes:
self.add_node(node)
def _hash(self, key):
return int(hashlib.md5(key.encode()).hexdigest(), 16)
def add_node(self, node):
for i in range(self.replicas):
h = self._hash(f"{node}:{i}")
self.ring[h] = node
self.sorted_keys.append(h)
self.sorted_keys.sort()
def get_node(self, data_key):
if not self.ring: return None
h = self._hash(data_key)
# 順時針尋找第一個節點
for node_hash in self.sorted_keys:
if h <= node_hash:
return self.ring[node_hash]
# 如果走到了環的盡頭,繞回第一個節點
return self.ring[self.sorted_keys[0]]
# 使用範例
ring = ConsistentHashRing(["Server_A", "Server_B", "Server_C"])
print(f"用戶 'luke' 分配到的伺服器: {ring.get_node('luke')}")小結
一致性哈希教會我們:真正的規模化需要局部化變化。透過從僵化的全局公式轉向靈活的環形排列,我們可以讓系統在成長過程中避免混沌。她提醒我們,在一個不斷變化的世界中,最好的系統是那些能夠適應變化而不打破全局寧靜的系統。
