System Design Basics: Pub/Sub Messaging
Publisher/subscriber messaging, or pub/sub messaging, is a form of asynchronous service-to-service communication used in serverless and microservices architectures. In a pub/sub model, any message published to a topic is immediately received by all of the subscribers to the topic. Pub/sub messaging can be used to enable event-driven architectures, or to decouple applications in order to increase performance, reliability and scalability.
Problems with Request-Response Architecture
Request-Response architecture is the most popular and common messaging system employed when making network calls. ReST is one of the most common form of messaging system used in distributed systems. The client makes a Request which is serviced by the server to provide a Response.
The problem arises as the distributed architecture gets complex. Introduction of multiple services creates a chain of strongly connected components. This increases the latency and wait time, and failure in one component leads to a failure in all systems.
For example, let’s say we have a video uploader service for Instagram reels. You have an upload service, a compressor service, formatter service and notification service, all of which make network calls using Request-Response architecture. The user uploads a video which is handled by the uploader service. The uploader service then triggers a compressor service that’s responsible for compressing the raw video. The formatter service then formats the video using the filters, music etc. selected by the user. The notification service then provides a notification to the end user that the upload is successful.
If these systems interact using request-response messaging, it would lead to a complex graph of connected components as the system evolves. The user has to wait till each service processes the request and provides a response. This would increase latency. The system would also not be fault tolerant as a failure in any one of the services would lead to failure in the entire chain.
Event Driven Architecture
Event Driven Architecture was designed to solve the above problem. We could make the system loosely coupled by using events to deal with exchange of information. An Event is a change in state, or an update, like an item being placed in a shopping cart on an e-commerce website. Events can either carry the state (the item purchased, its price, and a delivery address) or events can be identifiers (a notification that an order was shipped).
Event-driven architectures have three key components: event producers, event routers, and event consumers. A producer publishes an event to the message router, which filters and pushes the events to consumers. Producer services and consumer services are decoupled, which allows them to be scaled, updated, and deployed independently.
Using this architecture we can scale each component individually and make them fault tolerant. Since the messages are async we don’t have to wait for response from downstream services.
A Message Router, or a Message Broker(also called Topics in Kafka), is software that enables applications, systems, and services to communicate with each other and exchange information. The message broker does this by translating messages between formal messaging protocols. This allows interdependent services to “talk” with one another directly, even if they were written in different languages or implemented on different platforms.
Publisher Subscriber Messaging, also known as Publisher Subscriber pattern, is a messaging pattern that provides a framework for exchanging messages. It also allows for loose coupling and scaling between the sender of messages (publishers) and receivers (subscribers) on messaging brokers they subscribe to. Some of the common technologies using Pub/Sub Messaging are RabbitMQ, Kafka, Redis etc.
Messages are sent from a publisher to subscribers as they become available. Publishers are services that send messages to the message broker. The subscribers then subscribe to message brokers they’re interested in to listen these messages (similar to how a user subscribes to a channel on YouTube).
Pub Sub systems are widely used in use-cases where we need loosely coupled/decoupled components that are needed to be scaled individually. eg: Event Notification, Distributed Caching, Distributed Logging etc. These are mentioned in detail here.
Pros and Cons of Pub-Sub Messaging
Pub/sub messaging has the following benefits:
- It decouples subsystems that still need to communicate. Subsystems can be managed independently, and messages can be properly managed even if one or more receivers are offline. This helps applications continue to run smoothly under increased loads and handle intermittent failures more effectively.
- It increases scalability and improves responsiveness of the sender. The sender can quickly send a single message to the input channel, then return to its core processing responsibilities. The messaging infrastructure is responsible for ensuring messages are delivered to interested subscribers.
- It allows for deferred or scheduled processing. Subscribers can wait to pick up messages until off-peak hours, or messages can be routed or processed according to a specific schedule.
- It facilitates asynchronous workflows across an enterprise.
However, decoupling of components and async transfer of messages also leads to some downsides. Some of them are:
- uni-directional communication: The channels in a publish-subscribe system are treated as unidirectional. We do not send an acknowledgement/reply back to the publisher once the messages are subscribed.
- Lack of Message ordering: The order in which consumer instances receive messages isn’t guaranteed, and doesn’t necessarily reflect the order in which the messages were created.
- No Idempotency: We need to configure extra logic in our applications to handle idempotency. For example, If a payment service reads two messages for the same payment then the user ends up getting charged twice for the same transaction. Similarly, the message for a transaction might expire before it’s subscribed, and the user might not be charged for the transaction.
- Over-utilisation/Underutilisation of resources: There is underutilisation/over-utilisation of resources unless the channels/topics are very efficiently designed.
Pub-Sub messaging provides an edge when there are decoupled/loosely connected components in a system (like gaming, distributed caching etc.). They are also very useful in cases where we need many consumers subscribing to a single publisher(unidirectional systems).
But this pattern has several disadvantages as well for use-cases where reliability, idempotency and resource utilisation is of a higher priority. So a call should be taken when designing systems and use it for messaging only in scenarios where the pros outweigh the cons.
Thanks for reading!
- Azure Cloud: https://docs.microsoft.com/en-us/dotnet/architecture/dapr-for-net-developers/publish-subscribe
- Google Developers: https://www.youtube.com/watch?v=cvu53CnZmGI
- Hussein Nasser: https://www.youtube.com/watch?v=O1PgqUqZKTA
- Gaurav Sen: https://www.youtube.com/watch?v=FMhbR_kQeHw