वितरित लेनदेन में सागा पैटर्न - गो में उदाहरणों के साथ

माइक्रोसर्विसेज में सागा पैटर्न के साथ लेनदेन

Page content

सागा पैटर्न (https://www.glukhov.org/hi/post/2025/11/saga-transactions-in-microservices/ “वितरित लेनदेन के लिए सागा पैटर्न”) वितरित लेनदेन को एक श्रृंखला के स्थानीय लेनदेन और संतुलन कार्रवाइयों में तोड़कर एक सुंदर समाधान प्रदान करता है।

वितरित लॉक्स पर निर्भर करने के बजाय जो सेवाओं के बीच ऑपरेशन्स को ब्लॉक कर सकते हैं, सागा एक अनुक्रम के उलटने योग्य चरणों के माध्यम से अंतिम सुसंगतता को सक्षम बनाता है, जो लंबे समय तक चलने वाले व्यवसाय प्रक्रियाओं के लिए आदर्श है।

माइक्रोसर्विसेज आर्किटेक्चर में, सेवाओं के बीच डेटा सुसंगतता बनाए रखना सबसे चुनौतीपूर्ण समस्याओं में से एक है। पारंपरिक ACID लेनदेन काम नहीं करते जब ऑपरेशन्स कई सेवाओं के साथ स्वतंत्र डेटाबेसों को स्पैन करते हैं, जिससे डेवलपर्स डेटा अखंडता सुनिश्चित करने के लिए वैकल्पिक दृष्टिकोणों की खोज करते हैं।

इस गाइड में Go में सागा पैटर्न के कार्यान्वयन का प्रदर्शन किया गया है जिसमें प्रैक्टिकल उदाहरण शामिल हैं जो दोनों ऑर्केस्ट्रेशन और कोरियोग्राफी दृष्टिकोणों को कवर करते हैं। अगर आपको Go फंडामेंटल्स के लिए एक तेज़ संदर्भ की आवश्यकता है, तो Go चीतासूची एक उपयोगी अवलोकन प्रदान करती है।

वितरित लेनदेन के साथ निर्माण कार्यकर्ता यह सुंदर छवि AI मॉडल फ्लक्स 1 डेव द्वारा उत्पन्न की गई है।

सागा पैटर्न को समझना

सागा पैटर्न को मूल रूप से 1987 में हेक्टर गार्सिया-मोलिना और केनेथ सैलेम द्वारा वर्णित किया गया था। माइक्रोसर्विसेज के संदर्भ में, यह एक स्थानीय लेनदेन का अनुक्रम है जहां हर लेनदेन एकल सेवा के भीतर डेटा को अपडेट करता है। अगर कोई चरण विफल हो जाता है, तो संतुलन लेनदेन को क्रियान्वित किया जाता है ताकि पिछले चरणों के प्रभावों को उलट दिया जा सके।

पारंपरिक वितरित लेनदेन के विपरीत जो दो-चरण प्रतिबद्धता (2PC) का उपयोग करते हैं, सागा सेवाओं के बीच लॉक्स नहीं रखता, जिससे यह लंबे समय तक चलने वाले व्यवसाय प्रक्रियाओं के लिए उपयुक्त होता है। ट्रेड-ऑफ यह है कि अंतिम सुसंगतता के बजाय मजबूत सुसंगतता।

मुख्य विशेषताएं

  • वितरित लॉक्स नहीं: हर सेवा अपने स्थानीय लेनदेन का प्रबंधन करती है
  • संतुलन कार्रवाइयाँ: हर ऑपरेशन के लिए एक संबंधित रोलबैक मेकेनिज्म होता है
  • अंतिम सुसंगतता: प्रणाली अंततः एक सुसंगत स्थिति तक पहुंचती है
  • लंबे समय तक चलने वाली: सेकंड, मिनट या यहां तक कि घंटों तक चलने वाली प्रक्रियाओं के लिए उपयुक्त

सागा कार्यान्वयन दृष्टिकोण

सागा पैटर्न को लागू करने के दो प्राथमिक दृष्टिकोण हैं: ऑर्केस्ट्रेशन और कोरियोग्राफी।

ऑर्केस्ट्रेशन पैटर्न

ऑर्केस्ट्रेशन में, एक केंद्रीय कोऑर्डिनेटर (ऑर्केस्ट्रेटर) पूरे लेनदेन फ्लो का प्रबंधन करता है। ऑर्केस्ट्रेटर के लिए जिम्मेदारियाँ हैं:

  • सेवाओं को सही क्रम में कॉल करना
  • विफलताओं का प्रबंधन करना और संतुलन ट्रिगर करना
  • सागा की स्थिति बनाए रखना
  • रिट्राइज़ और टाइमआउट्स को समन्वित करना

लाभ:

  • केंद्रीय नियंत्रण और दृश्यता
  • आसान समझ और डिबगिंग
  • बेहतर त्रुटि हैंडलिंग और रिकवरी
  • समग्र फ्लो का सरल परीक्षण

हानियाँ:

  • एकल विफलता बिंदु (हालांकि इसे कम किया जा सकता है)
  • अतिरिक्त सेवा का रखरखाव करना
  • जटिल फ्लो के लिए बोटलनेक बन सकता है

Go में उदाहरण:

type OrderSagaOrchestrator struct {
    orderService    OrderService
    paymentService  PaymentService
    inventoryService InventoryService
    shippingService ShippingService
}

func (o *OrderSagaOrchestrator) CreateOrder(order Order) error {
    sagaID := generateSagaID()

    // चरण 1: ऑर्डर बनाना
    orderID, err := o.orderService.Create(order)
    if err != nil {
        return err
    }

    // चरण 2: इन्वेंटरी रिजर्व करना
    if err := o.inventoryService.Reserve(order.Items); err != nil {
        o.orderService.Cancel(orderID) // संतुलन
        return err
    }

    // चरण 3: भुगतान प्रोसेस करना
    paymentID, err := o.paymentService.Charge(order.CustomerID, order.Total)
    if err != nil {
        o.inventoryService.Release(order.Items) // संतुलन
        o.orderService.Cancel(orderID)          // संतुलन
        return err
    }

    // चरण 4: शिपमेंट बनाना
    if err := o.shippingService.CreateShipment(orderID); err != nil {
        o.paymentService.Refund(paymentID)      // संतुलन
        o.inventoryService.Release(order.Items) // संतुलन
        o.orderService.Cancel(orderID)          // संतुलन
        return err
    }

    return nil
}

कोरियोग्राफी पैटर्न

कोरियोग्राफी में कोई केंद्रीय कोऑर्डिनेटर नहीं होता। हर सेवा जानती है कि क्या करना है और घटनाओं के माध्यम से संचार करती है। सेवाएं घटनाओं की सुनती हैं और संबंधित रूप से प्रतिक्रिया करती हैं। यह घटना-चालित दृष्टिकोण विशेष रूप से AWS Kinesis जैसे संदेश स्ट्रीमिंग प्लेटफॉर्म के साथ मिलकर शक्तिशाली होता है, जो माइक्रोसर्विसेज के बीच घटना वितरण के लिए स्केलेबल इन्फ्रास्ट्रक्चर प्रदान करते हैं। AWS Kinesis का उपयोग करके घटना-चालित माइक्रोसर्विसेज को लागू करने के लिए एक व्यापक गाइड के लिए देखें AWS Kinesis के साथ घटना-चालित माइक्रोसर्विसेज बनाना

लाभ:

  • विकेंद्रीकृत और स्केलेबल
  • कोई एकल विफलता बिंदु नहीं
  • सेवाएं ढीली रूप से जुड़ी रहती हैं
  • घटना-चालित आर्किटेक्चर के लिए प्राकृतिक फिट

हानियाँ:

  • समग्र फ्लो को समझना कठिन
  • डिबगिंग और ट्रेसिंग कठिन
  • जटिल त्रुटि हैंडलिंग
  • चक्रीय निर्भरताओं का जोखिम

घटना-चालित आर्किटेक्चर के साथ उदाहरण:

// ऑर्डर सेवा
type OrderService struct {
    eventBus EventBus
    repo     OrderRepository
}

func (s *OrderService) CreateOrder(order Order) (string, error) {
    orderID, err := s.repo.Save(order)
    if err != nil {
        return "", err
    }

    s.eventBus.Publish("OrderCreated", OrderCreatedEvent{
        OrderID:    orderID,
        CustomerID: order.CustomerID,
        Items:      order.Items,
        Total:      order.Total,
    })

    return orderID, nil
}

func (s *OrderService) HandlePaymentFailed(event PaymentFailedEvent) error {
    return s.repo.Cancel(event.OrderID) // संतुलन
}

// भुगतान सेवा
type PaymentService struct {
    eventBus EventBus
    client   PaymentClient
}

func (s *PaymentService) HandleOrderCreated(event OrderCreatedEvent) {
    paymentID, err := s.client.Charge(event.CustomerID, event.Total)
    if err != nil {
        s.eventBus.Publish("PaymentFailed", PaymentFailedEvent{
            OrderID: event.OrderID,
        })
        return
    }

    s.eventBus.Publish("PaymentSucceeded", PaymentSucceededEvent{
        OrderID:   event.OrderID,
        PaymentID: paymentID,
    })
}

func (s *PaymentService) HandleInventoryReservationFailed(event InventoryReservationFailedEvent) error {
    // संतुलन: भुगतान वापस करना
    return s.client.Refund(event.PaymentID)
}

संतुलन रणनीतियाँ

संतुलन सागा पैटर्न का हृदय है। हर ऑपरेशन के लिए एक संबंधित संतुलन होना चाहिए जो उसके प्रभावों को उलट सकता है।

संतुलन के प्रकार

  1. उलटने योग्य ऑपरेशन्स: ऑपरेशन्स जो सीधे उलटे जा सकते हैं

    • उदाहरण: रिजर्व की गई इन्वेंटरी रिलीज़ करना, भुगतान वापस करना
  2. संतुलन कार्रवाइयाँ: अलग ऑपरेशन्स जो उलट प्रभाव प्राप्त करते हैं

    • उदाहरण: ऑर्डर रद्द करना इसके बजाय हटाना
  3. नकारात्मक संतुलन: संसाधनों को प्री-एलोकेट करना जो रिलीज़ किए जा सकते हैं

    • उदाहरण: भुगतान चार्ज करने से पहले इन्वेंटरी रिजर्व करना
  4. आशावादी संतुलन: ऑपरेशन्स को क्रियान्वित करना और आवश्यकता पड़ने पर संतुलन करना

    • उदाहरण: पहले भुगतान चार्ज करना, अगर इन्वेंटरी अनुपलब्ध है तो वापस करना

आइडेम्पोटेंसी आवश्यकताएँ

सभी ऑपरेशन्स और संतुलन आइडेम्पोटेंट होने चाहिए। यह सुनिश्चित करता है कि एक विफल ऑपरेशन को रिट्राई करने से डुप्लिकेट प्रभाव नहीं होते।

func (s *PaymentService) Refund(paymentID string) error {
    // चेक करें कि क्या पहले से वापस किया गया है
    payment, err := s.getPayment(paymentID)
    if err != nil {
        return err
    }

    if payment.Status == "refunded" {
        return nil // पहले से वापस किया गया है, आइडेम्पोटेंट
    }

    // वापसी प्रोसेस करना
    return s.processRefund(paymentID)
}

सर्वोत्तम प्रथाएँ

1. सागा स्टेट मैनेजमेंट

प्रत्येक सागा इंस्टेंस की स्टेट को ट्रैक करने के लिए रखें ताकि प्रगति का पता चल सके और रिकवरी संभव हो। जब सागा स्टेट को डेटाबेस में पर्सिस्ट करते हैं, तो प्रदर्शन और मेन्टेनेंस के लिए सही ORM का चयन करना महत्वपूर्ण है। PostgreSQL-आधारित इम्प्लीमेंटेशन के लिए, Comparing Go ORMs for PostgreSQL: GORM vs Ent vs Bun vs sqlc में तुलना देखें ताकि आपकी सागा स्टेट स्टोरेज की आवश्यकताओं के लिए सबसे अच्छा फिट चुन सकें:

type SagaState struct {
    ID           string
    Status       SagaStatus
    Steps        []SagaStep
    CurrentStep  int
    CreatedAt    time.Time
    UpdatedAt    time.Time
}

type SagaStep struct {
    Service     string
    Operation   string
    Status      StepStatus
    Compensated bool
    Data        map[string]interface{}
}

2. टाइमआउट हैंडलिंग

प्रत्येक स्टेप के लिए टाइमआउट लागू करें ताकि सागा अनिश्चित काल तक लटका न रहे:

type SagaOrchestrator struct {
    timeout time.Duration
}

func (o *SagaOrchestrator) ExecuteWithTimeout(step SagaStep) error {
    ctx, cancel := context.WithTimeout(context.Background(), o.timeout)
    defer cancel()

    done := make(chan error, 1)
    go func() {
        done <- step.Execute()
    }()

    select {
    case err := <-done:
        return err
    case <-ctx.Done():
        // Timeout occurred, compensate
        if err := step.Compensate(); err != nil {
            return fmt.Errorf("compensation failed: %w", err)
        }
        return fmt.Errorf("step %s timed out after %v", step.Name(), o.timeout)
    }
}

3. रिट्राई लॉजिक

अस्थायी विफलताओं के लिए एक्सपोनेंशियल बैकोफ लागू करें:

func retryWithBackoff(operation func() error, maxRetries int) error {
    backoff := time.Second
    for i := 0; i < maxRetries; i++ {
        err := operation()
        if err == nil {
            return nil
        }

        if !isTransientError(err) {
            return err
        }

        time.Sleep(backoff)
        backoff *= 2
    }
    return fmt.Errorf("operation failed after %d retries", maxRetries)
}

4. सागा स्टेट के लिए इवेंट सोर्सिंग

एक पूर्ण ऑडिट ट्रेल बनाए रखने के लिए इवेंट सोर्सिंग का उपयोग करें। जब इवेंट स्टोर्स और रिप्ले मेकेनिज्म लागू करते हैं, तो Go generics मदद कर सकते हैं टाइप-सेफ, रीयूज़ेबल इवेंट हैंडलिंग कोड बनाने में। Go generics के लिए उन्नत पैटर्न्स देखें Go Generics: Use Cases and Patterns:

type SagaEvent struct {
    SagaID    string
    EventType string
    Payload   []byte
    Timestamp time.Time
    Version   int64
}

type SagaEventStore struct {
    store EventRepository
}

func (s *SagaEventStore) AppendEvent(sagaID string, eventType string, payload interface{}) error {
    data, err := json.Marshal(payload)
    if err != nil {
        return fmt.Errorf("failed to marshal payload: %w", err)
    }

    version, err := s.store.GetNextVersion(sagaID)
    if err != nil {
        return fmt.Errorf("failed to get version: %w", err)
    }

    event := SagaEvent{
        SagaID:    sagaID,
        EventType: eventType,
        Payload:   data,
        Timestamp: time.Now(),
        Version:   version,
    }

    return s.store.Save(event)
}

func (s *SagaEventStore) ReplaySaga(sagaID string) (*Saga, error) {
    events, err := s.store.GetEvents(sagaID)
    if err != nil {
        return nil, fmt.Errorf("failed to get events: %w", err)
    }

    saga := NewSaga()
    for _, event := range events {
        if err := saga.Apply(event); err != nil {
            return nil, fmt.Errorf("failed to apply event: %w", err)
        }
    }

    return saga, nil
}

5. मॉनिटरिंग और ऑब्जर्वेबिलिटी

विस्तृत लॉगिंग और ट्रेसिंग लागू करें:

func (o *OrderSagaOrchestrator) CreateOrder(order Order) error {
    span := tracer.StartSpan("saga.create_order")
    defer span.Finish()

    span.SetTag("saga.id", sagaID)
    span.SetTag("order.id", order.ID)

    logger.WithFields(log.Fields{
        "saga_id": sagaID,
        "order_id": order.ID,
        "step": "create_order",
    }).Info("Saga started")

    // ... saga execution

    return nil
}

सामान्य पैटर्न और एंटी-पैटर्न

अनुसरण करने वाले पैटर्न

  • सागा कोऑर्डिनेटर पैटर्न: ऑर्केस्ट्रेशन के लिए एक समर्पित सेवा का उपयोग करें
  • आउटबॉक्स पैटर्न: विश्वसनीय इवेंट पब्लिशिंग सुनिश्चित करें
  • आइडेम्पोटेंसी कीज़: सभी ऑपरेशन्स के लिए अनूठे कीज़ का उपयोग करें
  • सागा स्टेट मशीन: सागा को स्टेट मशीन के रूप में मॉडल करें

टालने वाले एंटी-पैटर्न

  • सिंक्रोनस कंपेंसेशन: कंपेंसेशन के पूरा होने का इंतजार न करें
  • नेस्टेड सागा: सागा को अन्य सागा को कॉल करने से बचें (सब-सागा का उपयोग करें)
  • शेयर्ड स्टेट: सागा स्टेप्स के बीच स्टेट शेयर न करें
  • लॉन्ग-रनिंग स्टेप्स: बहुत लंबे समय लेने वाले स्टेप्स को तोड़ें

टूल्स और फ्रेमवर्क

कई फ्रेमवर्क सागा पैटर्न लागू करने में मदद कर सकते हैं:

  • टेम्पोरल: बिल्ट-इन सागा सपोर्ट के साथ वर्कफ्लो ऑर्केस्ट्रेशन प्लेटफॉर्म
  • ज़ीब: माइक्रोसर्विसेज ऑर्केस्ट्रेशन के लिए वर्कफ्लो इंजन
  • इवेंटुएट ट्राम: स्प्रिंग बूट के लिए सागा फ्रेमवर्क
  • AWS स्टेप फंक्शन्स: सर्वरलेस वर्कफ्लो ऑर्केस्ट्रेशन
  • एपाचे कैमल: सागा सपोर्ट के साथ इंटीग्रेशन फ्रेमवर्क

सागा ऑर्केस्ट्रेटर्स के लिए जो प्रबंधन और मॉनिटरिंग के लिए CLI इंटरफेस की आवश्यकता होती है, Building CLI Applications in Go with Cobra & Viper सागा ऑर्केस्ट्रेटर्स के साथ इंटरैक्ट करने के लिए कमांड-लाइन टूल्स बनाने के लिए उत्कृष्ट पैटर्न प्रदान करता है।

कubernetes में सागा-आधारित माइक्रोसर्विसेज डिप्लॉय करने के दौरान, एक सर्विस मेश लागू करना मॉनिटरिंग, सुरक्षा, और ट्रैफिक प्रबंधन में महत्वपूर्ण सुधार कर सकता है। Implementing Service Mesh with Istio and Linkerd कवर करता है कि सर्विस मेश कैसे वितरित ट्रांजैक्शन पैटर्न्स को पूरक होते हैं क्रॉस-कटिंग कंसेप्ट्स जैसे डिस्ट्रीब्यूटेड ट्रेसिंग और सर्किट ब्रेकिंग प्रदान करके।

सागा पैटर्न का उपयोग कब करें

सागा पैटर्न का उपयोग करें जब:

  • ✅ ऑपरेशन्स कई माइक्रोसर्विसेज को स्पैन करते हैं
  • ✅ लंबे समय तक चलने वाले बिजनेस प्रक्रियाएं
  • ✅ इवेंटुअल कन्सिस्टेंसी स्वीकार्य है
  • ✅ वितरित लॉक्स से बचना चाहिए
  • ✅ सर्विसेज के पास स्वतंत्र डेटाबेस हैं

टालें जब:

  • ❌ मजबूत कन्सिस्टेंसी की आवश्यकता है
  • ❌ ऑपरेशन्स सरल और तेज़ हैं
  • ❌ सभी सर्विसेज एक ही डेटाबेस शेयर करते हैं
  • ❌ कंपेंसेशन लॉजिक बहुत जटिल है

निष्कर्ष

सागा पैटर्न माइक्रोसर्विसेज आर्किटेक्चर में वितरित ट्रांजैक्शन प्रबंधन के लिए आवश्यक है। जबकि यह जटिलता पेश करता है, यह सर्विस बाउंडरीज के पार डेटा कन्सिस्टेंसी बनाए रखने के लिए एक व्यावहारिक समाधान प्रदान करता है। बेहतर नियंत्रण और विज़िबिलिटी के लिए ऑर्केस्ट्रेशन चुनें, या स्केलेबिलिटी और लूज़ कपलिंग के लिए कोरियोग्राफी। हमेशा ऑपरेशन्स को आइडेम्पोटेंट बनाएं, उचित कंपेंसेशन लॉजिक लागू करें, और व्यापक ऑब्जर्वेबिलिटी बनाए रखें।

सफल सागा इम्प्लीमेंटेशन की कुंजी आपकी कन्सिस्टेंसी आवश्यकताओं को समझना, सावधानीपूर्वक कंपेंसेशन लॉजिक डिजाइन करना, और अपने उपयोग के मामले के लिए सही दृष्टिकोण चुनना है। उचित इम्प्लीमेंटेशन के साथ, सागा आपको वितरित सिस्टम के पार डेटा इंटीग्रिटी बनाए रखने वाले लचीले, स्केलेबल माइक्रोसर्विसेज बनाने में सक्षम बनाता है।

उपयोगी लिंक्स