Distributed Locks: Redlock, etcd, ZooKeeper ו-Leader Election בפרקטיקה

מאת צוות מדיה דיל · 02.09.2026 · טכנולוגיה · 6 דק׳

מנעול רגיל עובד רק בזיכרון משותף. איך Redlock, etcd ו-ZooKeeper מממשים נעילה מבוזרת, למה Fencing Tokens קריטיים, ומתי Leader Election הוא הפתרון הנכון.

מנעול (Mutex) רגיל בקוד עובד מצוין כשכל התהליכים רצים על אותו מכונה וחולקים זיכרון משותף. אבל ברגע שהאפליקציה רצה על כמה instances — כפי שכל שירות מודרני רץ — אין זיכרון משותף, ואין "מנעול" שכולם רואים אותו דבר. Distributed Locks פותרים בעיה ספציפית וחשובה: איך מבטיחים שרק מופע אחד מבצע פעולה מסוימת בכל רגע נתון, כשאין לאף אחד תמונה מלאה ומיידית של כל השאר.

למה מנעול בקוד לא עוזר כאן

מנעול רגיל (כמו threading.Lock) מבוסס על כך שכל התהליכים המתחרים על המשאב יכולים לבדוק ולעדכן את אותו bit בזיכרון בפעולה אטומית אחת. במערכת מבוזרת אין את זה — כל instance רץ בתהליך נפרד, לרוב על מכונה נפרדת, וצריך צד שלישי מוסכם שכולם פונים אליו כדי להכריע מי מחזיק בזכות הפעולה כרגע. הצד השלישי הזה הוא בעצמו מסד נתונים או שירות קונצנזוס, וזה בדיוק מה שהופך את הבעיה למורכבת.

Redlock: מנעול מבוזר מעל Redis

אלגוריתם Redlock מציע לנעול על פני כמה instances עצמאיים של Redis (בדרך כלל 5), ולדרוש רוב (למשל 3 מתוך 5) שהצליחו להגדיר את המפתח עם TTL תוך חלון זמן קצר. הרעיון: גם אם node בודד נופל או מתנתק, הרוב עדיין מבטיח נעילה תקפה. הבעיה המרכזית שמרטין קלפמן הצביע עליה בביקורת ידועה היא ש-Redlock מסתמך על שעונים מסונכרנים ועל הנחה ש-GC Pause או השהיית רשת לא יגרמו ל-client לחשוב שהוא עדיין מחזיק במנעול אחרי שה-TTL כבר פג בפועל אצל אחרים.

etcd ו-ZooKeeper: נעילה מעל קונצנזוס אמיתי

בניגוד ל-Redlock שמבוסס על "רוב מקרי" בין nodes עצמאיים, etcd (מבוסס Raft) ו-ZooKeeper (מבוסס ZAB) מממשים קונצנזוס מלא — כל כתיבה עוברת דרך Leader יחיד ומאושרת על ידי רוב אמיתי לפני שהיא נחשבת מוצלחת. מנעול על גביהם מיושם כ-Lease: session עם TTL שמתחדש (Keep-Alive), וכשה-session נופל, המנעול משתחרר אוטומטית ומדורג ל-client הבא בתור. זו קרקע יציבה משמעותית יותר לנעילה שקריטית לנכונות המערכת, לא רק ליעילות.

Fencing Tokens: ההגנה שרוב המימושים שוכחים

גם מנעול "תקין" לא מספיק לבדו. תרחיש קלאסי: Client A מקבל מנעול, נתקע ב-GC Pause ארוך, המנעול פג ועובר ל-Client B, ואז A מתעורר וכותב למשאב בלי לדעת שהוא כבר לא בעל הזכות. הפתרון הוא Fencing Token — מספר עולה מונוטונית שניתן עם כל מנעול, כאשר המשאב המוגן (למשל storage) דוחה כל כתיבה עם token נמוך מהאחרון שראה. בלי Fencing Token, המנעול עצמו הוא רק אשליה של בטיחות.

Leader Election: השימוש הנפוץ ביותר בפועל

מרבית השימושים המעשיים ב-Distributed Locks בפרודקשן הם למעשה Leader Election: מתוך צי instances זהים, רק אחד צריך לרוץ כ-Leader שמבצע משימת cron, מנהל partition assignment, או כותב checkpoint. Kubernetes Controllers עצמם משתמשים במנגנון דומה (Lease API) כדי להבטיח שרק Controller אחד פעיל בכל רגע, גם כשרצות כמה רפליקות לצורכי High Availability.

TTL קצר מול TTL ארוך: פשרה שאין ממנה מנוס

TTL קצר מאפשר Failover מהיר כשה-Leader נופל, אבל חושף לסיכון שמופע חי ייפול מהמנעול רגעית בגלל השהיית רשת או GC Pause ואיבד אותו בטעות. TTL ארוך מקטין את הסיכון הזה אבל מאט משמעותית את הזמן שלוקח למערכת להבחין ש-Leader מת ולבחור חלופה. אין ערך "נכון" אוניברסלי — זו החלטת תצורה שחייבת להיגזר מכמה זמן Downtime מקובל בעסק שלכם.

מתי בכלל לא צריך מנעול מבוזר

הרבה פעמים הבעיה האמיתית היא לא "מי מבצע קודם" אלא "מה קורה אם משהו קורה פעמיים". אם אפשר לעצב את הפעולה כך שהיא Idempotent — הרצה כפולה לא משנה את התוצאה — אין צורך במנעול בכלל. באופן דומה, בתרחישי טרנזקציה מבוזרת בין שירותים, לרוב עדיף Saga Pattern עם פעולות מפצות על פני ניסיון לנעול משאבים בכמה שירותים בו-זמנית — נעילה מבוזרת חוצת-שירותים היא לרוב סימן לבעיית עיצוב, לא פתרון.

הקשר ל-CAP Theorem

כל שירות נעילה מבוזר הוא בעצמו מערכת CP: כשיש Partition ברשת, הוא חייב לבחור בין להמשיך לענות (בסיכון שתי צדדים יחשבו שהם מחזיקים במנעול) לבין לחסום ולהמתין לקונצנזוס. זו הסיבה ש-etcd ו-ZooKeeper מעדיפים לחסום על פני לענות שגוי, בעוד Redlock, בהיותו מבוסס-רוב רופף יותר, פגיע יותר בדיוק בתרחישי ה-Partition שהמשפט של CAP מדבר עליהם.

בונים מערכת מבוזרת וצריכים לוודא שרכיב קריטי לא רץ פעמיים בטעות? נשמח לעזור לכם לתכנן את זה נכון בוואטסאפ.

תגיות: Distributed Locks · Redlock · etcd · ZooKeeper · Leader Election

← חזרה לבלוג · צור קשר