Belajar System Design - Event-Driven Architecture & CQRS
Episode 16 of 28

Belajar System Design - Event-Driven Architecture & CQRS

Memahami event-driven architecture (event broker, choreography vs orchestration/saga pattern), CQRS (command query responsibility segregation), dan outbox pattern untuk reliable event publishing yang mengatasi dual-write problem

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 15 kita memahami microservices architecture, pada episode ini kita masuk ke pola komunikasi yang powerful untuk microservices: event-driven architecture dan CQRS. Dua konsep ini menyelesaikan masalah fundamental: bagaimana menjaga service loose coupling saat ada banyak data yang harus dikonsistenikan lintas service?

Event-driven architecture mengubah cara kita berpikir tentang komunikasi: bukan "saya panggil kamu" (request-response), tapi "saya beri tahu semua orang tentang apa yang terjadi" (event). CQRS memisahkan model write dan read — memungkinkan optimasi terpisah untuk masing-masing.

Event-Driven Architecture

Event Emitter/Listener (In-Process)

In-process event
OrderService.createOrder(order):
  1. Save order ke database
  2. Emit event: OrderCreated { orderId, userId, items }
  3. Return success
 
NotificationListener.on(OrderCreated):
  1. Kirim email "Order confirmed" ke user
 
InventoryListener.on(OrderCreated):
  1. Kurangi stock

Event Broker (Kafka)

100%

Kafka sebagai event broker memastikan:

  • Events persisten (bisa replay).
  • Consumer independent (bisa tambah consumer tanpa ubah producer).
  • High throughput (jutaan events per detik).

Choreography vs Orchestration

AspekChoreographyOrchestration
PolaSetiap service merespons event secara independentSatu orchestrator mengkoordinasi workflow
CouplingSangat looseTighter (orchestrator tahu semua step)
VisibilitySulit melihat flow utuhMudah (orchestrator punya central logic)
Error handlingSetiap service handle sendiriOrchestrator handle retry/compensation
Use caseSimple workflowsComplex workflows (saga)

Saga Pattern

Saga adalah sequence transaksi lintas service dengan kompensasi (undo) jika ada kegagalan.

Choreography Saga

Choreography saga
1. Order Service: create order → emit OrderCreated
2. Payment Service: process payment → emit PaymentProcessed
3. Inventory Service: reserve stock → emit StockReserved
4. Notification Service: send email → emit OrderConfirmed
 
Jika step 3 gagal:
3a. Inventory Service: emit StockReservationFailed
4a. Payment Service: refund (compensation)
5a. Order Service: update status ke "cancelled"

Orchestration Saga

Orchestration saga
Orchestrator (OrderSaga):
  1. Create order
  2. Process payment (retry 3x)
  3. Reserve stock (retry 3x)
  4. Send notification
 
  Jika step 3 gagal:
  → Compensate step 2: refund payment
  → Compensate step 1: cancel order

CQRS (Command Query Responsibility Segregation)

Konsep

Pisahkan model write (command) dan read (query) — database terpisah untuk write dan read.

100%

Mengapa CQRS?

Masalah tanpa CQRS
Write model: normalized (3NF) untuk data integrity
Read model: juga normalized → query lambat (JOIN banyak)
 
Solusi: CQRS
Write DB: normalized (PostgreSQL) → data integrity
Read DB: denormalized (Elasticsearch/Redis) → query cepat

CQRS + Event Sourcing

Event sourcing dengan CQRS
Write side:
  - Tidak simpan state langsung
  - Simpan sequence of events (event store)
  - State = replay semua events
 
Read side:
  - Update read model dari events
  - Read model = projection dari events

Event sourcing memberikan audit trail sempurna — setiap perubahan terekam sebagai event.

Trade-off CQRS

AspekKelebihanKekurangan
Read performanceQuery cepat (denormalized)Duplikasi data
Write performanceWrite ke normalized DBEventual consistency untuk reads
ComplexityFlexible read modelLebih banyak komponen
DebuggingEvent store = audit trailHarder untuk debugging state

Outbox Pattern

Masalah Dual-Write

Dual-write problem
1. Save order ke DB
2. Publish event ke Kafka
 
Masalah: jika step 2 gagal (setelah step 1 sukses)
→ DB punya order baru, tapi Kafka tidak punya event
→ Consumer tidak tahu ada order baru

Solusi: Outbox Pattern

Outbox pattern
1. Dalam SATU transaksi:
   a. Save order ke DB
   b. Save event ke outbox table di DB
2. Separate process (CDC/polling) baca outbox → publish ke Kafka
3. Hapus event dari outbox setelah publish sukses
 
Benefit: order dan event konsisten (same transaction)
Outbox table
CREATE TABLE outbox (
    id SERIAL PRIMARY KEY,
    event_type VARCHAR(100),
    payload JSONB,
    created_at TIMESTAMP DEFAULT NOW(),
    published BOOLEAN DEFAULT FALSE
);

CDC (Change Data Capture) tools: Debezium, Maxwell, pg_notify.

Note

Outbox pattern mengatasi dual-write problem dengan menjamin atomicity antara data write dan event publish. Gunakan CDC (seperti Debezium) untuk mem-poll outbox table dan publish ke Kafka — lebih reliable dari polling manual.

Praktik: Order Service dengan CQRS

Order service flow
Command: CreateOrder
  1. Validate order (user exists, stock available)
  2. Save order ke write DB (PostgreSQL)
  3. Save event ke outbox (same transaction)
  4. Return success
 
CDC Process:
  5. Debezium detect outbox row
  6. Publish event "OrderCreated" ke Kafka
  7. Mark outbox as published
 
Query: GetUserOrders(userId)
  1. Read dari read DB (denormalized, indexed)
  2. Return cached/denormalized data (fast!)

Penutup

Inti yang harus dibawa pulang:

  • Event-driven: loose coupling antar service; producer tidak tahu consumer; events persisten di Kafka.
  • Choreography untuk simple workflows; orchestration (saga) untuk complex workflows dengan kompensasi.
  • CQRS memisahkan write (normalized) dan read (denormalized) — optimasi terpisah untuk masing-masing.
  • Outbox pattern mengatasi dual-write problem: save event ke DB dalam transaksi yang sama, lalu publish via CDC.

Di episode 17 selanjutnya kita akan membahas migrasi: monolith → modular monolith → microservices — Strangler Fig pattern, modular monolith sebagai starting point, dan kapan saatnya extract ke microservices. Migrasi arsitektur adalah perjalanan, bukan sekadar tujuan!

Belajar System Design - Event-Driven Architecture & CQRS | Belajar System Design