Consistency Levels in a Database System

Sindhura Venkatesh
Designing distributed systems
5 min readJan 2, 2020

In a previous post, we learned about Isolation levels and how they affect the performance of a database system. Now let’s talk about another factor that is extremely important in designing database systems: Consistency level. Similar to Isolation levels, Consistency levels also affect “at what time a particular write can be seen/read.” They too, have to be chosen carefully based on the level of correctness and performance desired. However, Consistency and Isolation are often confused, even though there are some distinct differences between them. Let’s first learn what Consistency is and then delve into the differences between consistency and isolation in a future post.

What is Consistency?

In a Distributed System, consistency means that “all reads executed at a given time must return the same result irrespective of the server that executed the read.” For one server to read the data written by another server, we need to maintain a global ordering of reads and writes. So that each copy of the database will execute the events in the same order, and they will all result in the same final database state. Therefore, our data will be consistent.

The consistency levels differ in the way they implement this ordering of events. Some are strict, w.r.t maintaining a time-based order while others are more relaxed. We’ll learn about each one of them below.

Consistency Levels

Sequential Consistency: All writes must be globally ordered. Each thread of execution must see the same ordering of writes, irrespective of which thread executed and which data items were written to. However, this ordering needn’t be the same as the real-time ordering of writes. We can have any ordering of writes, as long as such an ordering is agreed upon by all the threads.

Figure 1: sequentially consistent

Threads 3 and 4 see that B has been updated before A (which is different from what actually happened), but this is still considered sequentially consistent as all the threads are in agreement.

Figure 2: Not sequentially consistent

In the above image, thread 3 sees the update to B before the update to A, while thread 4 sees the update to A first. This violates sequential consistency.

Strict Consistency: This is the highest level of consistency. Strict Consistency requires events to be ordered in the same real-time sequence in which they occurred. In other words, “an earlier write always has to be seen before a later write.” This is almost impossible to implement in distributed systems. Hence it remains in the realm of theoretical discussions.

Strict Consistency also demands that any write by a given thread should be immediately visible to all other threads. Hence the above two images do not satisfy strict consistency, as they read zero values from data items that were already written to.

Figure 3: Strictly Consistent

The above image satisfies strict consistency as immediate subsequent reads see the new value of the data item.

Linearizability/ Atomic Consistency: Although strict consistency is very hard to achieve, we can come pretty close to it. Linearizability also requires the writes to be ordered in a real-time fashion, but it acknowledges that there’s some time gap between when an operation is submitted to the system and when the system acknowledges it.

If another write has started executing before the earlier write has been completed, then the two writes are considered overlapping and hence there needn’t be a real-time ordering between them. Only non-overlapping writes need to be ordered in a real-time sequence.

Figure 4: Linearizable but not strictly consistent

The write of thread 1 overlaps with the read of thread 3. Therefore, there needn’t be a real-time ordering between them. Hence the above image satisfies Linearizability even though thread three’s read doesn’t fetch the latest value.

The levels discussed above are usually considered to be strong consistency levels. The weaker consistency levels, which we’ll discuss further, don’t place as strict a constraint on the order of operations.

Causal Consistency: Causal Consistency requires only related operations to have a global ordering between them. Two operations can be related because they acted on the same data item, or because they originated from the same thread. Operations that are not related can be seen in any order by any thread. Causal consistency is a weaker form of sequential consistency.

Figure 5: Causally consistent

The write to B by thread 2 follows the read from A. Hence these two operations are causally related. Hence, the write to A must appear before the write to B. Figure 5 is causally consistent since threads 3 and 4 see the writes in the same order.

Eventual Consistency: This can be called the weakest level of consistency. The only guarantee offered here is that if there are no writes for a long period of time, the threads will eventually agree on the value of the last write. That is, eventually, all the copies of the database will reflect the same value.

Figure 6: Eventually consistent

The above figure violates all consistency levels except eventual consistency. If there isn’t any other write for a long time, all the threads will see the same value of A and B.

We got a quick 101 on different consistency levels, the guarantees they offer, and the requirements in implementing them. Hopefully, this post helped in making your tech life much easier! Watch out for most posts and DBMSes and Distributed Systems.

--

--