Microservices
Publish/Subscribe Model
Message Consumption
Service Type
Message Delivery

In a publish/subscribe model in microservices, how to receive/consume a message only once per service type

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

In a microservices architecture, the publish/subscribe communication model enables efficient message distribution among the various services in a system. This model facilitates asynchronous communication, where publishers send messages without needing to know who the subscribers are. Subscribers receive messages based on the topics or events they are subscribed to. A common challenge in such systems is ensuring that each message is consumed by each service type exactly once. This is crucial to prevent duplicate processing or introduce inconsistencies.

Understanding Message Delivery Semantics

Three primary types of message delivery semantics exist in distributed systems:

  1. At-most-once: Each message is delivered once or not at all. Risk of message loss.
  2. At-least-once: Messages are guaranteed delivery but might be delivered more than once, causing duplicates.
  3. Exactly-once: Each message is guaranteed to be delivered exactly once – the gold standard for many business operations but the most challenging to achieve.

Ensuring Exactly-Once Delivery in Publish/Subscribe Models

Use of Idempotence

An operation is considered idempotent if repeating it doesn’t change the result beyond the initial application. When a microservice is designed to handle idempotent operations, even if it receives a message more than once, the final state of the service remains consistent.

Example: In a banking service, instead of a message saying "add 100,"themessagecouldbe"setbalanceto100," the message could be "set balance to1,100." If this message is processed multiple times, the balance remains correct.

Deduplication Mechanisms

Implementing deduplication involves storing the identifiers of processed messages (IDs) and checking each incoming message against these IDs.

Example: A service might maintain a cache or a database table with the IDs of all messages it has processed in the last period. If a new message has an ID already in this cache, it is ignored.

Message Ordering

Ensuring that messages are processed in the order they are sent is crucial to maintaining system integrity, especially in systems requiring sequential consistency.

Example: A sequence number can be added to each message. Services process messages only in increasing order of their sequence numbers.

Using Transactions

Transactions ensure that either all operations succeed or none do. By wrapping message consumption and the business logic into a transaction, we can roll back both if something fails, preventing inconsistent states.

Example: In a distributed database, consuming a message and updating records can be part of the same transaction.

Technologies Supporting Exactly-Once Delivery

Several messaging systems provide tools and features to aid in achieving exactly-once delivery:

  • Apache Kafka: Offers exactly-once semantics through its idempotent producer and transactional APIs.
  • RabbitMQ: Utilizes publisher confirms and consumer acknowledgments to ensure messages are not lost and are processed once.
  • AWS SQS: Supports at-least-once delivery and deduplication can be implemented manually.

Challenges and Trade-offs

Achieving exactly-once delivery comes with trade-offs regarding complexity, performance, and resource usage. For instance, maintaining a deduplication cache requires additional storage and can introduce latency.

Summary Table

The following table summarizes key considerations for receiving/consuming a message only once per service type in a publish/subscribe model:

ConsiderationTechniqueDescriptionApplicable Technology
IdempotenceFunctional DesignMaking operations re-runnable without state changes after the initial run.All
DeduplicationCache/DatabaseStoring message IDs that are processed and checking new messages against them.Kafka, RabbitMQ, Custom solutions
Message OrderingSequence NumbersEnsuring messages are processed in the exact order they’re sent by using sequence numbers.Kafka, Custom solutions
TransactionsAtomic OperationsUsing transactions to wrap message consumption and business logic.Kafka, Databases

Conclusion

Achieving exactly-once delivery in a microservices environment using a publish/subscribe model is complex, requiring a combination of good design principles, proper tooling, and considerations for trade-offs. By applying idempotence, deduplication, message ordering, and transactional consistency, systems can ensure reliable and consistent message consumption across different service types.


Course illustration
Course illustration

All Rights Reserved.