סאגות ועסקאות מבוזרות
סאגה היא עסקה ארוכת טווח המתפרקת לרצף של צעדים מקומיים על פני שירותים/מאגרים שונים. לכל צעד יש פעולת פיצוי שמגלגלת את אפקט הצעד בכישלון חלקי. שלא כמו 2PC/3PC, הסאגות אינן מחזיקות מנעולים גלובליים והן מתאימות למיקרו-רחם, רב-אזורים ועומסים גבוהים, שם בסופו של דבר העקביות מקובלת.
1) מתי לבחור סאגות (ומתי לא)
בכושר:- תהליכים עסקיים ארוכים/רב שלבים (order action action action action).
- תחומים שונים ומקומות שבהם אין עסקה משותפת.
- צריך זמינות גבוהה וסולם החוצה.
- אטומיקציה של חומצה מוצקה היא קריטית (לדוגמה, העברת כמויות גדולות באותו רישום).
- אין פיצוי ברור (אתה לא יכול ”לשמור” או לבטל את האפקט).
- הגבלות חוקיות/רגולטוריות דורשות בידוד קפדני ופגיעה ”מיידית”.
2) דגמי סאגה
1. המתאם המרכזי מנהל צעדים ופיצויים.
מקצוענים: זרימה מפורשת, בקרת שגיאות, טלמטריה מפושטת.
חסרונות: נקודת ריכוז, סיכון של מתאם ”שמן”.
2. כוריאוגרפיה (כוריאוגרפיה): אף מרכז - צעדים מופעלים על ידי אירועים (”Service A do X agh service B reacts”).
מקצוענים: קישוריות חלשה, קישוריות פשוטה.
חסרונות: זה יותר קשה לעקוב/לטאטא את הזרימה, הסיכון של ”התפשטות” של כללים.
3. TCC (נסה לאשר/לבטל) - כל צעד הוא ”נסה”, ואז לאשר או לבטל.
מקצוענים: קרוב יותר לפרוטוקול פסאודו-שני פאזות, מנוהל משאבים.
חסרונות: יקרים יותר ביישום ממשקים; זה דורש פסקי זמן של ”נסה”.
3) עיצוב מגרש ופיצויים
אינווריאנטים: ציין בבירור מה צריך להיות נכון ”לפני/אחרי” הצעד (לדוגמה, ”שארית 0”).
פיצוי על עסקה הפוכה: זוהי פעולה לוגית המבטלת את האפקט העסקי (החזר, שחרור, שחזור).
idempotence: גם צעד וגם מפצה יש לחזור בבטחה (על ידי "operation _ id').
פסקי זמן: לכל צעד יש דד-ליין; עיכוב מעורר פיצויים.
אפקטים ללא החזר: להקליט אותם בנפרד (הודעות, דואר אלקטרוני) ולאפשר ”המאמץ הטוב ביותר”.
4) עקביות וסדר
בסופו של דבר עקביות: משתמשים יכולים לראות סתירות זמן; UX - עם ”חכה ”/ספינרים/סטטוסים.
הזמנה על ידי מפתח - קבוצה את הצעדים המתחלפים על ידי מפתח עסקי (order_id) כדי להזמין את האירועים.
Dauplication - לאחסן את רישום העיבוד ('operation _ id' au status) עם ה ־ TTL.
5) תחבורה ואמינות
תבנית היוצא כותבת את האירוע לשולחן היוצא המקומי בתוך אותה עסקה, ואז מפרסמת אותו באופן אסינכרוני לאוטובוס.
חנות דואר אלקטרוני/Idempotency: בצד הצרכן - יומן הודעות כבר מעובד.
בדיוק-פעם ביעילות: ”outbox + idempotent הצרכן” נותן פרקטיקה ”בדיוק פעם אחת”.
DLQ: עבור הודעות ”רעילות” עם מידע מטא עשיר ו redrive מאובטח.
6) שגיאה, מגש מחדש, מדיניות חזרה
אנחנו חוזרים רק על מדרגות אידמפוטנטיות; לכתוב מבצעים עם 'Idempotency-Key'.
גיבוי מעריכי + jitter; מגביל ניסיונות ומועד סופי של הסאגה.
עם הידלדלות מערכתית - שובר מעגל והשפלה חיננית (למשל, לבטל את החלק הבדיוני המשני של הסאגה).
סכסוכים עסקיים ('409') - מחדש לאחר פיוס או לפצות ולסיים.
7) תזמורת: אחריות ומבנה
פונקציות:- מעקב אחר המצב של הסאגה: ”תלוי ועומד _ ריצה = = פיצוי = עשה/נכשל”.
- תכנון צעדים, מועדים, פסקי זמן, נסיגות.
- ניתוב אירועים ושיגור פיצויים.
- אידמפוטנטיות של פעולות המתאם (רישום פקודות).
- יכולת תצפית: "saga _ id' קורלציה בלוגים/עקבות/מטריצות.
- שולחנות ”סאגה”, ”סאגה _ סטפ”, ”פקודות”, ”אאוטבוקס”.
- אינדקסים על ”saga _ id',” business _ key ”,” status ”,” next _ run _ at'.
8) כוריאוגרפיה: חוקים והגנה מפני ”כדור שלג”
חוזי אירועים: תוכניות וסכימות (Avro/Proto/JSON Schema).
סמנטיקה ברורה: ”עובדה אירוע” נגד ”פקודה”.
עצירת השרשרת: השירות, לאחר שגילה חוסר התאמה, מפרסם אירוע 'נכשל '/' מפצה'.
אזעקות והתראות על ”לולאות אינסופיות”.
9) TCC: פרטים מעשיים
נסה: שמורת משאבים עם TTL.
לאשר: להתחייב, לשחרר מנעולים זמניים.
ביטול: rollback רזרבי (ללא תופעות לוואי).
אוסף אשפה: ביטול אוטומטי של Try after TTL (ביטול אידמפוטנט).
אישור/ביטול אידמפוטנט: חוזר הוא בטוח.
10) דוגמה (תוכנית מילים) - ”סדר עם תשלום ומשלוח”
1. הזמנה מקורית (local) # outbox: ” נוצר”.
2. שירות : 'Try' reserve (TCC); ▪ אם ”השמורים” נכשלו, אם ”הכשל” נכשל.
3. שירות ממציאים: שמורת מוצרים; מתוך ”ממציא נכשל”.
4. שירות - צור חריץ משלוח (ניתן לביטול).
5. אם כל צעד ”נכשל” = התזמור מתחיל פיצויים בסדר ההפוך: ”Sloading Shippling” # ”Abserventory” = ”Discovery Outhory”.
6. אם הכל בסדר ”אישור” ”אושר” ”אושר”.
11) תזמורת פסאודוקודה
pseudo startSaga(saga_id, order_id):
steps = [ReservePayment, ReserveInventory, BookShipment, ConfirmPayment]
for step in steps:
res = execWithRetry(step, order_id)
if!res.ok:
compensateInReverse(steps_done(order_id))
return FAIL return OK
execWithRetry(step, key):
for attempt in 1..MAX:
try:
return step.run(key) # идемпотентно catch RetryableError:
sleep(backoff(attempt))
catch NonRetryableError:
return FAIL return FAIL
compensateInReverse(done_steps):
for step in reverse(done_steps):
step.compensate() # идемпотентно
12) יכולת תצפית ותצפית SLOs
איתור: saga _ id, annotations 'step', 'transit', 'decision' (ריצה/פיצוי/דילוג).
מדדים:- הצלחה/שגיאה של סאגות (%), משך ממוצע, p95/p99.
- הנתח של סאגות מתוגמלות, סיבות ראשונות לפיצוי.
- תורים/דרגות יציאה, מגשים מחדש בצעדים.
- יומנים/ביקורת: פתרונות תזמור, זיהוי משאבים, מפתחות עסקיים.
13) בדיקה ותוהו ובוהו
הזרקת שגיאות לכל שלב: פסקי זמן, '5xx', קונפליקטים עסקיים.
אירועים לא תקינים, שכפולים, טיפות.
זנבות ארוכים של איחור = בדיקת מועדים ופיצויים.
Sagas = בדיקת WFQ/DRR וכובעי תורים, היעדר ”חסימת ראש-קו”.
רדרייב מ-DLQ בצעדים ובסאגה שלמה.
14) עמידות מרובה, אזורים, ציות
תגיות 'דייר _ id/plan/region' באירועים ו-saga repositories.
תושבות: נתונים/אירועים אינם עוזבים את האזור; סאגות צולבות-אזוריות מעוצבות כפדרציות של סאגות מקומיות + מתקבצות.
עדיפות: סאגות VIP נושאות משקל מכסה גדול יותר; בידוד של עובדים לדייר.
15) רשימת בדיקות לפני המכירה
[ ] לכל צעד יש מפצה ברור, שניהם אידיוטים.
[ ] תבנית שנבחרה: תזמור/כוריאוגרפיה/TSS; גבולות האחריות מתוארים.
[ ] Outbox/Inbox מיושם, שכפול על ידי "Operation _ id'.
[ מדיניות ] ריטריי: לסגת עם ג 'יטר, לנסות גבולות וסאגה כוללת המועד האחרון.
[ חוזי האירוע ] מבוססים, יש אימות של המזימה.
[ ] DLQ ושחרור מאובטח מוגדרים.
[ ] טלמטריה: מדדים, איתור, קורלציה "saga _ id'.
[ ] מחזות מבצעיים: ביטול/אישור כוח ידני, פתיחת ”תלוי” סאגות.
[ ] בדיקות כאוס ועומס לעבור, תקציב SLO/שגיאה מוגדר.
16) שגיאות אופייניות
אין מפצה או שהוא ”טמא” (יש לו תופעות לוואי).
אין אידמפוטנטיות/דידאפ - כפילים ו ”נדנדות” של מדינות.
”סאגה בסאגה” ללא גבולות מפורשים - מחזורים ומנעולים משותפים.
אין תאריכי יעד = ”סאגות נצחיות” ודליפות משאבים.
המזכירה מאחסנת את המדינה ”בזיכרון” ללא חנות יציבה.
כוריאוגרפיה ללא מרכז טלמטריה * כשלים ”בלתי נראים”.
Opaque UX: משתמשים לא רואים סטטוסים בינוניים.
17) מתכונים מהירים
קלאסיקות SaaS: תזמור + outbox/inbox, גיבוי אקספוננציאלי, DLQ, סאגה סטטוסים בUI.
משאבים חזקים אינווריאנטים: TCC עם reserve TTL ו-GC ביטול.
כוריאוגרפיית אירועים + אידמפוטנטיות קפדנית ומדדי מפתח.
אזור מרובה: סאגות מקומיות + אגרגטים סופיים; הימנע מנעולים גלובליים.
מסקנה
סאגות הן דרך להשיג עקביות צפויה במערכות מבוזרות ללא מנעולים גלובליים. מפצים ברורים, אידמפוטנציה, משלוח אמין (eutbox/inbox), משמעת זמן ומגש מחדש, בתוספת טלמטריה וספרי משחק הם המפתח להבטיח שתהליכים עסקיים מורכבים יישארו יציבים וקריאים עם עומס הולך וגדל, מספר שירותים וגיאוגרפיות.