The Challenges of Event-Driven Architecture: Dealing with the Dual Write Anti-Pattern
Momen Negm
Chief Technology Officer @ T-Vencubator | Digital Transformation |Consultant , Software Management, Data Scientist, Generative AI | Tech entrepreneur - Engineering leader
Contemporary applications employ Event-Driven Microservices to harness the benefits of autonomous deployment and scalability offered by Domain services while maintaining loose coupling between these services.
If your application adopts a Microservices Architecture, with each Domain service managing its own data in dedicated Datastores and communicating with other services through asynchronous means, often by emitting Domain events for activities like participating in a Saga operation (such as a long-running business transaction) or data replication across services, there is a significant likelihood that you have implemented this communication approach using the Dual Write Anti-Pattern.
When considering this pattern, whether it's something to be concerned about or not, here's a brief response for situations when you should not be concerned.
If it’s OK for your application to sometimes lose the Business domain events, causing data inconsistencies across services then you can absolutely ignore this, but if this is not the case, then you need to understand this anti-pattern well and fix it.
The Dual Write Anti-Pattern refers to a scenario in which a domain service needs to perform write operations on two distinct systems, such as data storage and event brokers, within a single logical business transaction. The goal is to achieve eventual data consistency across various services. However, there is no assurance that both data systems will always be updated successfully, or conversely, that neither will be updated during this process.
Yeah, you are thinking absolutely right — we want to achieve something like Database ACID transaction, but across 2 different kind of systems. And we cannot leverage Distributed Transaction implementation because either it is not feasible or it cannot be implemented because of inherent Scalability issues with Distributed Transaction frameworks.
Let’s understand this better with a simple use case
In the provided scenario, the business objective is quite straightforward: whenever a user publishes a Feed post, it's essential to have the Content Moderation services examine the post. If any concerns are detected, the user should receive a notification, prompting them to either delete or edit the post. The Feed Microservice is responsible for managing Feed post requests from the User Interface. It not only stores the feed post data in the Database but also triggers the publication of a FeedPosted Domain event on the Event Broker. This event serves as a signal for the Content Moderation Services to take appropriate actions.
Moreover, the developer has taken meticulous steps to ensure that this entire process appears as a unified and cohesive business transaction. The pseudocode snippet below illustrates this approach:
(Original pseudocode or implementation details can be provided if needed.)
try
{
Start DB Transaction
Write into DB
Push Event to Event Broker
Commit DB Transaction
}
catch()
{
Rollback DB Transaction
}
In the provided pseudocode, the following scenarios ensure expected behavior:
Only in the edge case, when the Database transaction commit fails (and it can very well fail by the way), the requirement is not met. Event is written to Event Broker but Data is not saved in the Database.
And this could very well lead to a User Experience or Reliability issue where the user was prompted with an error on the User Interface that Feed Post could not be saved successfully and an email was sent to the user asking to delete the post or update the post because Content Moderation service did not find the feed post appropriate.
So, what do we do now to handle the situation? One of the solution we ruled out was — leveraging Distributed Transaction. So, what next? Here are some of the possible options
领英推荐
Approach 1 — Publish the event after data is saved into the Database
In this scenario, after data has been successfully written to the database, the service tries to also write it to the Event Broker. Ideally, this works smoothly, but if it fails due to any reason, you can store the event in a persistent storage, which might even be the same database. Then, you can set up a scheduled task (like a Cron Job) to periodically retry publishing the event to the Event Broker. While this approach seems logical, it does have some drawbacks.
Approach 2 — Use Outbox Pattern
One of the recommended strategies for managing the Dual Write Anti-Pattern involves a two-step process. In this approach, a service first stores the business data in the database within a single database transaction. Simultaneously, it also records the event that needs to be published in a separate table known as the Outbox Table. This approach capitalizes on the ACID properties of the database, ensuring that the business data is saved in the database as part of a unified transaction.
However, the event intended for publication to the Event Store is not immediately published at this point. Instead, an external process is responsible for reading the records from the Outbox Table. Subsequently, it publishes the event to the Event Store. This process ultimately leads to the achievement of eventual data consistency and effectively addresses issues associated with the Dual Write problem.
With this approach -
But these benefits does not come for free
Here is a pictorial representation of this approach
There are different ways by which we can implement the Outbox pattern and some of the design level issues which one needs to think thru in terms of
In my next article, I will cover the Outbox pattern implementation in detail, including the above design decisions plus something called Change Data Capture (CDC).
Hope you enjoyed reading this article, Do share this article with your friends if this has helped you in any way.
Happy article…Cheers!!!
#Microservices #MicroservicesCommunication #MicroservicesAntiPattern #DualWriteAntiPattern #MicroservicesArchitecture #EventDrivenArchitecture
Web3 Builder & Headhunter l Helping you find the best crypto talent out there.
1 年Thanks for sharing.