In relational databases data integrity is achieved using transactions whereas in the NoSQL world, this is referred to as strong consistency. Achieving strong consistency in a NoSQL database is more challenging, because NoSQL databases by design write to multiple replicas. And in the case of Azure Cosmos DB, these replicas can be geographically spread across multiple Microsoft data centers throughout the world.
In one Azure data center, your data is written out to multiple replicas (four at least). Consistency is all about whether or not you can be sure that the data you are reading at any point in time is – in fact – the latest version of that data, because, you can be reading from any replica at any given time. And if it’s not the latest version, then this is known as a “dirty read.”
Cosmos DB supports five consistency levels, ranging from strong to eventual. The sliding scale as shown below balances latency with availability:
On the left hand side, strong consistency guarantees you’ll never experience a dirty read, but of course, this guarantee comes with a cost, because Cosmos DB can’t permit reads until all the replicas are updated. This results in higher latency, which degrades performance.
On the other end of the spectrum, there’s eventual consistency, which offers no guarantees whatsoever, and you never know with certainty whether or not you’re reading the latest version of data. This gives Cosmos DB the freedom to serve your reads from any available replica, without having to wait for that replica to receive the latest updates from other writes. In turn, this results in the lowest latency, and delivers the best performance, at the cost of potentially experiencing dirty reads.
Strong |
Bounded Staleness |
Session |
Consistent Prefix |
Eventual |
You are always reading the latest data but
you pay for that certainty in performance. Because when somebody writes to
the database, everybody waits for Cosmos DB to acknowledge that the write was
successfully saved to all the replicas. Only then can Cosmos DB serve up
consistent reads, guaranteed. Cosmos DB actually does support strong
constency across regions, assuming that you can tolerate the high latency
that will result while replicating globally.
|
Bounded staleness is a compromise that trades delays for
strong consistency. Instead of guaranteeing that all observers have the same
data at the same time, this level allows a lag to be specified in operations
and/or time. For example, this database is configured to be at most 100
operations behind or five seconds delayed.
|
Session consistency is the default consistency level for
newly created databases and collections, and for good reasons. It is less
than half as expensive as strong consistency and bounded staleness and
provides both good performance and availability. With
session consistency, you maintain a session for your writer – or writers – by
defining a unique session key that all writers include in their requests.
Cosmos DB then uses the session key to ensure strong consistency for the
writer, meaning that a writer is always guaranteed to read the same data that
they wrote, and will never read a stale version from an out-of-date replica –
while everyone else may experience dirty reads.
|
With consistent prefix, dirty reads are
always possible. However, you do get some guarantees. First, when you do get
stale data from a dirty read, you can at least be sure that the data you get
has in fact been updated to all the replicas, even thought it’s not the most
up-to-date version of that data, which has still yet to be replicated. And
second, you’ll never experience reads out of order. For example, say the same
data gets updated four times, so there are versions A, B, C, and D, where D
is the must up to date version, and A, B, and C are stale versions. Now
assume A and B have both been replicated, but C and D haven’t yet. You can be
sure that, until C and D do get replicated, you’ll never read versions A and
B out of order. That is, you might first get version A when only A has been
replicated, and then get version B once version B has been replicated, and
then you’ll never again get version A. You can only get the stale versions in
order, so you’ll only continue getting version B until a later version gets
replicated.
|
Eventual consistency is the weakest
consistency level. It offers no guarantees whatsoever, in exchange for the
lowest latency and best performance compared to all the other consistency
levels. With eventual, you never wait for any acknowledgement that data has
been fully replicated before reading. This means that read requests can be
serviced by replicas that have already been updated, or by those that
haven’t. So you can get inconsistent results in a seemingly random fashion,
until eventually, all the replicas get updated and then all the reads become
consistent – until the next write operation, of course. So this really is the
polar opposite of strong consistency, because now there’s no guarantee that
you’re ever reading the latest data, but there’s also never any waiting,
which delivers the fastest performance.
|
Data consistency: Highest
App availability: Lowest Latency: High (bad) Throughput: Lowest Examples: Financial, inventory, scheduling |
Data consistency: High
App availability: Low Latency: High Throughput: Low Examples: Apps showing status, tracking, scores, tickers, etc. |
Data consistency: Moderate
App availability: High Latency: Moderate Throughput: Moderate Examples: Social apps, fitness apps, shopping cart |
Data consistency: Low
App availability: High Latency: Low Throughput: Moderate Examples: Social media (comments, likes), apps with updates like scores |
Data consistency: Lowest
App availability: High Latency: Low Throughput: Highest Examples: Non-ordered updates like reviews and ratings, aggregated status |