Eventual Consistency in Microservices

Why Eventual Consistency is Highly Beneficial and How to Achieve It

Chameera Dulanga
Bits and Pieces

--

Microservices architecture has become a popular choice among many modern organizations looking to build highly scalable and available applications.

Although it has more advantages than traditional monolithic architecture, complexity in large-scale applications makes it difficult to maintain consistency between the services and data stores involved. That is where eventual consistency comes into play. In this article, I will discuss how eventual consistency can help to maintain data consistency across microservices using real-world examples.

What is Eventual Consistency

Eventual consistency is a technique used to maintain data consistency in distributed computing systems. It supports data consistency among replicas, regardless of network delays, partitions, or failures.

In eventual consistency, updates in one replica may not immediately propagate to all other replicas. So, all the replicas won’t have the latest data as soon as you make an update. It will eventually update all the replicas if no new updates are made to the data.

Eventual consistency ensures high availability and partition tolerance in distributed systems while helping to maintain a reasonable level of consistency. Developers often use versioning, conflict resolution, and anti-entropy protocols to implement eventual consistency in distributed systems. These techniques allow replicas to exchange information about changes made to the data and to resolve any conflicts that may arise due to those changes.

The Eventual consistency model is widely used in NoSQL databases, cloud storage systems, and microservices architectures. In this article, I will be focusing on microservices.

Strong Consistency vs Eventual Consistency

The main difference between strong and eventual consistency is the level of consistency guaranteed at any given moment. Here are some key similarities and differences between strong and eventual consistency.

Eventual Consistency

Source
  • Replicas may be temporarily out of sync but eventually converge to the same state.
  • Provides eventual consistency across all replicas.
  • Suitable systems that require high availability and partition tolerance, like social media platforms or e-commerce websites.
  • Achieved through techniques such as versioning, conflict resolution, and anti-entropy protocols.
  • High latency and complexity.

Strong Consistency

Source
  • All replicas have the same value for selected data at the same time.
  • Provides immediate consistency across all replicas.
  • Suitable systems that require immediate consistency, like financial transactions or real-time bidding platforms.
  • Achieved through protocols like 2-phase commit
  • Slower and less resilient to network failures.

Why Microservices Need Eventual Consistency?

Maintaining consistency across services and data stores while maintaining high scalability and performance is one of the biggest challenges in a microservices architecture. Eventual consistency resolves this issue by prioritizing availability and partition tolerance over immediate consistency. Using the CAP theorem, I will explain the connection between consistency, availability, and partition tolerance.

CAP Theorem

The CAP theorem is a fundamental concept in distributed systems that explains the trade-offs between Consistency, Availability, and Partition Tolerance. According to the CAP theorem, it is impossible to simultaneously ensure consistency, availability, and partition tolerance in a distributed system, and you must make trade-offs between them.

For example, if you prioritize consistency and partition tolerance, you might experience reduced availability during network partitions. Similarly, if you prioritize availability and partition tolerance, it will result in eventual consistency or conflicting data.

How Eventual Consistency Helps Microservices Architecture

In a microservices architecture, services are independent of each other and often have separate data stores for each microservice. Hence, maintaining immediate consistency between data stores would require a lot of coordination between the services, increasing the latency and reducing performance.

Eventual consistency resolves this issue by prioritising availability and partition tolerance over immediate consistency, making it perfect for microservices architecture. It allows microservices to propagate changes across different data stores asynchronously and eventually converge to a consistent state.

This approach helps microservices maintain high scalability and performance without sacrificing data consistency, which is essential in modern distributed systems.

💡 Note: Treating the microservices architecture like composable building blocks goes a long way in maintaining scalability in your system and it’s made easier with a tool like Bit which allows your teams to independently publish, version, document, test, and share individual components such as functions, UI elements, or data models, that can be reused across multiple microservices.

Learn more:

How to Achieve Eventual Consistency in Microservices

Since now you understand how eventual consistency helps microservices, let’s discuss a couple of different ways to implement eventual consistency with microservices.

Conflict Resolution Mechanisms

Conflict resolution mechanisms are used when there is a high chance of conflicting updates to the same data item in different data stores. For example, this can widely happen in e-commerce applications where multiple users update a single product simultaneously. Last-writer-wins (LWW) and vector clocks are 2 of the widely used methods in such situations to decide which version of the data should be displayed.

1. Last-writer-wins (LWW)

In the LWW approach, the most recent update is considered valid. For example, let’s consider a scenario where two users add the same item to the cart in an e-commerce application. If the first user’s write operation is timestamped later than the second user’s write operation, the version of the item added by the first user will be stored in the cart.

2. Vector clocks

The vector clock approach assigns a list of integers known as a vector clock for each data record replica. When an update is made to a data replica, the vector clock for that replica is incremented. Then, when a replica receives an update from another replica, it can compare the vector clocks to determine which version of the data is more recent.

Replication Techniques

Replication techniques are used when there is a high write throughput and a low likelihood of conflicts. Here are some of the most common replication techniques to ensure eventual consistency.

1. Master-slave replication

In this method, a single master node is responsible for writing data, and multiple slave nodes are there to read data. Hence, updates are first written to the master node and gradually propagated to the slave nodes.

2. Multi-master replication

Master-master replication treats all the nodes as master nodes. Hence, updates can be made to any node and gradually propagated to other nodes.

3. Active-active replication

Here, multiple nodes are actively serving requests, either reading or writing. All the nodes are capable of reading and writing data. Updates can be made to any node and gradually propagated to other nodes.

Examples of Eventual Consistency in Microservices

  • Amazon DynamoDB — DynamoDB is a fully managed, highly scalable NoSQL database designed for low latency and high availability. In DynamoDB, changes are immediately written to the local database. Then, the write is asynchronously propagated to other replicas.
  • Netflix: Netflix achieves high scalability and availability by combining caching, load balancing, and eventual consistency for its data stores. Netflix’s CDN uses eventual consistency to replicate content across multiple nodes, ensuring users can access the content even if some nodes are down.
  • Twitter: Twitter uses eventual consistency for its data stores to achieve high scalability and availability. When a user tweets, data is initially stored in a temporary cache. Then, eventually, data is written to the permanent data store, ensuring that the tweet is available to all users.

Apart from the above, Raik, SoundCloud, and LinkedIn are other popular companies that use eventual consistency for their applications built with microservices architecture.

Handling Transactions in Eventual Consistency

Although eventual consistency ensures high availability and partition tolerance, handling transactions can get complex due to data inconsistencies. Hence, many organizations opt out of using the eventual consistency approach for applications with heavy transactions.

However, there are methods to implement transaction-heavy applications with both microservices architecture and eventual consistency without compromising anything. For example, the SAGA pattern is a widely used design pattern in microservices architecture to handle long-running transactions. It allows you to use eventual consistency by breaking long transactions into a series of local transactions. Each local transaction is responsible for updating the state of a single service and is designed to be either fully committed or fully rolled back.

You can find how the SAGA pattern works in detail with examples in my previous article, “How to Use Saga Pattern in Microservices”.

Conclusion

Eventual consistency is an essential approach in microservices architecture to maintain high availability and scalability without sacrificing data consistency. However, it is essential to consider application requirements since some applications might require data consistency over high availability. I hope this article will help you to decide the best approach to handle data consistency for your microservices architecture. Thank you for reading.

Build Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--