تكرار السؤال: …
الإجابة المختصرة
التجزئة المتسقة ترتب الخوادم والمفاتيح في حلقة دائرية افتراضية، وعند إضافة أو إزالة سيرفر، يُعاد تعيين نسبة طفيفة جداً من المفاتيح (K/N) بدلاً من إعادة توزيع كافة البيانات كما يحدث في خوارزمية Modulo.
الشرح
في خوارزمية hash(key) % N التقليدية، إذا كان لديك 4 خوادم وأضفت خادماً خامساً ليصبح N=5، فإن نتيجة العملية الحسابية تتغير لحوالي 80% من المفاتيح (بشكل عام تتغير نسبة N/(N+1) منها)، مما يتسبب في إفراغ كامل للكاش واختفاء البيانات (Massive Cache Invalidation) وانهيار قواعد البيانات تحت الضغط. تحل Consistent Hashing ذلك برسم حلقة من 0 إلى 2^32 - 1. يوضع السيرفر على الحلقة، ويتم البحث عن أول سيرفر يقع في اتجاه عقارب الساعة لكل مفتاح. تُستخدم العقد الافتراضية (Virtual Nodes) لضمان التوزيع العادل والموحد للأحمال وتفادي البقع الساخنة (Hotspots).
مثال بالكود
import bisect, hashlib
def h(key: str) -> int:
return int(hashlib.md5(key.encode()).hexdigest(), 16)
class Ring:
def __init__(self, nodes, vnodes=100): # virtual nodes spread each server around the ring
self.ring = sorted((h(f"{n}#{i}"), n) for n in nodes for i in range(vnodes))
self.points = [point for point, _ in self.ring]
def node_for(self, key: str) -> str:
i = bisect.bisect(self.points, h(key)) % len(self.ring) # first node clockwise from the key
return self.ring[i][1]
before = Ring(["A", "B", "C", "D"])
after = Ring(["A", "B", "C", "D", "E"])
keys = [f"user:{i}" for i in range(10_000)]
moved = sum(before.node_for(k) != after.node_for(k) for k in keys)
print(f"{moved / len(keys):.0%} of keys moved") # ≈ 1/5, versus ≈ 80% with hash % Nأخطاء شائعة
- تطبيق التجزئة المتسقة دون استخدام العقد الافتراضية (Virtual Nodes)، مما يسبب تفاوتاً غير عادل في توزيع الحمل بين الخوادم.