Menu

Event-Driven Architecture with Kafka

2. Event-Driven Architecture with Kafka

a. Event Sourcing

Event sourcing is a design pattern where every change in state is stored as an event. Instead of saving only the current state, the system keeps the full history of what happened. Kafka is a strong fit for this approach because it naturally stores ordered events durably.

In a bookstore, an order is not just “saved” once; instead, the system might record order_created, payment_confirmed, packed, and shipped as separate events. The current state is then derived by replaying those events. This gives you a complete audit trail and makes debugging much easier.

Event sourcing also makes recovery simpler because you can rebuild the system state from the log. The tradeoff is that application logic becomes more complex, since business state must be derived rather than stored directly. It works best when historical traceability matters a lot.

b. CQRS with Kafka

CQRS stands for Command Query Responsibility Segregation. It separates the write model from the read model, so commands update state while queries read from a separate optimized model. Kafka helps implement CQRS by moving events from the write side to consumers that build read-optimized views.

In the bookstore, the checkout service might write order events, while separate consumers maintain projections for inventory, customer history, and analytics dashboards. This keeps write logic simple and allows each read model to be designed for its own use case. A reporting dashboard, for example, can be optimized for fast reads without affecting checkout performance.

CQRS pairs naturally with event sourcing, but it can also be used without it. The main benefit is that one event stream can feed many different read models. The tradeoff is eventual consistency, since read models may lag slightly behind the write model.

c. Microservices Communication Patterns

Kafka is often used as the communication layer between microservices. Instead of one service calling another synchronously over HTTP, services publish and consume events asynchronously. This reduces coupling and makes the system more resilient to partial failures.

For example, when a bookstore order is placed, the order service publishes an event, the inventory service reserves stock, the shipping service creates a shipment, and the email service sends a confirmation. None of these services need to know the internal details of the others. They just react to events.

There are three common patterns here: publish-subscribe, event notification, and event-carried state transfer. Publish-subscribe works well when multiple services need the same event. Event notification shares that something changed, while event-carried state transfer includes enough data so consumers do not need to call back to the source system.

Comparison: Communication Patterns

Pattern

Coupling

Latency

Best For

Synchronous API callsHighLow initially, fragile at scaleDirect request/response
Publish-subscribeLowLow to moderateFan-out workflows
Event-carried state transferLowLowDecoupled downstream processing