Publish-Subscribe Pattern
About
The Publish-Subscribe (Pub/Sub) pattern is an asynchronous messaging architecture where producers (publishers) send messages without directly targeting specific recipients. Instead, they publish messages to a channel, topic, or event bus. Consumers (subscribers) express interest in certain topics and receive messages only for those topics.
Unlike the request-response model, where communication is point-to-point and synchronous, Pub/Sub enables decoupled, many-to-many communication:
Publishers are unaware of who the subscribers are.
Subscribers are unaware of how many publishers exist or how they produce messages.
This makes it ideal for scalable, event-driven systems and real-time broadcast scenarios.
Publisher: Sends a message to a topic (not to a specific subscriber).
Broker / Event Bus: Handles routing and delivery to all subscribers interested in that topic.
Subscriber: Receives the message if they have subscribed to that topic.
Example: A news service publishes updates on different categories like sports, technology, and politics.
A publisher sends a message to the "Sports" topic.
Only subscribers to the "Sports" topic receive the update — technology and politics subscribers are unaffected.
Characteristics
The Publish-Subscribe (Pub/Sub) pattern has defining traits that make it a cornerstone of asynchronous, event-driven architecture. These characteristics determine how messages flow, how loosely components are coupled, and how scalability is achieved.
1. Topic or Channel-Based Routing
Messages are classified under a topic, channel, or subject.
Publishers send messages to a topic, not to specific recipients.
Subscribers receive only the topics they subscribed to.
Example:
Topic:
order.created
Subscribers: Payment Service, Inventory Service
When an order is created, both services receive the event.
2. Many-to-Many Communication
Multiple publishers can publish to the same topic.
Multiple subscribers can listen to the same topic.
A single event can reach thousands of subscribers simultaneously.
3. Asynchronous Delivery
Messages are typically queued or buffered by a broker.
Subscribers process events at their own pace without blocking publishers.
4. Loose Coupling Between Components
Publishers don’t know who subscribes to their events.
Subscribers don’t need to know where the message originated.
This allows independent scaling, deployment, and upgrades.
5. Broadcast Semantics
A single published message can be delivered to all active subscribers.
Depending on broker settings, delivery can be fan-out (all subscribers get it) or selective (based on filtering rules).
6. Decoupled Failure Handling
Publisher failures do not stop subscribers from working.
Subscriber failures do not block publishing - messages may be stored and delivered later (persistent messaging).
7. Optional Message Persistence
Many brokers (e.g., Kafka, RabbitMQ) allow durable storage so that messages are delivered even if a subscriber reconnects later.
Some lightweight brokers (e.g., Redis Pub/Sub) offer fire-and-forget delivery with no persistence.
8. Filtering & Routing Rules
Advanced systems allow subscribers to filter messages by attributes, headers, or payload content.
Supports pattern-based subscriptions (e.g., wildcard topics:
order.*
).
Execution Flow
The Pub/Sub execution flow describes how a message moves from a publisher → through a broker → to one or more subscribers, all without direct awareness between the sender and receivers.
Step-by-Step Flow
Publisher Creates a Message
The publisher prepares an event (e.g.,
order.created
) containing relevant data (order ID, customer details, etc.).It does not specify any recipients - only the topic or channel.
Message Sent to the Broker
The message is published to a message broker (e.g., Apache Kafka, RabbitMQ, Google Pub/Sub).
The broker receives, validates, and routes it based on the topic.
Topic-Based Routing
The broker categorizes the message under its topic or subject.
Multiple publishers may post to the same topic.
Multiple subscribers may be listening to that topic.
Subscribers Register Interest
Before messages are published, subscribers typically subscribe to one or more topics.
This subscription can be explicit (manual config) or dynamic (runtime API call).
Message Distribution
The broker copies or streams the message to all subscribers of that topic.
Delivery depends on broker settings:
Fan-out – all subscribers get every message.
Filtered delivery – subscribers get only relevant messages.
Subscriber Processes Message
Subscribers receive the event asynchronously.
Processing logic is independent of the publisher (e.g., one subscriber updates inventory, another sends an email).
Acknowledgment (Optional)
Some systems require subscribers to acknowledge receipt before removing the message from the queue (Kafka consumer offsets, RabbitMQ ACKs).
Others are fire-and-forget (e.g., Redis Pub/Sub).
Error Handling & Retry
If a subscriber fails to process a message, the broker may:
Retry delivery
Send it to a dead-letter queue for later inspection
Advantages
The Pub/Sub model is designed for scalable, decoupled, and flexible communication, making it a cornerstone for event-driven systems and distributed architectures.
1. Loose Coupling Between Components
Why it matters: Publishers and subscribers don’t know each other’s identities, locations, or internal logic.
Impact:
Easier maintenance and evolution of services.
Allows adding or removing subscribers without touching publisher code.
Example: An Order Service publishes an
order.shipped
event.The Email Service sends a shipping confirmation.
The Analytics Service records delivery statistics. Neither knows the other exists.
2. High Scalability
Why it matters: Multiple publishers and subscribers can be added without creating a tangled web of direct connections.
Impact:
Ideal for systems that grow over time.
Allows horizontal scaling of consumers.
Example: In Kafka, you can add more consumers to a consumer group to handle higher message throughput.
3. Asynchronous Processing
Why it matters: Subscribers handle messages in their own time, without blocking the publisher.
Impact:
Increases system responsiveness.
Enables workload distribution.
Example: A Payment Service can continue processing payments while the Notification Service sends receipts later.
4. Support for Multiple Message Consumers
Why it matters: One event can be consumed by many independent services.
Impact:
Enables fan-out patterns for broadcasting information.
Example: A single
user.registered
event can trigger:Sending a welcome email
Adding a record in a CRM
Logging for compliance
5. Flexibility in Adding New Features
Why it matters: New subscribers can be added without modifying existing publishers.
Impact:
Supports evolving business needs.
Example: Later, a Recommendation Service subscribes to
order.completed
to analyze purchase patterns — no changes to the Order Service.
6. Fault Isolation
Why it matters: Subscriber failures don’t directly affect publishers.
Impact:
One faulty service doesn’t bring down the entire system.
Example: If the Analytics Service is down, the Email Service still processes events normally.
7. Technology Diversity
Why it matters: Different subscribers can be implemented in different programming languages and platforms.
Impact:
Encourages heterogeneous environments.
Example:
Publisher in Java + Spring Boot
Subscriber in Node.js
Another subscriber in Python Flask
Limitations
While Pub/Sub offers flexibility and scalability, it also introduces operational and architectural challenges that teams must manage carefully.
1. Event Delivery Uncertainty
Why it matters: Depending on the broker and configuration, messages may be:
Delivered at least once (can cause duplicates)
Delivered at most once (can cause data loss)
Delivered exactly once (complex to achieve)
Impact: Application logic often needs idempotency to handle duplicates or missing events.
Example: If an
order.shipped
event is delivered twice, the Email Service might send two confirmation emails unless it checks for duplicates.
2. Increased Complexity in Debugging
Why it matters: Since publishers and subscribers are decoupled, tracing the event flow can be challenging.
Impact:
Harder to track cause-effect relationships.
Requires specialized tools for observability.
Example: An event is published, but one subscriber fails silently — finding the root cause without distributed tracing can be time-consuming.
3. Lack of Immediate Feedback
Why it matters: Publishers do not get a direct acknowledgment that the subscriber processed the event successfully.
Impact:
Hard to build real-time confirmation workflows.
Requires additional channels if confirmation is necessary.
Example: If a Payment Service publishes
payment.success
but the Order Service fails to mark the order as paid, the publisher won’t know unless there’s a monitoring system.
4. Ordering Guarantees are Broker-Dependent
Why it matters: Not all brokers guarantee message ordering across subscribers.
Impact:
Potential for out-of-sequence events.
Example: If
order.created
arrives afterorder.shipped
due to reordering, consumers may process events incorrectly.
5. Possible Performance Bottlenecks
Why it matters: A slow subscriber can create back-pressure if the broker has limited queue capacity.
Impact:
Can cause message delivery delays for all subscribers.
Example: If the Analytics Service processes events too slowly, Kafka partitions can get filled, delaying events for other consumers.
6. Operational Overhead
Why it matters: Message brokers (Kafka, RabbitMQ, Google Pub/Sub, etc.) require deployment, scaling, and monitoring.
Impact:
Adds infrastructure cost and complexity.
Example: Kafka clusters need Zookeeper (in older versions), partition management, and disk space monitoring.
7. Potential Overhead in Event Schema Management
Why it matters: Multiple services consuming the same event require a shared understanding of its structure.
Impact:
Schema changes can break subscribers unexpectedly.
Example: Adding a required field to an event without versioning can crash subscribers that aren’t updated.
Common Technologies & Protocols Used
The Publish-Subscribe (Pub/Sub) model can be implemented using various messaging brokers, streaming platforms, and cloud-based messaging services. The choice depends on scale, latency requirements, persistence, and operational complexity.
1. Apache Kafka
Type: Distributed Event Streaming Platform
Key Features:
High-throughput, fault-tolerant, distributed log-based storage.
Event persistence for replay.
Partitioned topics for parallel processing.
Consumer groups for scalability.
When to Use:
Large-scale event streaming.
Scenarios needing replayable events and strong ordering guarantees within a partition.
Example: E-commerce platform publishes order events to Kafka, consumed by analytics, inventory, and notification services independently.
2. RabbitMQ
Type: Traditional Message Broker (AMQP protocol)
Key Features:
Flexible routing (topics, fanout, direct exchange).
Acknowledgments and retry mechanisms.
Plugins for multiple protocols (MQTT, STOMP).
When to Use:
Complex routing rules.
Reliable delivery without massive throughput needs.
Example: Order service publishes to a fanout exchange so that billing, shipping, and email services each receive the same event.
3. Google Cloud Pub/Sub
Type: Managed Cloud Messaging Service
Key Features:
Fully managed with auto-scaling.
Global delivery across regions.
Integrates with Google Cloud Dataflow, BigQuery.
When to Use:
Cloud-native apps on GCP.
No desire to manage messaging infrastructure.
Example: IoT devices publish telemetry to Pub/Sub, processed in real-time for analytics dashboards.
4. AWS SNS + SQS
Type: Cloud Messaging Combo (SNS = Pub/Sub, SQS = Queuing)
Key Features:
SNS publishes messages to multiple subscribers (SQS queues, Lambda functions, HTTP endpoints).
SQS ensures durability and decoupling.
When to Use:
AWS ecosystem applications.
Need for durable message queues per subscriber.
Example: SNS publishes an image-uploaded event to multiple SQS queues for image processing and audit logging.
5. NATS
Type: Lightweight, High-Performance Messaging System
Key Features:
Simple to deploy.
Supports both core pub/sub and JetStream for persistence.
Very low latency.
When to Use:
Microservices communication with minimal infrastructure.
Real-time, low-latency scenarios.
Example: Financial trading platform uses NATS for real-time market data broadcasting.
6. MQTT
Type: Lightweight Pub/Sub Protocol (often over TCP)
Key Features:
Designed for IoT and low-bandwidth devices.
QoS levels for delivery reliability.
Topic-based filtering.
When to Use:
IoT sensors, embedded devices.
Constrained environments with unstable networks.
Example: Smart home devices publishing temperature readings to an MQTT broker.
7. Redis Pub/Sub
Type: In-memory Data Store with Pub/Sub capability
Key Features:
Extremely low latency.
Simple to use but no persistence in standard pub/sub mode.
When to Use:
Temporary real-time notifications where persistence is not required.
Example: Gaming servers broadcasting match status updates to connected clients
Last updated