יישום תבנית סאגה לעסקאות מבוזרות

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

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

יישום תבנית Saga לעסקאות מבוזרות

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

Saga היא דרך לנהל את המורכבות הזו. זוהי רצף של עסקאות מקומיות, שכל אחת מהן מפרסמת אירוע לשלב הבא. במקרה של שגיאה, עסקאות מפצות מבטלות שלבים שכבר הושלמו. מרטין פאולר מתאר את Saga כתבנית אמינה לשמירה על עקביות במיקרוסרוויסים. התשתית חייבת להיות בנויה כראוי; אחרת, Saga הופכת למקור לבאגים שקשה לתפוס עם אירועים שאבדו ומצב לא עקבי. העלות הממוצעת של השבתה במהלך כשל Saga היא 10,000 דולר לשעה, כך שיישום איכותי משתלם במהירות.

כיצד פועלת תבנית Saga?

Saga אינה פתרון קסם. ללא תשתית מתאימה, עסקאות מבוזרות הופכות ל"סיוטים מבוזרים". בפועל, כ-30% מה-Sagas מסתיימות בפיצוי, ו-latency של אחוזון 99 בשרשרת יכול להגיע ל-2.5 שניות. לאחר אופטימיזציה של התשתית, ה-latency יורד ל-0.8 שניות, ומספר הפיצויים ל-8%.

כוריאוגרפיה מול אורקסטרציה: הבחירה משפיעה על התשתית

  • כוריאוגרפיה: כל שירות מפרסם אירועים ומגיב אליהם. אין מתאם מרכזי.
  • אורקסטרציה: מתאם Saga מרכזי מנהל את התהליך, וקורא לכל שירות ישירות דרך HTTP/gRPC.

לכוריאוגרפיה, יש צורך בתיווך הודעות אמין עם הבטחת מסירה. לאורקסטרציה, יש צורך במצב מתמשך (מסד נתונים או Redis). בפועל, קל יותר לנפות באגים ולנטר אורקסטרציה — כל גרף הביצוע נראה לעין. Temporal מהירה פי 3 מ-Kafka בעת ניפוי באגים בתרחישי שחזור מכשל.

פרמטר כוריאוגרפיה אורקסטרציה
מורכבות תשתית נמוכה (רק broker) בינונית (broker + אחסון מצב)
ניפוי באגים קשה (לוגים מפוזרים) קל (זרימת עבודה אחת)
ניטור מדדים לכל שלב מעקב מלא
אידמפוטנטיות קריטית בכל מקום מובנית חלקית

Kafka כתחבורה לכוריאוגרפיה של Saga

Kafka עם acks=all ו-min.insync.replicas=2 מבטיחה: הודעה לא תיאבד לאחר אישור. תצורת topic טיפוסית:

תצורת KafkaTopic
---
apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaTopic
metadata:
  name: order-saga-events
spec:
  partitions: 12
  replicas: 3
  config:
    retention.ms: "604800000"
    min.insync.replicas: "2"
    cleanup.policy: compact

היצרן חייב לכלול apiVersion: kafka.strimzi.io/v1beta2 kind: KafkaTopic metadata: name: order-saga-events spec: partitions: 12 replicas: 3 config: retention.ms: "604800000" min.insync.replicas: "2" cleanup.policy: compact — Kafka מבטיחה כתיבה בדיוק פעם אחת בניסיון חוזר. זה קריטי עבור Saga, שבה אירועים כפולים מובילים לביצוע חוזר של שלבים.

כיצד ליישם אידמפוטנטיות של handler?

Kafka ב-at-least-once פירושו: אירוע עשוי להגיע פעמיים. כל handler ב-Saga חייב להיות אידמפוטנטי — ביצוע חוזר עם אותו מזהה אירוע לא משנה את המצב. תבנית: בדוק אם האירוע כבר עובד → בצע עסקה מקומית → פרסם את האירוע הבא.

async def handle_order_created(event: OrderCreatedEvent):
    if await redis.get(f"processed:payment:{event.saga_id}"):
        logger.info(f"Event {event.saga_id} already processed")
        return
    async with db.transaction():
        payment = await payment_service.charge(
            customer_id=event.customer_id,
            amount=event.total_amount,
            idempotency_key=event.saga_id
        )
        await db.execute(
            "INSERT INTO saga_steps (saga_id, step, status) VALUES ($1, $2, $3)",
            event.saga_id, "payment", "completed"
        )
        await redis.setex(f"processed:payment:{event.saga_id}", 86400, "1")
        await kafka_producer.produce("payment.completed", PaymentCompletedEvent(...))

אם שלב N נכשל, יש לבטל את השלבים 1..N-1. עסקאות מפצות חייבות להיות גם אידמפוטנטיות — השתמש ב-enable.idempotence=True עם קידומת refund-.

מדוע אורקסטרציה עדיפה?

Temporal היא מנוע זרימת עבודה עם מצב מתמשך, ניסיון חוזר אוטומטי, והיסטוריה מלאה של כל ביצוע. כאשר עובד קורס, התהליך מתחדש מנקודת העצירה. תשתית: Temporal Server (Docker או Kubernetes), PostgreSQL להתמדה.

@workflow.defn
class OrderSagaWorkflow:
    @workflow.run
    async def run(self, order: OrderRequest) -> OrderResult:
        try:
            payment = await workflow.execute_activity(
                process_payment,
                order.payment_details,
                start_to_close_timeout=timedelta(seconds=30))
        except ActivityError:
            raise
        try:
            reservation = await workflow.execute_activity(
                reserve_inventory,
                order.items,
                start_to_close_timeout=timedelta(seconds=30))
        except ActivityError:
            await workflow.execute_activity(refund_payment, payment.payment_id)
            raise
        try:
            shipment = await workflow.execute_activity(
                create_shipment,
                order,
                start_to_close_timeout=timedelta(seconds=60))
        except ActivityError:
            await workflow.execute_activity(cancel_reservation, reservation.id)
            await workflow.execute_activity(refund_payment, payment.payment_id)
            raise
        return OrderResult(order_id=order.id, payment_id=payment.payment_id, shipment_id=shipment.id)

ניטור Saga: מה לעקוב

מדד משמעות
שיעור השלמת Saga אחוז ה-Sagas שהושלמו בהצלחה
שיעור פיצויים באיזו תדירות מופעלים פיצויים
Latency של שלב p99 היכן נמצא הצוואר בקבוק בשרשרת
גודל תור הודעות מתות כמה אירועים לא ניתן היה לעבד
מספר Sagas פעילים כמה Sagas מבוצעות כעת

DLQ (תור הודעות מתות) הוא קריטי. אירועים שלא עובדו לאחר 3 ניסיונות חוזרים עוברים ל-DLQ. יש לטפל בהם אוטומטית או ידנית.

כיצד ליישם את תבנית Saga: מדריך שלב אחר שלב

  1. ביקורת ארכיטקטורה: זהה נקודות כשל במיקרוסרוויסים הנוכחיים.
  2. עיצוב Saga: תאר שלבים, פיצויים, סכמת אירועים.
  3. פריסת תשתית: הגדר אשכול Kafka/Temporal, topics, התמדה.
  4. יישום handler: יישם אידמפוטנטיות, עסקאות מפצות, DLQ.
  5. ניטור והתראות: הגדר לוחות מחוונים של Prometheus/Grafana, התראות על פיצויים ו-DLQ.

מה כלול בעבודה שלנו

  • ביקורת ארכיטקטורה: ניתוח מיקרוסרוויסים נוכחיים ונקודות כשל.
  • עיצוב Saga: הגדרת שלבים, פיצויים, סכמת אירועים.
  • פריסת תשתית: אשכול Kafka/Temporal, תצורת topic, הגדרת התמדה.
  • יישום handler: אידמפוטנטיות, עסקאות מפצות, DLQ.
  • ניטור והתראות: לוחות מחוונים של Prometheus/Grafana, התראות על פיצויים ו-DLQ.
  • תיעוד והדרכה: runbook, תבניות postmortem, הדרכת צוות.

תהליך היישום

שלב משך
עיצוב: שלבי saga, פיצויים, סכמת אירועים יום אחד
תשתית: הגדרת Kafka/Temporal יום אחד
יישום handler עם אידמפוטנטיות 1.5 ימים
DLQ + ניטור + התראות 0.5 יום
בדיקת תרחישי כשל יום אחד

העלות מחושבת באופן אישי לאחר ביקורת ארכיטקטורת מיקרוסרוויסים. צור קשר להערכה של הפרויקט שלך.

הזמן יישום Saga במפתח — קבל מערכת מבוזרת יציבה.