A primer and a rant about eventual consistency
This is the first blog in a short series about Consistency
When I decided to start my blog again, I created a poll about what should I write first. The reason was that I have gathered material about 2-3 subjects which I liked and wanted to speak about, but I wasn’t sure which one to start with. More people voted than I expected, but the decision was a tie between what different types of events would be helpful to recognise in an Event Sourced system, and Distributed consistency.
I decided to write a bit about consistency first, which would also serve to establish some terminology before continuing on other (potentially more controversial) topics.
What is eventual consistency?
Among consistency models, eventual consistency offers one of the weakest guarantee: given a request for chang, then, in the absence of new changes, you can expect to see the impacts of those operations only after an indeterminate period of time has passed. However, While it is recognised as an independent consistency model, it is probably easy to understand that it can co-exist with other consistency models in a system and, importantly, at the same time. One such example is the “read-your-writes” consistency model, which allows for eventual consistency across writes other than your own.
It is also important to mention that eventual consistency is a consistency model which paves the way for high availability, by making the tradeoff for availability over consistency from CAP 1.
I’m not sure if this would help you, but I find it easier to think of eventual consistency as being a family of consistency models, or a characteristic instead of an actual, independent consistency model. The reason I say this is that as an independent consistency model, it makes the absolute minimum set of guarantees for distributed state, and it’s very permissive of what can happen. This makes it quite challenging to use in practical terms in the absence of stricter guarantees which can enforce a minimum of expectations for our users to rely on. In fact, frequently when I hear people use the term “Eventual Consistency”, a stricter consistency model is in fact implied, one which exhibits stricter guarantees than the absolute minimum that the eventual consistency model provides.
The below example illustrates how eventual consistency behaves:
Observations about Eventual Consistency; and it’s adoption
The most important thing to mention is that by adopting eventual consistency, some aspects of our users experience will be negatively affected. However, eventual consistency still is quite interesting, because while it may have its negatives, it does allow for high availability, which (depending on the domain) may be vastly more important than any inconvenience which may be introduced when we adopt eventual consistency. In fact, its support towards high availability makes it more than just an option, but an actual requirement for some classes of problems and systems.
On the subject, there is one thing that I was just dying to say, and that is about the mentality and disposition which some people have against eventual consistency. If you read y-combinator posts (and even worse, some of the comments there), or Medium articles you’ll undoubtedly come across quite a large number of people advising against adopting eventual consistency. The popular rhetoric starts with teams adopting Event Sourcing and CQRS (some patterns which we’ll visit in this blog in due time) and failing in no small part due to Eventual Consistency.
Now I won’t go into CQRS-specific options\comments, but what I will say is that from personal experience, a lot (but not all) of these problems stem from other aspects of each systems design, and are not inherent to Eventual Consistency. Instead they are mostly introduced by wrong system and transactional boundaries which exacerbate the negative tradeoffs of eventual consistency (most often by compounding those) to such an extent that they become a problem. In other words, I’m saying that systems which benefit from being distributed are inherently complex and exhibit complex problems. Unless we purposely design, and do that well, we run an increased risk of introducing complex bugs, which may involve eventual consistency in some parts. And this has been most of those peoples experience: they took a simple, synchronous, well-designed, non-distributed system, and tried to replicate it as an asynchronous, distributed one without going through the learning process required of the product team. Fundamentally, they’re facing a learning and mentality problem, not a technical one.
In summary, I strongly believe, and it has been my personal experience as well, that eventual consistency allows for a significantly simpler systems from implementation and maintenance perspective, assuming the system needs to be distributed.
Common misunderstandings ← the “ranty” bits
Now that we’ve seen the definition, a small analysis, and an example of eventual consistency, I’d like to go over some common misconceptions about eventual consistency.
1. “Even electrons need time to travel, so even assigning a variable is eventually consistent”, and other examples which imply all operations take time
I’ve seen countless permutations of this argument. “Even if you write on paper, light takes time to travel to your eyes”, for example, and other similar ones, some specific to the domain at hand.
NOTE: There exists some truth, and relevance, to some of these arguments, but not in the obvious way. For example, once I’ve heard that “even writing to RAM is eventually consistent”. Well… That may be technically true because, for soft-write memory models, writes will stay in cache. This doesn’t happen in x86 architecture, (although it may still exhibit eventual consistency due to defaulting to soft reads) but it does happen in some other CPU architectures which employ a soft memory model.
Why isn’t this true then? Well, it’s not true because the time taken for the information to travel between the system and you is unimportant to the consistency model. What is of importance, is the ordering of operations, and how long they can take before completion.
The time taken by light to reach your eyes, or a query to reach your PC across half the globe, are not part of the definition here. So long as you can query the value and see what you wrote, immediately after you wrote it, and at any time later (in the absence of further operations) then you aren’t eventually consistent, but have a stronger form of consistency.
2. “Everything is eventually consistent anyway”
No, not everything is eventually consistent. Linearizability is achievable, and by definition it is a stronger consistency model than eventual consistency. It does require locking over data and synchronisation across servers, it does require preferring unavailability in the face of partitions, and it does include the risk of unavailability due to locking required by the transactions mentioned earlier, but it is achievable.
That means that while it may not be a good option for systems which need to exhibit high availability, but it is doable and much stricter than eventual consistency.
3. “Strict consistency is impossible”
This statement is true, but at the same time, it’s in my list of misconceptions and rants because of what is implied when people use it in support of Eventual Consistency. I may go over why strict consistency isn’t possible in another article 2, but for now, I’ll ask you please to just accept the word of Wikipedia on the matter.
What is implied is that there are only two forms of consistency: strict (sometimes people use the term “immediate”), and eventual. And because strict consistency is impossible, you’re left with just eventual consistency, so you better accept it! This is of course not true: there are multiple consistency levels, which are clearly defined, studied, documented and exhibit different tradeoffs, each useful in different circumstances. It makes a lot of sense to know their guarantees, recognise which one we need, and how to apply and implement each correctly.
Eventual consistency is useful
With this article, I hope you have a better understanding of what eventual consistency is and what it’s trade offs are, and I sincerely hope that I piqued your interest on this subject. In future articles, when I refer to eventual consistency, I’ll be referring to it as described above, and probably linking here.
Thank you for reading.
- 1 The CAP Theorem: The CAP theorem states that you cannot have linearizable consistency in the face of partitions. I very strongly suggest you read the paper in the further reading material list below
- 2 Strong consistency: Tbh, I do not find a lot of reasons to expand on the strong consistency model because in it’s formal definition is so strict which makes it useful only in entirely theoretical contexts, and what Wikipedia has on the matter seems to be all that need to be said about strong consistency.