MICROSERVICES DISTRIBUTED-SYSTEMS ARCHITECTURE DESIGN-PATTERNS DATA-CONSISTENCY TRANSACTIONS EVENT-DRIVEN ASYNCHRONOUS BACKEND RELIABILITY FAULT-TOLERANCE MESSAGE-QUEUE

Menjaga Konsistensi Data di Dunia Mikro: Memahami Saga Pattern untuk Transaksi Terdistribusi

⏱️ 12 menit baca
👨‍💻

Menjaga Konsistensi Data di Dunia Mikro: Memahami Saga Pattern untuk Transaksi Terdistribusi

1. Pendahuluan

Di dunia monolit, menjaga konsistensi data dalam transaksi yang melibatkan beberapa tabel atau bagian sistem adalah hal yang relatif mudah. Kita punya ACID transactions (Atomicity, Consistency, Isolation, Durability) yang bisa langsung diandalkan. Cukup bungkus operasi dalam satu transaksi database, dan jika ada yang gagal, semua akan di-rollback. Sederhana!

Namun, begitu kita masuk ke arsitektur microservices, cerita berubah drastis. Setiap layanan memiliki database-nya sendiri yang terisolasi. Bagaimana jika satu operasi bisnis memerlukan pembaruan data di tiga layanan yang berbeda? Misalnya, “Pemesanan Produk” yang melibatkan layanan Order, Payment, dan Inventory. Kita tidak bisa lagi melakukan transaksi ACID lintas database yang terpisah ini. Jika pembayaran berhasil tapi stok tidak tersedia, apa yang terjadi? Data menjadi tidak konsisten! 🤯

Di sinilah tantangan besar muncul: bagaimana menjaga konsistensi data di sistem terdistribusi? Kita tidak bisa lagi mengandalkan transaksi database tradisional.

Artikel ini akan membawa Anda menyelami Saga Pattern, sebuah pola desain arsitektur yang kuat untuk mengatasi masalah transaksi terdistribusi ini. Saga memungkinkan kita membangun alur kerja yang melibatkan banyak layanan, memastikan bahwa meskipun ada kegagalan di tengah jalan, sistem dapat kembali ke keadaan yang konsisten melalui serangkaian transaksi kompensasi.

Siap untuk menaklukkan konsistensi data di dunia mikro? Mari kita mulai!

2. Apa Itu Saga Pattern?

📌 Saga Pattern adalah pola manajemen transaksi terdistribusi yang mengelola urutan transaksi lokal. Setiap transaksi lokal memperbarui database-nya sendiri dan mempublikasikan event atau memicu transaksi lokal berikutnya. Jika transaksi lokal gagal, Saga akan mengeksekusi serangkaian transaksi kompensasi untuk membatalkan perubahan yang telah dilakukan oleh transaksi lokal sebelumnya.

Analogi paling mudah untuk memahami Saga adalah proses pemesanan perjalanan. Bayangkan Anda memesan paket liburan yang mencakup:

  1. Pemesanan tiket pesawat ✈️
  2. Pemesanan kamar hotel 🏨
  3. Penyewaan mobil 🚗

Setiap langkah ini adalah “transaksi lokal” yang independen dan dikelola oleh penyedia layanan yang berbeda (maskapai, hotel, rental mobil).

Saga Pattern bekerja persis seperti ini:

Tujuan utama Saga adalah mencapai konsistensi data eventual di seluruh sistem terdistribusi. Artinya, mungkin ada periode singkat di mana sistem tidak sepenuhnya konsisten, tetapi pada akhirnya, semua data akan konsisten (baik itu berhasil diselesaikan atau dikompensasi sepenuhnya).

3. Dua Pendekatan Implementasi Saga

Ada dua cara utama untuk mengimplementasikan Saga Pattern: Choreography dan Orchestration. Keduanya memiliki kelebihan dan kekurangan masing-masing.

A. Choreography-based Saga (Saga Berbasis Koreografi)

Dalam pendekatan Choreography, setiap layanan berpartisipasi dalam Saga secara mandiri. Tidak ada “pusat kendali” atau orkestrator. Sebaliknya, setiap layanan mempublikasikan event setelah menyelesaikan transaksi lokalnya, dan layanan lain yang tertarik akan mendengarkan event tersebut untuk memicu transaksi lokal berikutnya.

💡 Prinsip: Layanan bereaksi terhadap event yang dipublikasikan oleh layanan lain.

Mari kita ambil contoh proses “Pemesanan Produk” (Order -> Payment -> Inventory -> Shipping):

  1. Layanan Order menerima permintaan CreateOrder.
    • Ia membuat entri Order di database-nya (status PENDING).
    • Memublikasikan event OrderCreated ke message broker.
  2. Layanan Payment mendengarkan event OrderCreated.
    • Ia mencoba memproses pembayaran untuk order tersebut.
    • Jika berhasil, memublikasikan event PaymentProcessed.
    • Jika gagal, memublikasikan event PaymentFailed.
  3. Layanan Inventory mendengarkan event PaymentProcessed.
    • Ia mencoba mengurangi stok produk.
    • Jika berhasil, memublikasikan event InventoryUpdated.
    • Jika gagal (misal, stok habis), memublikasikan event InventoryUpdateFailed.
  4. Layanan Shipping mendengarkan event InventoryUpdated.
    • Ia membuat jadwal pengiriman.
    • Memublikasikan event ShippingScheduled.
  5. Layanan Order mendengarkan ShippingScheduled dan memperbarui status order menjadi COMPLETED.

Bagaimana jika ada kegagalan?

sequenceDiagram
    participant Client
    participant OrderService
    participant PaymentService
    participant InventoryService
    participant ShippingService
    participant MessageBroker

    Client->>OrderService: Create Order
    OrderService->>OrderService: Create Local Order (PENDING)
    OrderService->>MessageBroker: Publish OrderCreated Event
    MessageBroker-->>PaymentService: OrderCreated Event
    PaymentService->>PaymentService: Process Payment
    alt Payment Succeeded
        PaymentService->>MessageBroker: Publish PaymentProcessed Event
        MessageBroker-->>InventoryService: PaymentProcessed Event
        InventoryService->>InventoryService: Update Local Inventory
        alt Inventory Succeeded
            InventoryService->>MessageBroker: Publish InventoryUpdated Event
            MessageBroker-->>ShippingService: InventoryUpdated Event
            ShippingService->>ShippingService: Schedule Shipping
            ShippingService->>MessageBroker: Publish ShippingScheduled Event
            MessageBroker-->>OrderService: ShippingScheduled Event
            OrderService->>OrderService: Update Order (COMPLETED)
        else Inventory Failed
            InventoryService->>MessageBroker: Publish InventoryUpdateFailed Event
            MessageBroker-->>PaymentService: InventoryUpdateFailed Event
            PaymentService->>PaymentService: Refund Payment (Compensation)
            PaymentService->>MessageBroker: Publish PaymentRefunded Event
            MessageBroker-->>OrderService: PaymentRefunded Event
            OrderService->>OrderService: Update Order (CANCELLED)
        end
    else Payment Failed
        PaymentService->>MessageBroker: Publish PaymentFailed Event
        MessageBroker-->>OrderService: PaymentFailed Event
        OrderService->>OrderService: Update Order (CANCELLED)
    end

Kelebihan Choreography:

Kekurangan Choreography:

B. Orchestration-based Saga (Saga Berbasis Orkestrasi)

Dalam pendekatan Orchestration, ada satu layanan khusus yang disebut Saga Orchestrator yang bertanggung jawab untuk mengelola dan mengarahkan seluruh alur Saga. Orchestrator ini tahu urutan transaksi lokal yang harus dipanggil dan transaksi kompensasi yang harus dijalankan jika terjadi kegagalan.

🎯 Prinsip: Orchestrator adalah “otak” yang memberi tahu setiap layanan apa yang harus dilakukan.

Kembali ke contoh “Pemesanan Produk”:

  1. Layanan Order menerima permintaan CreateOrder.
    • Ia membuat entri Order di database-nya (status PENDING).
    • Mengirimkan perintah CreateOrderSaga ke Saga Orchestrator.
  2. Saga Orchestrator menerima perintah CreateOrderSaga.
    • Ia menyimpan status Saga.
    • Mengirimkan perintah ProcessPayment ke Layanan Payment.
  3. Layanan Payment memproses pembayaran.
    • Mengirimkan respons PaymentProcessed atau PaymentFailed kembali ke Orchestrator.
  4. Jika PaymentProcessed:
    • Orchestrator mengirimkan perintah UpdateInventory ke Layanan Inventory.
  5. Layanan Inventory memperbarui stok.
    • Mengirimkan respons InventoryUpdated atau InventoryUpdateFailed kembali ke Orchestrator.
  6. Jika InventoryUpdated:
    • Orchestrator mengirimkan perintah ScheduleShipping ke Layanan Shipping.
  7. Layanan Shipping membuat jadwal.
    • Mengirimkan respons ShippingScheduled kembali ke Orchestrator.
  8. Jika ShippingScheduled:
    • Orchestrator mengirimkan perintah CompleteOrder ke Layanan Order.
    • Layanan Order memperbarui status menjadi COMPLETED.
    • Orchestrator menandai Saga selesai.

Bagaimana jika ada kegagalan?

sequenceDiagram
    participant Client
    participant OrderService
    participant SagaOrchestrator
    participant PaymentService
    participant InventoryService
    participant ShippingService

    Client->>OrderService: Create Order
    OrderService->>OrderService: Create Local Order (PENDING)
    OrderService->>SagaOrchestrator: Start Saga: CreateOrderSaga(orderId, userId, items)

    SagaOrchestrator->>PaymentService: Command: ProcessPayment(orderId, amount)
    PaymentService-->>SagaOrchestrator: Reply: PaymentProcessed(orderId)

    SagaOrchestrator->>InventoryService: Command: UpdateInventory(orderId, items)
    alt Inventory Succeeded
        InventoryService-->>SagaOrchestrator: Reply: InventoryUpdated(orderId)

        SagaOrchestrator->>ShippingService: Command: ScheduleShipping(orderId, address)
        ShippingService-->>SagaOrchestrator: Reply: ShippingScheduled(orderId)

        SagaOrchestrator->>OrderService: Command: CompleteOrder(orderId)
        OrderService-->>SagaOrchestrator: Reply: OrderCompleted(orderId)
        SagaOrchestrator->>SagaOrchestrator: Mark Saga as COMPLETED
    else Inventory Failed
        InventoryService-->>SagaOrchestrator: Reply: InventoryUpdateFailed(orderId, reason)

        SagaOrchestrator->>PaymentService: Command: RefundPayment(orderId) (Compensation)
        PaymentService-->>SagaOrchestrator: Reply: PaymentRefunded(orderId)

        SagaOrchestrator->>OrderService: Command: CancelOrder(orderId)
        OrderService-->>SagaOrchestrator: Reply: OrderCancelled(orderId)
        SagaOrchestrator->>SagaOrchestrator: Mark Saga as FAILED
    end

Kelebihan Orchestration:

Kekurangan Orchestration:

4. Memilih Antara Choreography dan Orchestration

Memilih pendekatan yang tepat sangat tergantung pada kompleksitas dan kebutuhan spesifik sistem Anda:

Secara umum, untuk Saga yang lebih kompleks dan penting, Orchestration-based Saga seringkali menjadi pilihan yang lebih baik karena kemudahan pengelolaan dan pemeliharaan jangka panjang.

5. Tantangan dan Pertimbangan Praktis

Meskipun Saga Pattern adalah solusi ampuh, ada beberapa tantangan yang perlu Anda perhatikan:

  1. Idempotency (Idempoten):

    • Transaksi kompensasi dan bahkan transaksi lokal mungkin dipanggil lebih dari sekali (misal, karena retry atau duplikasi event). Pastikan setiap operasi bersifat idempoten, artinya menjalankannya berkali-kali memberikan hasil yang sama dengan menjalankannya sekali.
    • Contoh: Refund pembayaran harus bisa dipanggil berkali-kali tanpa menggandakan pengembalian dana.
  2. Observability (Keteramatan):

    • Melacak perjalanan Saga yang melibatkan banyak layanan bisa sangat menantang. Anda memerlukan distributed tracing (misalnya dengan OpenTelemetry) untuk melihat seluruh alur Saga, dari awal hingga akhir, termasuk transaksi kompensasi.
    • Logging yang efektif dan metrik yang jelas di setiap langkah Saga juga krusial.
  3. Penanganan Kegagalan Kompensasi:

    • Bagaimana jika transaksi kompensasi itu sendiri gagal? Ini adalah skenario langka tapi mungkin. Anda perlu strategi untuk menanganinya, seperti retry dengan backoff, alerting manual, atau bahkan intervensi operator.
    • ⚠️ Never-ending Saga: Hindari kondisi di mana Saga tidak bisa selesai atau dikompensasi.
  4. Versiing Saga:

    • Seiring waktu, alur bisnis Anda mungkin berubah. Bagaimana Anda mengelola perubahan pada alur Saga yang sedang berjalan? Pertimbangkan strategi versiing untuk Saga Orchestrator atau event yang digunakan dalam Choreography.
  5. Teknologi Pendukung:

    • Message Queues (Kafka, RabbitMQ): Sangat penting untuk Choreography dan juga bisa digunakan Orchestrator untuk mengirim perintah/event.
    • Distributed Tracing Tools (Jaeger, Zipkin): Penting untuk observability.
    • Saga Frameworks (misal: Cadence, Temporal, Axon Framework): Untuk Orchestration yang lebih canggih, framework ini menyediakan fitur-fitur seperti workflow engine, state management, dan retry logic out-of-the-box.

6. Kapan Menggunakan Saga Pattern?

Gunakan Saga Pattern ketika:

Hindari Saga Pattern ketika:

Kesimpulan

Saga Pattern adalah alat yang sangat berharga dalam kotak peralatan setiap developer yang bekerja dengan arsitektur microservices. Ini memungkinkan kita mengatasi tantangan konsistensi data yang muncul ketika kita memecah monolit dan mengadopsi database per layanan.

Baik Anda memilih Choreography atau Orchestration, memahami prinsip dasar transaksi lokal dan transaksi kompensasi adalah kuncinya. Ingatlah untuk selalu mempertimbangkan tantangan praktis seperti idempotency, observability, dan penanganan kegagalan kompensasi untuk membangun sistem yang tangguh dan dapat diandalkan.

Dengan Saga Pattern, Anda tidak perlu lagi mengorbankan otonomi layanan demi konsistensi data. Anda bisa memiliki keduanya, membangun aplikasi terdistribusi yang kuat dan skalabel!

🔗 Baca Juga