In our previous blog (Introduction to Azure Cosmos DB), we gave you a detailed introduction to Azure Cosmos DB!
In this blog, we will be discussing the different consistency levels provided by Azure Cosmos DB and how each of them can be used in different scenarios to make an optimal tradeoff between consistency, latency and, throughput.
For the duration of this article, let’s say that a sports channel is broadcasting a live football match all around the world. To avoid latency to its users, it has deployed replications of its main server (currently deployed in North America) across all major continents. At 7:03:51 PM, the scores between the two teams are tied at 2-2. Team A scores a goal to make it 3-2 at 7:03:55 PM. The score is updated immediately in the main server and, this update will be rippled through all the replications.
With that premise in mind, we first need to go through some important terms related to consistency model of Azure Cosmos DB:
Latency is simply the time it takes for a server to respond to a request made by a user. If the user and the server are in closer proximity, it will take lesser time to cater to the user request, as opposed to the user and the server being in different hemispheres altogether.
In terms of a server or a database, throughput defines the number of transactions or operations performed in unit time. For example, a server that performs 20 read operations per second is twice as faster as a server that performs 10 read operations per second.
In the context of data replication, consistency refers to the principle that multiple copies of the same database should always return the same data if they are accessed simultaneously.
If we continue with our broadcasting example, consistency demands that the users all around the world should see the same score, i.e., 3-2, at 7:03:55 PM. If the users in North America get the updated score of 3-2 at 7:03:55 PM, whereas, the users in Australia are still getting 2-2, then we say that this is weak consistency. Weak consistency occurs when there is a lag between the update in the primary database and its subsequent replications.
Tradeoff between Consistency, Latency, and Throughput
From our discussions above, we can easily assume that Strong Consistency and Lower Latency are desirable in any database. However, they both seldom go together due to their intrinsic differences. Lower Latency demands more replications, consequently making it harder to keep the state of the databases consistent with each other. To achieve both, we can always increase the throughput of the system, but it’s a costly option. We must make tradeoffs between consistency, latency, and throughput according to the use cases of the business. In the example above, we need live updates all around the world, so we can’t compromise on either consistency or latency. Hence, we must opt for a higher throughput, which comes at a hefty price.
Now that we have declared a premise for our discussion, let’s look at each of the Consistency Levels provided by Azure Cosmos DB:
Also referred to as Linearizability, Strong Consistency guarantees that only the most recent committed version of the data will be returned. Committed version means that the data has been permanently saved into the database, rather than tentative changes.
Strong consistency is used when we can’t compromise the user seeing tentative or outdated changes to the data. For example, if the result of a match is to be announced, the announcer must have the most recent committed version of the score so that he doesn’t announce the wrong winner.
To understand Bounded Staleness, think of write operations analogous to links in a chain. If 5 independent write operations are performed on a database, they will be carried out one by one and committed. When these 5 write operations are completed on the primary database, they will also be replicated to the secondary databases.
In a strongly consistent model, we will only read the most recent committed write operation, even if we have higher latency. However, if we don’t want to compromise on latency, we can read data from secondary databases, even if it is not the most recent version. Bounded Staleness gives us the guarantee to put a bound on the committed version to be read. More specifically, we can choose the oldest committed write operation that we can afford to read depending upon the criticality of the business use case.
In our example of 5 write operations, we may be willing to compromise on NOT getting the most recent write, that is the 5th write, but we don’t want to read the writes before the 3rd write. In other words, we can afford a lag of 3 write operations, but no more than that. We can also define the bound in terms of time. For example, we can afford to read a database that is at most 5 seconds old.
If we go back to our broadcasting example, we can afford the public viewers not getting the latest data. They can get a 5 to 10 seconds delay in it, which will save us costs in terms of lesser throughput.
This is the default consistency level for Azure Cosmos DB, and very easy to understand as well. It simply guarantees that the writer of the data will see the most recent version. All other users will have eventual consistency set for them.
In our broadcasting example, there will be a person who is responsible for updating the score. If he updates the score, he should be able to see the updated score. Otherwise, he could end up updating the score again. The session can also be easily understandable through Facebook. When you comment on a post, you can see it immediately, even though it may not have been committed to all the replications yet. If they don’t use a session, you may not see your comment right away, and end up commenting again and again.
This is one of the weaker consistency levels in Cosmos DB. It doesn’t ensure that you will read the recent committed versions, but it does guarantee that you won’t see out-of-order data. To understand out-of-order data, let’s again review the case when 5 writes were made in a short period. The writes will be replicated to the secondary databases, but they may not always be replicated in the same order as they were written.
For example, if the current score is -1-1, and team A and B score a goal in quick succession. The score now becomes 2-2. What’s important is that the score went from 1-1 to 2-1, and then 2-2. The writes are also performed in that manner. However, the replication may be out-of-order and some secondary databases may have a tentative score of 1-2, even though there was never a point in the match where the score was 1-2. Hence, this qualifies as false information. Consistent Prefix helps us rectify the situation and guarantees that the reads will always be in order. If Consistent Prefix is set, the users can either see 1-1, 2-1, or 2-2 because it doesn’t guarantee the most recent result, but they will never see 1-2, which is a false result anyway.
This consistency level is the weakest of the lot. It doesn’t guarantee anything other than this:
Given a significant amount of time when no writes occur, all the replications of the database will eventually be consistent with each other.
This consistency level is ideal for the scenarios where we are in no hurry to get the latest results. Hence, we can save costs on throughput. In our broadcasting example, if there are some sports analysts that host late-night shows to discuss the matches, they will have plenty of time to see the results of the match. Hence, Eventual Consistency will be an ideal case with this use case. This is a cost-effective option, yet it also suffers the least latency, which is another plus.
In this article, we talked about different consistency levels provided by Azure Cosmos DB and how each of them can be used in different scenarios to make an optimal tradeoff between consistency, latency and, throughput.
In the next article, we will look at the different APIs provided by Cosmos DB to store and query data in a flexible manner. If you have any questions or insights regarding the consistency model in Azure Cosmos DB, feel free to leave a comment below!