Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 75

Pub/Sub for Event-Driven Microservices

Recommended resources

Hello! Let's dive into the next piece of our asynchronous processing puzzle.

In our last session, we dissected the role of a message broker and compared two titans: RabbitMQ, the dedicated and reliable postmaster, and Redis, the versatile and lightning-fast in-memory store. We saw how they enable communication between different parts of a system without them being directly connected. We used terms like "Pub/Sub" and "fan-out" to describe how one message could be sent to many receivers.

Today, we're going to formalize that concept. The learning outcome for this lesson is to explain the Publish/Subscribe (Pub/Sub) pattern and how it enables event-driven architectures for service decoupling. This pattern is not just a feature of a broker; it's a fundamental architectural paradigm that changes how you design and build complex, scalable backend systems.

The Problem: The Rigidity of Direct Communication

Imagine a typical e-commerce backend built with microservices. When a user places an order, several things need to happen:

  1. The Orders service saves the order to the database.
  2. The Inventory service needs to decrement the stock for the purchased items.
  3. The Payments service needs to process the payment.
  4. The Notifications service needs to send a confirmation email to the user.
  5. A new Analytics service is added to track purchasing trends.

In a traditional, request-driven model, the Orders service would be responsible for making direct, synchronous API calls to each of the other services.

A tightly-coupled system where the Orders service must directly call all other services.

This approach has several critical flaws, especially as systems grow:

  • Tight Coupling: The Orders service must know the network address and API contract of every other service. If the Inventory service's endpoint changes, the Orders service must be updated and redeployed.
  • Lack of Resilience: What if the Notifications service is temporarily down? The entire order placement process might fail or be significantly delayed, even though the core order was saved correctly. The failure of one non-essential component can cascade and bring down the whole operation.
  • Poor Scalability: Every time a new service needs to react to an order placement (like our new Analytics service), we have to modify and redeploy the Orders service to add another API call. This is slow and error-prone.

The core issue is that the Orders service has too many responsibilities and is too knowledgeable about the rest of the system. We need a way to decouple these components.

To see this problem animated, the following video does an excellent job of showing the drawbacks of a synchronous request-response model in a microservice architecture.

What is the Publisher Subscriber Model?

Let's watch this segment from Gaurav Sen's video 'What is the Publisher Subscriber Model?'. It clearly illustrates the latency and failure-propagation issues in a tightly coupled system.

Watch the video from the beginning to 01:52. Pay attention to how a failure in one downstream service (S4) impacts the entire chain of requests back to the client.


The Solution: The Publish/Subscribe Pattern

The Publish/Subscribe (Pub/Sub) pattern fundamentally inverts the communication model. Instead of the Orders service commanding other services, it simply announces an event: "An order was placed."

The pattern consists of four key components:

  1. Publisher: The component that creates and sends the message (e.g., the Orders service). It doesn't know or care who is listening. It simply sends the message to a specific topic.
  2. Subscriber: A component that is interested in certain types of messages (e.g., the Inventory, Payments, and Notifications services). It subscribes to topics it cares about.
  3. Topic (or Channel): A named channel to which messages are published. In our example, this would be the order_placed topic.
  4. Message Broker (or Event Bus): The intermediary that filters and routes messages from publishers to the appropriate subscribers. It's the central nervous system that manages these connections.
How the Pub/Sub Messaging Pattern Works (Food Ordering Scenario)
This diagram uses a food ordering system to show the Pub/Sub pattern in action. The User Profile Service publishes a 'Pizza Order' event, which the Restaurant Partner Service subscribes to. Services communicate asynchronously through events, managed by a central message broker, without knowing about each other.

The key takeaway is decoupling. The publisher and subscribers are completely unaware of each other's existence. The Orders service no longer needs to know the addresses or APIs of the other services. It just sends its event to the broker and is done. This resolves the issues we identified:

  • Loose Coupling: The Orders service only needs to know about the broker.
  • Improved Resilience: If the Notifications service is down, the broker holds the order_placed message for it until it's back online. The order process itself completes successfully without interruption.
  • Enhanced Scalability: When the new Analytics service comes online, it simply subscribes to the order_placed topic. No changes are needed in the Orders service.

Let's continue with the Gaurav Sen video, as it perfectly explains how Pub/Sub solves the problems it just presented and what benefits this provides.

What is the Publisher Subscriber Model?

Now, let's see how the Pub/Sub model directly addresses the issues of tight coupling and failure propagation.

Watch from 01:52 to 05:46. Focus on how the message broker acts as an intermediary, the 'fire and forget' nature of the publisher's job, and the key advantages discussed, such as decoupling, scalability, and improved system understanding.


Pub/Sub as the Foundation of Event-Driven Architecture

When you build a system around the Pub/Sub pattern, you are creating an Event-Driven Architecture (EDA). In an EDA, the flow of the system is determined by the production, detection, and consumption of asynchronous events.

This is a paradigm shift from a request-driven model:

  • Request-Driven (Imperative): You command other services to perform actions. "Inventory service, decrease stock for item X."
  • Event-Driven (Reactive): You announce facts about what has already happened. "An order was placed for item X." The Inventory service hears this event and decides for itself that it needs to decrease its stock.
Event-Driven Architecture Components
This diagram illustrates the structure of an Event-Driven Architecture. Multiple 'Producers' send different events to a central 'Event manager' (the broker). 'Consumers' subscribe only to the event types they are interested in, showcasing the decoupling at the heart of the system.

This reactive model is what makes systems so flexible and scalable. For a more structured breakdown of these benefits, the Microsoft Azure documentation on this pattern is an excellent resource.

Publisher-Subscriber pattern - Azure Architecture Center

Let's read the 'Publisher-Subscriber pattern' article from the Azure Architecture Center. It provides a formal, industry-standard definition and a clear list of the benefits.

Read the 'Context and problem', 'Solution', and 'benefits' sections. This will solidify your understanding of the components and reinforce how Pub/Sub enables decoupling, scalability, and reliability.

Pub/Sub vs. P2P (Task Queues)

In the previous module, we discussed task queues, which often use a Point-to-Point (P2P) messaging pattern. It's crucial to understand the difference:

  • P2P (One-to-One): A message is sent to a specific queue and is consumed by only one worker, even if multiple workers are listening. This is for distributing tasks (e.g., "process this video").
  • Pub/Sub (One-to-Many): A message is sent to a topic and is delivered to every subscriber of that topic. This is for broadcasting events (e.g., "a user signed up").

The following article explains this distinction clearly.

Delving into Message Brokers Internals

This article, 'Delving into Message Brokers Internals', provides a concise comparison between the P2P and Pub/Sub patterns.

Read the sections 'Message sending patterns:', 'P2P (work/task queue)', 'Pub/Sub', and the 'Pros' list. Focus on the two key differences highlighted between P2P and Pub/Sub regarding destination and message distribution.


The Deep Dive: Trade-offs and Challenges

As you requested, we need to go to the deepest level, which means understanding the drawbacks. The decoupling and asynchronicity of Pub/Sub are powerful, but they come at a cost.

1. Lack of Atomicity and Consistency

The biggest challenge is handling operations that must succeed or fail as a single, atomic unit. The classic example is a financial transaction.

Watch how the Pub/Sub model can lead to an inconsistent state in a system that requires strong consistency.

What is the Publisher Subscriber Model?

The Pub/Sub pattern is not suitable for all use cases. Let's return to the Gaurav Sen video to see a concrete example of where it fails.

Watch from 05:46 to 09:14. This section walks through a financial transaction scenario. Pay close attention to how the separate, asynchronous processing of commission and fund transfer leads to a corrupted final state. This highlights the loss of atomicity.

For such transactional workflows, a request-response model or more advanced patterns like Sagas (which we may cover later) are often required. You can't simply replace all direct communication with Pub/Sub.

2. Message Delivery Guarantees

The term "Pub/Sub" doesn't imply a specific delivery guarantee. It depends entirely on the message broker and its configuration:

  • At-most-once: The broker tries to deliver the message but may lose it if a subscriber is offline or the broker crashes. This is common in simple, "fire-and-forget" systems. Redis's basic PUBSUB command provides this.
  • At-least-once: The broker guarantees the message will be delivered, but it might be delivered more than once (e.g., if a consumer processes a message but fails before acknowledging it). This requires consumers to be idempotent.
  • Exactly-once: The ideal but most complex and resource-intensive guarantee.

The following clip explains Redis's simple PUBSUB implementation and its trade-offs.

Redis Deep Dive w/ a Ex-Meta Senior Manager

To see a practical example of a simpler, less reliable Pub/Sub implementation, let's watch this segment from the 'Redis Deep Dive' video.

Watch from 26:38 to 29:56. The speaker explains Redis Pub/Sub using a chat room example and explicitly mentions its 'at most once delivery' guarantee and what that implies for system design.

3. Complexity Moves to the Subscribers

While the publisher's logic becomes simpler, the overall system complexity doesn't disappearโ€”it moves. Subscribers must now be designed to handle:

  • Repeated Messages: If the broker offers "at-least-once" delivery, a subscriber might receive the same message twice. The subscriber's logic must be idempotent, meaning processing the same message multiple times has the same effect as processing it once.
  • Out-of-Order Messages: There is often no guarantee that messages will be received in the order they were sent.
  • Poison Messages: A malformed message that repeatedly causes a subscriber to crash can get stuck in a redelivery loop. Brokers often provide a "dead-letter queue" to handle such messages.

Conclusion

You now have a deep understanding of the Publish/Subscribe pattern, its role in modern backend design, and its trade-offs. It is the engine that powers scalable, resilient, and flexible event-driven architectures.

Key Takeaways:

  • Pub/Sub decouples services by introducing a message broker that routes events from publishers to subscribers based on topics.
  • This pattern is the foundation for Event-Driven Architectures (EDA), enabling systems to be more scalable, resilient, and flexible by reacting to events rather than obeying direct commands.
  • It is distinct from the Point-to-Point (P2P) pattern used in task queues, as Pub/Sub facilitates one-to-many communication.
  • The primary trade-off is the loss of strong consistency and atomicity, making it unsuitable for operations that must be treated as a single transaction.
  • Implementing Pub/Sub reliably requires careful consideration of delivery guarantees and designing subscribers to be idempotent to handle message retries.

Preview of the Next Lesson

We've repeatedly mentioned the term "idempotency" as a critical requirement for building reliable systems with "at-least-once" delivery. In our next lesson, we will focus squarely on this concept. We will explain idempotency and why it is critical for building reliable distributed operations, exploring patterns and techniques to ensure your asynchronous tasks can handle failures and retries gracefully without causing data corruption.