This article explains event-driven architecture through a conversational analogy, covering how events decouple services and comparing Redis Pub/Sub, RabbitMQ, and Kafka based on their strengths for different use cases like real-time notifications, task queues, and event replay.
Event-driven architecture solves a fundamental problem in distributed systems: how to decouple services so they can evolve independently while still communicating effectively. Instead of direct service-to-service calls that create tight coupling and fragile dependencies, services publish events when something significant occurs, and other services subscribe to those events they care about. This pattern transforms monolithic workflows into resilient, scalable systems where failures in one component don't cascade uncontrollably.
The core insight is simple yet powerful: treat business occurrences as first-class citizens. When a user places an order, that's not just a database write—it's an 'OrderPlaced' event. When a payment succeeds, that's a 'PaymentCompleted' event. By focusing on these events rather than the mechanics of service interaction, architects gain flexibility. The order service no longer needs to know about email services, inventory systems, or analytics pipelines; it merely publishes the event and moves on.
This approach directly addresses the spaghetti code problem described in the original analogy. Consider a food delivery system where placing an order triggers multiple actions: saving the order, sending confirmations, notifying the restaurant, updating loyalty points, and refreshing analytics. In a tightly coupled implementation, the order service function becomes a brittle chain of dependencies. Adding a WhatsApp notification requirement forces modification of this central function, increasing risk and complicating testing. With event-driven design, the order service publishes 'OrderCreated' and remains unchanged when new subscribers (like a WhatsApp service) are added. Each subscriber operates independently, scaling or failing without affecting others.
However, the choice of event delivery mechanism introduces critical trade-offs that determine system reliability and functionality. Three dominant technologies address different points on the reliability-simplicity spectrum:
Redis Pub/Sub operates like an FM radio broadcast. Publishers send messages to channels, and subscribers receive them only if actively listening at that exact moment. There's no message persistence—if a subscriber is offline when an event publishes, that message is lost forever. This makes it ideal for transient, real-time use cases where occasional loss is acceptable: live user presence indicators ('User is typing...'), real-time stock tickers, or ephemeral chat notifications. The simplicity and low latency come at the cost of durability, rendering it unsuitable for financial transactions or critical business events where message loss could mean lost revenue or compliance violations.
RabbitMQ introduces message persistence through queues, functioning more like a reliable postal service. When a publisher sends a message, RabbitMQ stores it durably until a worker explicitly acknowledges processing. If a worker crashes before acknowledging, the message returns to the queue for redelivery. This guarantees at-least-once delivery, making it perfect for task queues: sending emails, generating reports, or processing image uploads where each message represents a discrete unit of work. However, RabbitMQ's queue model has a fundamental limitation for event-driven architectures—once a message is acknowledged and removed from the queue, it's gone forever. This prevents multiple independent services from consuming the same event for different purposes (e.g., one service for email notifications, another for fraud detection, a third for analytics). If the email service processes and acknowledges an 'OrderPlaced' message, the analytics service never sees it, even if it was temporarily offline.
Kafka resolves this limitation by treating events as immutable records in a distributed log, akin to a library book that never gets removed from the shelf. Events are appended to topics and retained for configurable periods (hours, days, or years), allowing any service to read historical events at any time. Each consumer group tracks its own position in the log via offsets, enabling multiple services to independently consume the same event stream without interference. If analytics crashes for two hours, it resumes reading from its last offset upon restart, processing all missed events without duplication or loss. This replay capability is invaluable for regulatory compliance, debugging, and enabling new teams to analyze historical behavior—imagine a recommendation team needing six months of purchase data to train a model; with Kafka, they simply start reading from the beginning of the relevant topic.
Scaling considerations further differentiate these technologies. Redis Pub/Sub scales vertically but struggles with high fan-out scenarios since every subscriber receives every message. RabbitMQ scales through queue partitioning and worker pools but faces bottlenecks when many services need the same message. Kafka excels at high-throughput horizontal scaling through partitioning: a single topic can be split across multiple brokers, with events distributed by key (e.g., userId) to ensure related events stay ordered. Consumer groups allow parallel processing where each partition is consumed by exactly one member of the group, enabling linear scalability as partitions increase.
The decision framework for choosing between these tools hinges on three questions:
- Do you need message history or replay capability? If yes, Kafka is the clear choice.
- If not, do multiple independent services need to consume the same event? If yes, Kafka still wins despite its complexity—RabbitMQ cannot support this pattern.
- If only one service consumes each event, do you need guaranteed delivery? If yes, use RabbitMQ for task queues; if no (occasional loss is acceptable), Redis Pub/Sub suffices for real-time notifications.
Real-world implementations validate these distinctions. Social media platforms use Redis Pub/Sub for live comment updates where missing a notification is inconvenient but not catastrophic. E-commerce order processing relies on RabbitMQ for reliable email and SMS delivery where each message must be sent exactly once. Financial institutions and streaming services like Netflix deploy Kafka for audit trails, fraud detection, and personalization engines where replaying historical events is essential for business intelligence and model training.
Ultimately, event-driven architecture isn't about selecting the 'best' tool but matching the technology to the specific guarantees your business requires. Start by identifying your critical events, determining who needs to know about them, and assessing the cost of message loss. Only then does the optimal choice between Pub/Sub simplicity, RabbitMQ reliability, or Kafka's replay power become evident.

Comments
Please log in or register to join the discussion