Event-Driven Architecture: Message Queues, Pub/Sub Systems, and Event Sourcing
In modern software development, systems must be scalable, resilient, and responsive. Event-Driven Architecture (EDA) is a design paradigm that enables applications to react to events (changes in state) in real-time, improving flexibility and decoupling components.
This blog explores three key concepts in EDA:
- Message Queues – For ordered, reliable message processing.
- Pub/Sub Systems – For broadcasting events to multiple consumers.
- Event Sourcing – For storing state changes as a sequence of events.
We’ll break down each concept, compare them, and discuss real-world use cases.
1. What is Event-Driven Architecture (EDA)?
EDA is a software architecture where components communicate via events—notifications that something has happened (e.g., "Order Placed," "Payment Processed"). Instead of direct API calls, systems emit and react to events asynchronously.
Key Benefits of EDA
- Loose Coupling – Services don’t need to know about each other.
- Scalability – Events can be processed in parallel.
- Resilience – Failures in one service don’t cascade.
- Real-Time Processing – Immediate reactions to changes.
2. Message Queues (Point-to-Point Communication)
A message queue is a middleware that stores messages until they are processed by a consumer. It follows a First-In-First-Out (FIFO) model.
How It Works
- A producer sends a message to a queue.
- The message is stored until a consumer retrieves and processes it.
- Once processed, the message is removed (or acknowledged).
Use Cases
- Order Processing – Ensuring orders are handled sequentially.
- Task Scheduling – Background jobs like sending emails.
- Load Leveling – Smoothing out traffic spikes.
Popular Message Queue Systems
- RabbitMQ – Simple, robust, supports multiple protocols.
- Amazon SQS – Fully managed, scalable queue service.
- Apache Kafka (as a queue) – High-throughput, durable.
Example: Order Processing with RabbitMQ
# Producer (Order Service)
channel.queue_declare(queue='orders')
channel.basic_publish(exchange='', routing_key='orders', body='Order123')
# Consumer (Payment Service)
def callback(ch, method, properties, body):
print(f"Processing order: {body}")
channel.basic_consume(queue='orders', on_message_callback=callback, auto_ack=True)
channel.start_consuming()
Pros & Cons
| Pros | Cons |
|---|---|
| Guaranteed delivery | Only one consumer per message |
| Ordered processing | Requires manual scaling |
| Decouples producers & consumers | Can become a bottleneck |
3. Pub/Sub Systems (Publish-Subscribe Model)
In Pub/Sub, messages are broadcasted to multiple consumers via topics (channels). Unlike queues, multiple subscribers can receive the same message.
How It Works
- A publisher sends a message to a topic.
- The message is delivered to all subscribers of that topic.
- Subscribers process the message independently.
Use Cases
- Notifications – Sending alerts to multiple services.
- Real-Time Analytics – Broadcasting sensor data.
- Log Aggregation – Multiple services consuming logs.
Popular Pub/Sub Systems
- Apache Kafka – High-throughput, distributed log.
- Google Pub/Sub – Serverless, auto-scaling.
- AWS SNS – Simple, integrates with SQS.
Example: Notifications with Kafka
# Publisher (Notification Service)
producer = KafkaProducer(bootstrap_servers='localhost:9092')
producer.send('notifications', value='New user registered')
# Subscriber (Email Service)
consumer = KafkaConsumer('notifications', bootstrap_servers='localhost:9092')
for message in consumer:
print(f"Sending email for: {message.value}")
Pros & Cons
| Pros | Cons |
|---|---|
| Multiple consumers per message | No guaranteed order (unless partitioned) |
| Highly scalable | Complex setup (e.g., Kafka) |
| Real-time broadcasting | Can lead to duplicate processing |
4. Event Sourcing (Storing State Changes as Events)
Event Sourcing is a pattern where state changes are stored as an immutable sequence of events. Instead of updating a database record, we append events (e.g., "UserCreated," "AddressUpdated").
How It Works
- Every state change is recorded as an event.
- The current state is derived by replaying all past events.
- Events are stored in an event store (e.g., Kafka, EventStoreDB).
Use Cases
- Audit Logs – Tracking every change for compliance.
- Financial Systems – Reconstructing account balances.
- CQRS (Command Query Responsibility Segregation) – Separating reads and writes.
Example: Bank Account with Event Sourcing
# Event Store
events = [
{"type": "AccountCreated", "data": {"id": "acc1", "balance": 0}},
{"type": "Deposited", "data": {"id": "acc1", "amount": 100}},
{"type": "Withdrawn", "data": {"id": "acc1", "amount": 50}},
]
# Reconstructing state
balance = 0
for event in events:
if event["type"] == "Deposited":
balance += event["data"]["amount"]
elif event["type"] == "Withdrawn":
balance -= event["data"]["amount"]
print(f"Current balance: {balance}") # Output: 50
Pros & Cons
| Pros | Cons |
|---|---|
| Complete audit trail | Event replay can be slow |
| Time-travel debugging | Storage can grow large |
| Works well with CQRS | Requires careful schema design |
5. Comparing Message Queues, Pub/Sub, and Event Sourcing
| Feature | Message Queues | Pub/Sub | Event Sourcing |
|---|---|---|---|
| Communication | Point-to-point | Broadcast | Append-only log |
| Consumers | Single consumer per message | Multiple consumers | Replayable events |
| Ordering | FIFO (usually) | Depends on system | Strictly ordered |
| Use Case | Task processing | Real-time notifications | State reconstruction |
6. When to Use Which?
- Use Message Queues for ordered, one-to-one processing (e.g., order fulfillment).
- Use Pub/Sub for broadcasting to multiple services (e.g., notifications).
- Use Event Sourcing when you need an audit log or historical state (e.g., banking).
7. Conclusion
Event-Driven Architecture enables scalable, decoupled, and resilient systems.
- Message Queues ensure reliable, ordered processing.
- Pub/Sub allows real-time event broadcasting.
- Event Sourcing provides a complete history of state changes.
By combining these patterns, you can build highly responsive and maintainable systems.
Would you like a deeper dive into any of these topics? Let me know in the comments! 🚀
Projects to explore next
Source-code projects from the KritiMyantra catalogue. Check each project's details before buying.
Flask Authentication System (Free Version) - Kritim Yantra
🛠 Features✔ Google & GitHub Authentication✔ User Registration & Login✔ Profile/Dashboard Access✔ Secure & Mi...
Flask Blog CMS with Admin Dashboard — Python Source Code
A Flask-based blogging website with a built-in admin dashboard. Manage articles, images, categories, tags and featured p...
Laravel 12 + ReactJS Starter Kit: Add Multi-Language Support (Arabic, English, Spanish) with Blog CRUD
🚀 Installation & Setup Download & Extract Get the ZIP from kritimyantra.com and extract it. Includes preconfigu...
Comments
No comments yet. Be the first to comment.
Sign in to join the discussion.