Pub-Sub: The Digital Megaphone
1. Beyond 1-to-1 Messaging
In a standard Message Queue (Point-to-Point), one message is processed by one consumer. This is great for work distribution (e.g., “Resize this image”).
But what if multiple services need to know about an event?
- User Signs Up:
Email Serviceneeds to send a welcome email.Analytics Serviceneeds to log the event.Fraud Serviceneeds to check the IP.
If we use a standard queue, only one of them will get the message. We need Pub-Sub.
2. The Pub-Sub Model
Publish-Subscribe decouples the sender (Publisher) from the receivers (Subscribers). Think of it like a Radio Station: The DJ (Publisher) broadcasts, and anyone tuned in (Subscribers) hears it.
Core Components
- Publisher: Sends a message to a Topic (not a specific queue).
- Topic (Exchange): The “Post Office” that decides where to route the message.
- Subscription: Services “subscribe” to the topic.
- Fanout: The broker copies the message to ALL subscribers.
3. Exchange Types Deep Dive
Not all Pub-Sub is the same. In AMQP (RabbitMQ), the “Topic” is actually called an Exchange. There are 4 main types:
| Exchange Type | Routing Logic | Use Case |
|---|---|---|
| Direct | Exact Match (routing_key == binding_key) |
Unicast routing (e.g., error.log → ErrorQueue). |
| Fanout | Broadcasts to ALL queues. Ignores key. | “Mass Notification” (e.g., New User Signup → Email, Analytics, Fraud). |
| Topic | Pattern Match with Wildcards (*, #). |
Multicast routing (e.g., payment.us.* vs payment.#). |
| Headers | Matches message headers (metadata) instead of key. | Complex routing where the routing key string isn’t enough. |
[!TIP] Performance: Fanout is the fastest (O(1) complexity) because it blindly copies messages. Topic exchanges are slower (O(N) complexity) because they must parse the string pattern against the routing table.
4. Interactive Demo: Topic Exchange & Wildcards
Visualize how messages are routed using Routing Keys.
- Scenario: A Payment System emitting events like
payment.us.successorpayment.eu.error. - Goal: Route specific events to specific services using Wildcards (
*matches one word,#matches many). - Action: Click the buttons to publish different events and watch who receives them.
5. Why is this powerful?
1. Loose Coupling (Plug & Play)
If we need to add a new Recommendation Service next month, we don’t change the Payment Gateway code.
We just add a new subscriber. The Publisher doesn’t know (or care) who is listening.
2. Parallel Processing
All subscribers receive the message simultaneously (or near simultaneously).
- Email sent: 200ms
- Analytics logged: 50ms
- Fraud check: 100ms Total Time: Max(200, 50, 100) = 200ms (Parallel), instead of 350ms (Sequential).
3. Fanout Cost Analysis
Be careful with Fanout. If you have 1 event and 100 subscribers, the broker must create 100 copies.
- CPU Cost: Low (it’s just a pointer copy).
- Network Cost: High (100x bandwidth).
- Storage Cost: High (if durable queues are used).
6. Filtering Strategies
Where should the filtering happen?
A. Broker-Side Filtering (Efficient)
The broker (Exchange) decides which queue gets the message.
- Example: RabbitMQ Topic Exchange.
- Logic: If no one binds to
sys.debug, the message is discarded immediately at the broker. - Pros: Saves network bandwidth and consumer CPU.
- Cons: Broker works harder (CPU usage for pattern matching).
B. Consumer-Side Filtering (Wasteful)
The consumer receives everything and filters it in code.
- Example: All services listen to a “Firehose”.
- Logic:
if (msg.type != 'error') return; - Pros: Dumb broker (fast).
- Cons: Massive waste of bandwidth. The consumer wakes up for nothing.
[!TIP] Always prefer Broker-Side Filtering for high-volume systems. Only send data to services that actually need it.
7. Understanding Wildcards
Sometimes you don’t want all messages. You want to subscribe to a subset.
Wildcards (RabbitMQ Example)
- Topic format:
service.region.status - Wildcard
*(Star): Matches exactly one word.payment.us.*matchespayment.us.successbut NOTpayment.us.db.error.
- Wildcard
#(Hash): Matches zero or more words.payment.#matchespayment.error,payment.us.success, andpayment.debug.level.1.
8. Delivery Semantics
When doing Pub-Sub, you must decide your guarantee level:
| Semantics | Description | Pros | Cons |
|---|---|---|---|
| At-Most-Once | Fire and Forget. Message might be lost. | Fastest. No state tracking. | Data loss possible. |
| At-Least-Once | Retries until ack received. | No data loss. | Duplicates (Requires Idempotency). |
| Exactly-Once | Hardest to achieve. Transactional. | Perfect consistency. | High latency, complex. |
9. Summary
- Use Queues for 1-to-1 work distribution.
- Use Pub-Sub for 1-to-Many notifications.
- Enables Event-Driven Architecture where services react to state changes.
- Use Topic Routing to filter noise at the source to save bandwidth.