Files
nexus/sreweekly/articles/178/01-the-dangers-of-conditional-consistency-guarantees.html
2026-09-12 17:23:01 +08:00

1706 lines
68 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html class='v2' dir='ltr' lang='en'>
<head>
<link href='https://www.blogger.com/static/v1/widgets/2872013778-css_bundle_v2.css' rel='stylesheet' type='text/css'/>
<meta content='width=1100' name='viewport'/>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/>
<meta content='blogger' name='generator'/>
<link href='http://dbmsmusings.blogspot.com/favicon.ico' rel='icon' type='image/x-icon'/>
<link href='http://dbmsmusings.blogspot.com/2019/07/the-dangers-of-conditional-consistency.html' rel='canonical'/>
<link rel="alternate" type="application/atom+xml" title="DBMS Musings - Atom" href="http://dbmsmusings.blogspot.com/feeds/posts/default" />
<link rel="alternate" type="application/rss+xml" title="DBMS Musings - RSS" href="http://dbmsmusings.blogspot.com/feeds/posts/default?alt=rss" />
<link rel="service.post" type="application/atom+xml" title="DBMS Musings - Atom" href="https://www.blogger.com/feeds/8899645800948009496/posts/default" />
<link rel="alternate" type="application/atom+xml" title="DBMS Musings - Atom" href="http://dbmsmusings.blogspot.com/feeds/6521959894959786533/comments/default" />
<!--Can't find substitution for tag [blog.ieCssRetrofitLinks]-->
<meta content='http://dbmsmusings.blogspot.com/2019/07/the-dangers-of-conditional-consistency.html' property='og:url'/>
<meta content='The dangers of conditional consistency guarantees' property='og:title'/>
<meta content='The ease of writing an application on top of infrastructure that guarantees consistency can not be overstated . It’s just so much easier to ...' property='og:description'/>
<title>DBMS Musings: The dangers of conditional consistency guarantees</title>
<style id='page-skin-1' type='text/css'><!--
/*
-----------------------------------------------
Blogger Template Style
Name: Ethereal
Designer: Jason Morrow
URL: jasonmorrow.etsy.com
----------------------------------------------- */
/* Content
----------------------------------------------- */
body {
font: normal normal 13px Arial, Tahoma, Helvetica, FreeSans, sans-serif;
color: #666666;
background: #fb5e53 url(https://resources.blogblog.com/blogblog/data/1kt/ethereal/birds-2toned-bg.png) repeat-x scroll top center;
}
html body .content-outer {
min-width: 0;
max-width: 100%;
width: 100%;
}
a:link {
text-decoration: none;
color: #2198a6;
}
a:visited {
text-decoration: none;
color: #4d469c;
}
a:hover {
text-decoration: underline;
color: #2198a6;
}
.main-inner {
padding-top: 15px;
}
.body-fauxcolumn-outer {
background: transparent none repeat-x scroll top center;
}
.content-fauxcolumns .fauxcolumn-inner {
background: #ffffff url(https://resources.blogblog.com/blogblog/data/1kt/ethereal/bird-2toned-blue-fade.png) repeat-x scroll top left;
border-left: 1px solid #fb5e53;
border-right: 1px solid #fb5e53;
}
/* Flexible Background
----------------------------------------------- */
.content-fauxcolumn-outer .fauxborder-left {
width: 100%;
padding-left: 300px;
margin-left: -300px;
background-color: transparent;
background-image: url(//themes.googleusercontent.com/image?id=0BwVBOzw_-hbMNjViMzQ0ZDEtMWU1NS00ZTBkLWFjY2EtZjM5YmU4OTA2MjBm);
background-repeat: no-repeat;
background-position: left top;
}
.content-fauxcolumn-outer .fauxborder-right {
margin-right: -299px;
width: 299px;
background-color: transparent;
background-image: url(//themes.googleusercontent.com/image?id=0BwVBOzw_-hbMNjViMzQ0ZDEtMWU1NS00ZTBkLWFjY2EtZjM5YmU4OTA2MjBm);
background-repeat: no-repeat;
background-position: right top;
}
/* Columns
----------------------------------------------- */
.content-inner {
padding: 0;
}
/* Header
----------------------------------------------- */
.header-inner {
padding: 27px 0 3px;
}
.header-inner .section {
margin: 0 35px;
}
.Header h1 {
font: normal normal 60px Times, 'Times New Roman', FreeSerif, serif;
color: #ff8b8b;
}
.Header h1 a {
color: #ff8b8b;
}
.Header .description {
font-size: 115%;
color: #666666;
}
.header-inner .Header .titlewrapper,
.header-inner .Header .descriptionwrapper {
padding-left: 0;
padding-right: 0;
margin-bottom: 0;
}
/* Tabs
----------------------------------------------- */
.tabs-outer {
position: relative;
background: transparent;
}
.tabs-cap-top, .tabs-cap-bottom {
position: absolute;
width: 100%;
}
.tabs-cap-bottom {
bottom: 0;
}
.tabs-inner {
padding: 0;
}
.tabs-inner .section {
margin: 0 35px;
}
*+html body .tabs-inner .widget li {
padding: 1px;
}
.PageList {
border-bottom: 1px solid #fb5e53;
}
.tabs-inner .widget li.selected a,
.tabs-inner .widget li a:hover {
position: relative;
-moz-border-radius-topleft: 5px;
-moz-border-radius-topright: 5px;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-goog-ms-border-top-left-radius: 5px;
-goog-ms-border-top-right-radius: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
background: #ffa183 none ;
color: #ffffff;
}
.tabs-inner .widget li a {
display: inline-block;
margin: 0;
margin-right: 1px;
padding: .65em 1.5em;
font: normal normal 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif;
color: #666666;
background-color: #ffdfc7;
-moz-border-radius-topleft: 5px;
-moz-border-radius-topright: 5px;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-goog-ms-border-top-left-radius: 5px;
-goog-ms-border-top-right-radius: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
/* Headings
----------------------------------------------- */
h2 {
font: normal bold 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif;
color: #666666;
}
/* Widgets
----------------------------------------------- */
.main-inner .column-left-inner {
padding: 0 0 0 20px;
}
.main-inner .column-left-inner .section {
margin-right: 0;
}
.main-inner .column-right-inner {
padding: 0 20px 0 0;
}
.main-inner .column-right-inner .section {
margin-left: 0;
}
.main-inner .section {
padding: 0;
}
.main-inner .widget {
padding: 0 0 15px;
margin: 20px 0;
border-bottom: 1px solid #dbdbdb;
}
.main-inner .widget h2 {
margin: 0;
padding: .6em 0 .5em;
}
.footer-inner .widget h2 {
padding: 0 0 .4em;
}
.main-inner .widget h2 + div, .footer-inner .widget h2 + div {
padding-top: 15px;
}
.main-inner .widget .widget-content {
margin: 0;
padding: 15px 0 0;
}
.main-inner .widget ul, .main-inner .widget #ArchiveList ul.flat {
margin: -15px -15px -15px;
padding: 0;
list-style: none;
}
.main-inner .sidebar .widget h2 {
border-bottom: 1px solid #dbdbdb;
}
.main-inner .widget #ArchiveList {
margin: -15px 0 0;
}
.main-inner .widget ul li, .main-inner .widget #ArchiveList ul.flat li {
padding: .5em 15px;
text-indent: 0;
}
.main-inner .widget #ArchiveList ul li {
padding-top: .25em;
padding-bottom: .25em;
}
.main-inner .widget ul li:first-child, .main-inner .widget #ArchiveList ul.flat li:first-child {
border-top: none;
}
.main-inner .widget ul li:last-child, .main-inner .widget #ArchiveList ul.flat li:last-child {
border-bottom: none;
}
.main-inner .widget .post-body ul {
padding: 0 2.5em;
margin: .5em 0;
list-style: disc;
}
.main-inner .widget .post-body ul li {
padding: 0.25em 0;
margin-bottom: .25em;
color: #666666;
border: none;
}
.footer-inner .widget ul {
padding: 0;
list-style: none;
}
.widget .zippy {
color: #cccccc;
}
/* Posts
----------------------------------------------- */
.main.section {
margin: 0 20px;
}
body .main-inner .Blog {
padding: 0;
background-color: transparent;
border: none;
}
.main-inner .widget h2.date-header {
border-bottom: 1px solid #dbdbdb;
}
.date-outer {
position: relative;
margin: 15px 0 20px;
}
.date-outer:first-child {
margin-top: 0;
}
.date-posts {
clear: both;
}
.post-outer, .inline-ad {
border-bottom: 1px solid #dbdbdb;
padding: 30px 0;
}
.post-outer {
padding-bottom: 10px;
}
.post-outer:first-child {
padding-top: 0;
border-top: none;
}
.post-outer:last-child, .inline-ad:last-child {
border-bottom: none;
}
.post-body img {
padding: 8px;
}
h3.post-title, h4 {
font: normal normal 24px Times, Times New Roman, serif;
color: #2198a6;
}
h3.post-title a {
font: normal normal 24px Times, Times New Roman, serif;
color: #2198a6;
text-decoration: none;
}
h3.post-title a:hover {
color: #2198a6;
text-decoration: underline;
}
.post-header {
margin: 0 0 1.5em;
}
.post-body {
line-height: 1.4;
}
.post-footer {
margin: 1.5em 0 0;
}
#blog-pager {
padding: 15px;
}
.blog-feeds, .post-feeds {
margin: 1em 0;
text-align: center;
}
.post-outer .comments {
margin-top: 2em;
}
/* Comments
----------------------------------------------- */
.comments .comments-content .icon.blog-author {
background-repeat: no-repeat;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9sLFwMeCjjhcOMAAAD+SURBVDjLtZSvTgNBEIe/WRRnm3U8RC1neQdsm1zSBIU9VVF1FkUguQQsD9ITmD7ECZIJSE4OZo9stoVjC/zc7ky+zH9hXwVwDpTAWWLrgS3QAe8AZgaAJI5zYAmc8r0G4AHYHQKVwII8PZrZFsBFkeRCABYiMh9BRUhnSkPTNCtVXYXURi1FpBDgArj8QU1eVXUzfnjv7yP7kwu1mYrkWlU33vs1QNu2qU8pwN0UpKoqokjWwCztrMuBhEhmh8bD5UDqur75asbcX0BGUB9/HAMB+r32hznJgXy2v0sGLBcyAJ1EK3LFcbo1s91JeLwAbwGYu7TP/3ZGfnXYPgAVNngtqatUNgAAAABJRU5ErkJggg==);
}
.comments .comments-content .loadmore a {
background: #ffffff url(https://resources.blogblog.com/blogblog/data/1kt/ethereal/bird-2toned-blue-fade.png) repeat-x scroll top left;
}
.comments .comments-content .loadmore a {
border-top: 1px solid #dbdbdb;
border-bottom: 1px solid #dbdbdb;
}
.comments .comment-thread.inline-thread {
background: #ffffff url(https://resources.blogblog.com/blogblog/data/1kt/ethereal/bird-2toned-blue-fade.png) repeat-x scroll top left;
}
.comments .continue {
border-top: 2px solid #dbdbdb;
}
/* Footer
----------------------------------------------- */
.footer-inner {
padding: 30px 0;
overflow: hidden;
}
/* Mobile
----------------------------------------------- */
body.mobile {
background-size: auto
}
.mobile .body-fauxcolumn-outer {
background: ;
}
.mobile .content-fauxcolumns .fauxcolumn-inner {
opacity: 0.75;
}
.mobile .content-fauxcolumn-outer .fauxborder-right {
margin-right: 0;
}
.mobile-link-button {
background-color: #ffa183;
}
.mobile-link-button a:link, .mobile-link-button a:visited {
color: #ffffff;
}
.mobile-index-contents {
color: #444444;
}
.mobile .body-fauxcolumn-outer {
background-size: 100% auto;
}
.mobile .mobile-date-outer {
border-bottom: transparent;
}
.mobile .PageList {
border-bottom: none;
}
.mobile .tabs-inner .section {
margin: 0;
}
.mobile .tabs-inner .PageList .widget-content {
background: #ffa183 none;
color: #ffffff;
}
.mobile .tabs-inner .PageList .widget-content .pagelist-arrow {
border-left: 1px solid #ffffff;
}
.mobile .footer-inner {
overflow: visible;
}
body.mobile .AdSense {
margin: 0 -10px;
}
--></style>
<style id='template-skin-1' type='text/css'><!--
body {
min-width: 1310px;
}
.content-outer, .content-fauxcolumn-outer, .region-inner {
min-width: 1310px;
max-width: 1310px;
_width: 1310px;
}
.main-inner .columns {
padding-left: 0;
padding-right: 350px;
}
.main-inner .fauxcolumn-center-outer {
left: 0;
right: 350px;
/* IE6 does not respect left and right together */
_width: expression(this.parentNode.offsetWidth -
parseInt("0") -
parseInt("350px") + 'px');
}
.main-inner .fauxcolumn-left-outer {
width: 0;
}
.main-inner .fauxcolumn-right-outer {
width: 350px;
}
.main-inner .column-left-outer {
width: 0;
right: 100%;
margin-left: -0;
}
.main-inner .column-right-outer {
width: 350px;
margin-right: -350px;
}
#layout {
min-width: 0;
}
#layout .content-outer {
min-width: 0;
width: 800px;
}
#layout .region-inner {
min-width: 0;
width: auto;
}
body#layout div.add_widget {
padding: 8px;
}
body#layout div.add_widget a {
margin-left: 32px;
}
--></style>
<!-- Google tag (gtag.js) -->
<script async='true' src='https://www.googletagmanager.com/gtag/js?id=G-WPSPKTZ8VQ'></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-WPSPKTZ8VQ');
</script>
<link href='https://www.blogger.com/dyncss/8899645800948009496/authorization.css?zx=64628a2a-8581-41e2-b103-b6627e610902' media='none' onload='if(media!=&#39;all&#39;)media=&#39;all&#39;' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyncss/8899645800948009496/authorization.css?zx=64628a2a-8581-41e2-b103-b6627e610902' rel='stylesheet'/></noscript>
<meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/>
<meta name='google-adsense-platform-domain' content='blogspot.com'/>
</head>
<body class='loading variant-hummingBirds2'>
<div class='navbar section' id='navbar' name='Navbar'><div class='widget Navbar' data-version='1' id='Navbar1'><script type="text/javascript">
function setAttributeOnload(object, attribute, val) {
if(window.addEventListener) {
window.addEventListener('load',
function(){ object[attribute] = val; }, false);
} else {
window.attachEvent('onload', function(){ object[attribute] = val; });
}
}
</script>
<div id="navbar-iframe-container"></div>
<script type="text/javascript" src="https://apis.google.com/js/platform.js"></script>
<script type="text/javascript">
gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() {
if (gapi.iframes && gapi.iframes.getContext) {
gapi.iframes.getContext().openChild({
url: 'https://www.blogger.com/navbar/8899645800948009496?po\x3d6521959894959786533\x26origin\x3dhttp://dbmsmusings.blogspot.com',
where: document.getElementById("navbar-iframe-container"),
id: "navbar-iframe"
});
}
});
</script><script type="text/javascript">
(function() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '//pagead2.googlesyndication.com/pagead/js/google_top_exp.js';
var head = document.getElementsByTagName('head')[0];
if (head) {
head.appendChild(script);
}})();
</script>
</div></div>
<div class='body-fauxcolumns'>
<div class='fauxcolumn-outer body-fauxcolumn-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</div>
<div class='content'>
<div class='content-fauxcolumns'>
<div class='fauxcolumn-outer content-fauxcolumn-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</div>
<div class='content-outer'>
<div class='content-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left content-fauxborder-left'>
<div class='fauxborder-right content-fauxborder-right'></div>
<div class='content-inner'>
<header>
<div class='header-outer'>
<div class='header-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left header-fauxborder-left'>
<div class='fauxborder-right header-fauxborder-right'></div>
<div class='region-inner header-inner'>
<div class='header section' id='header' name='Header'><div class='widget Header' data-version='1' id='Header1'>
<div id='header-inner'>
<div class='titlewrapper'>
<h1 class='title'>
<a href='http://dbmsmusings.blogspot.com/'>
DBMS Musings
</a>
</h1>
</div>
<div class='descriptionwrapper'>
<p class='description'><span>
</span></p>
</div>
</div>
</div></div>
</div>
</div>
<div class='header-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</header>
<div class='tabs-outer'>
<div class='tabs-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left tabs-fauxborder-left'>
<div class='fauxborder-right tabs-fauxborder-right'></div>
<div class='region-inner tabs-inner'>
<div class='tabs no-items section' id='crosscol' name='Cross-Column'></div>
<div class='tabs no-items section' id='crosscol-overflow' name='Cross-Column 2'></div>
</div>
</div>
<div class='tabs-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<div class='main-outer'>
<div class='main-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left main-fauxborder-left'>
<div class='fauxborder-right main-fauxborder-right'></div>
<div class='region-inner main-inner'>
<div class='columns fauxcolumns'>
<div class='fauxcolumn-outer fauxcolumn-center-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<div class='fauxcolumn-outer fauxcolumn-left-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<div class='fauxcolumn-outer fauxcolumn-right-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<!-- corrects IE6 width calculation -->
<div class='columns-inner'>
<div class='column-center-outer'>
<div class='column-center-inner'>
<div class='main section' id='main' name='Main'><div class='widget Blog' data-version='1' id='Blog1'>
<div class='blog-posts hfeed'>
<div class="date-outer">
<h2 class='date-header'><span>Monday, July 15, 2019</span></h2>
<div class="date-posts">
<div class='post-outer'>
<div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'>
<meta content='8899645800948009496' itemprop='blogId'/>
<meta content='6521959894959786533' itemprop='postId'/>
<a name='6521959894959786533'></a>
<h3 class='post-title entry-title' itemprop='name'>
The dangers of conditional consistency guarantees
</h3>
<div class='post-header'>
<div class='post-header-line-1'></div>
</div>
<div class='post-body entry-content' id='post-body-6521959894959786533' itemprop='description articleBody'>
The ease of writing an application on top of infrastructure that guarantees consistency <a href="http://dbmsmusings.blogspot.com/2018/09/newsql-database-systems-are-failing-to.html">can not be overstated</a>. It&#8217;s just so much easier to write an application when you can be sure that every read will return the most recent state of the data --- no matter where in the world writes to data state occur, and no matter what types of failure may occur. <br />
<br />
Unfortunately, consistency in distributed systems comes at a cost. Other desirable system properties may be traded off in order to uphold a consistency guarantee. For example, it is well known (see the CAP theorem) that <a href="http://www.cs.umd.edu/~abadi/papers/abadi-pacelc.pdf">in the event of a network partition</a>, it is impossible to guarantee both consistency and availability. One must be traded off for the other. Furthermore, in a system deployed across a wide geography, the laws of physics prevent the communication required to maintain consistency from happening instantaneously. This leads to the <a href="http://www.cs.umd.edu/~abadi/papers/abadi-pacelc.pdf">PACELC tradeoff</a>: when there is a network partition (the P in PACELC), the system must decide how it will tradeoff availability (A) for consistency (C). Else (E) --- during normal operation of the system --- the system must decide how it will tradeoff latency (L) for consistency (C).<br />
<br />
There are four points in the PACELC tradeoff space: (1) PA/EC (when there is a partition, choose availability; else, choose consistency), (2) PC/EC (choose consistency at all times), (3) PA/EL (prioritize availability and latency over consistency), and (4) PC/EL (when there is a partition, choose consistency; else, choose latency). <br />
<br />
If you were to ask a student who just learned about the CAP theorem in a distributed systems class what guarantees they would want from a distributed system deployed for an application that needs 99.999% availability, the student would likely answer: &#8220;That&#8217;s easy! I would choose a system that prioritizes availability over consistency in the event of a network partition. But in the absence of a network partition, it is possible for a system to guarantee both availability and consistency, so I would want both those guarantees in the system I would deploy.&#8221;<br />
<br />
This answer is natural and obvious. But at the same time, it is naive and incorrect. <br />
<br />
The system that the student described would be a PA/EC system from PACELC --- a system that does not guarantee consistency during a network partition, but otherwise guarantees consistency. There are many applications that need several &#8220;nines&#8221; of availability. If the right PACELC system for those applications was PA/EC, then there would be many vendors competing with each other, attempting to sell the best PA/EC system. Yet in practice, the opposite is true --- it is extremely rare to find PA/EC systems in the wild. In fact, it took me <a href="http://dbmsmusings.blogspot.com/2017/10/hazelcast-and-mythical-paec-system.html">several years until I came across the IMDG (in-memory data grid) market</a> before I could find examples of real PA/EC systems. <br />
<br />
The reason for this is that PA/EC systems are much less useful than one might initially expect. To understand why this is the case, one must understand the fundamental difference between a real guarantee and a conditional guarantee.<br />
<br />
<br />
<h3>
Real guarantees vs. conditional guarantees</h3>
<br />
Of the three desirable properties that we&#8217;ve mentioned thus far as being desirable in a distributed system --- availability, consistency, and latency --- only one of them can ever be a real guarantee: consistency. No system will ever guarantee 100% availability, nor will any system guarantee that 100% of requests will complete within a particular latency bound. Such guarantees would be impossible to uphold. A &#8220;PA&#8221; system in PACELC prioritizes availability, but cannot guarantee 100% availability. Similarly, an &#8220;EL&#8221; system in PACELC prioritizes latency, but does not make any particular 100% guarantees. <br />
<br />
In contrast, consistency is a real guarantee. Systems that guarantee consistency are actually capable of upholding the promise of 100% consistency, and many systems do in fact provide it.<br />
<br />
Real guarantees form the foundation of the success of modern computing. Computers are extremely complex systems. Even a simple program must involve a large number of complex components --- from registers and logic gates to cache and memory to operating systems and security all the way up to the run time environment of the program. A simple &#8220;hello world&#8221; program ought to take weeks to develop. The reason why it doesn&#8217;t is because of the power of &#8220;abstraction&#8221; in computer science. Each level of a computer system builds on top of an underlying level that abstracts away the complex details of its implementation. Instead, the underlying level presents an interface to the higher level, and inviolable guarantees about what is returned through this interface. <br />
<br />
For example, when a program reads from a particular place in memory, it can assume that it will see the data that was last written there. In reality, the processor inside a computer may choose to execute instructions within a program out of order. Furthermore, electric or magnetic interference may cause bits to spontaneously flip in memory. In practice, complicated solutions are used to detect and correct such bit corruption, including using redundant memory bits, additional circuitry, and error correcting codes. All of this is hidden to the higher level program that wants to read this location in memory. The higher level program assumes that it will receive the data that was most recently written to that location 100% of the time. [Side note: In theory, all of the error correcting logic in storage systems still cannot yield an actual 100% guarantee. However, the chances of a corrupted data value being returned to the end user is so infinitesimally small that this guarantee is still treated like 100% for all practical purposes.]<br />
<br />
Imagine the extra complexity that would be involved in writing a program if you could not assume that instructions from a program are processed in the specified order, or the data in memory has not been corrupted. Almost every line of code that reads data from a variable would have to be surrounded by &#8216;if-statements&#8217; that check for what might be corruption in that particular context and that specifies what should be done if the read appears to not be correct. This extra code would likely increase the development cycle for a program by one to two orders of magnitude!<br />
<br />
For a program to be &#8220;bug-free&#8221;, this guarantee must be 100%. If a read returns the correct result 99% of the time, or even 99.99% or 99.9999% of the time, the above described &#8216;if-statements&#8217; and conditional logic will still be necessary. Only if the program can assume that the correct result will always be returned can the extra conditional logic be avoided. Thus, from the perspective of the developer, there is an enormous difference between a complete guarantee and an incomplete guarantee. Within the space of incomplete guarantees, it is certainly the case that 99.9999% accuracy is better than 99% accuracy. But the big jump in complexity savings for the developer is the jump between anything less than 100% and a 100% guarantee. <br />
<br />
This is why a PA/EC system has limited utility to an application developer. A PA/EC system is a system that guarantees consistency in all cases &#8230;. except when there is a network partition. In other words, a PA/EC makes a conditional guarantee of consistency: it guarantees consistency in all cases as long as a particular condition is met: that there is no network partition. <br />
<br />
However, we just said that the big jump in complexity savings for the developer is a jump between anything less than 100% and a 100% guarantee. Any guarantee that comes with conditions that are out of the control of the developer (such as ensuring that there will never be a network partition), is not that helpful. The developer still has to write code to handle the cases where the guarantee is not upheld. <br />
<br />
I am not arguing that all systems must guarantee consistency. I am only pointing out that there is a big difference in developer complexity between developing on top of a system that guarantees consistency fully, and one that guarantees consistency only under certain conditions. Without a full guarantee of consistency, there is a significant amount of extra effort required to ensure the absence of corner-case bugs that may emerge days, weeks, or even years after the application is first deployed. <br />
<br />
<br />
<h3>
Conditional guarantees and PACELC</h3>
<div>
<br /></div>
We just explained that a PA system in PACELC results in a large amount of extra effort for the application developer, in order to ensure that the application remains bug-free even when inconsistent reads occur during a network partition. If so, during normal operation, where there is a tradeoff between consistency and latency, why choose consistency? All of the effort in building an application that does not break in the face of inconsistent reads has already been paid. Why not benefit from all that effort during normal operation and get better latency as well?<br />
<br />
All of this suggests that application developers should decide whether they want to develop on top of a system that guarantees consistency or not. If they want consistency, they should deploy on top of a PC/EC system in PACELC --- i.e. a system that guarantees consistency 100% of the time. If they are willing to go to all of the extra effort to build on top of a system that does not guarantee consistency, they should be looking to get as many benefits as possible from this effort, and should deploy on top of PA/EL system, and thereby get better availability and latency properties (even if those properties do not come with guarantees).<br />
<br />
<br />
<div>
<h3>
New consistency guarantees in Hazelcast</h3>
<div>
<br /></div>
As I pointed out <a href="http://dbmsmusings.blogspot.com/2017/10/hazelcast-and-mythical-paec-system.html">in a previous post</a>, when deploying within a single geographic region, the latency vs. consistency tradeoff is not significant. In such environments, there is not much difference between PA/EC and PA/EL systems. Since in-memory data grids are typically deployed in a single region, PA/EC became the standard PACELC option for the IMDG market. <br />
<br />
Nonetheless, it is interesting to note how Hazelcast --- one of the most widely used IMDG implementations --- is moving away from the PA/EC default configuration and towards the more natural PC/EC and PA/EL pairings. <br />
<br />
In 2017, I wrote an <a href="http://dbmsmusings.blogspot.com/2017/10/hazelcast-and-mythical-paec-system.html">in-depth analysis</a> of Hazelcast&#8217;s consistency and availability guarantees. At around the same time, Kyle Kingsbury published a <a href="https://jepsen.io/analyses/hazelcast-3-8-3">linearizability analysis</a> of Hazelcast using his Jepsen testing library. These analyses led to what CEO Greg Luck tells me was 3 person-years of effort to release the first <a href="https://hazelcast.com/blog/hazelcast-imdg-3-12-introduces-cp-subsystem/">PC/EC configuration option in Hazelcast</a>. <br />
<br />
A quick reminder about what Hazelcast does: Many Java programs store program state inside Java collections and data structures such as Queue, Map, or Multimap. As a program scales --- both in terms of the number of clients accessing data and in terms of the amount of data stored, these data structures may get too large to fit in memory on a single server. Hazelcast provides a distributed implementation of these popular data structures, thereby enabling programs that leverage them to scale. Java programs interact with Hazelcast identically to how they interacted with the local data Java structures. However, under the covers, Hazelcast is distributing and replicating them across a cluster of machines.<br />
<br />
Hazelcast also provides distributed implementations of Java concurrency structures such as AtomicLong, AtomicReference, Lock. Using such structures without a consistency guarantee is downright dangerous. For example, in situations for which consistency is not upheld, it is possible for multiple different processes to acquire the same lock (concurrently) or for non-atomic actions to occur on supposedly atomic data structures. In other words, lack of consistency violates the fundamental premise of these backbone Java concurrency structures. <br />
<br />
With a PC/EC configuration option, you can now deploy Hazelcast&#8217;s distributed version of these concurrency tools --- IAtomicLong, IAtomicReference, and ILock --- and get <a href="https://hazelcast.com/blog/testing-the-cp-subsystem-with-jepsen/">identical correctness guarantees</a> relative to what they provide when being used by a regular single-server Java program. <br />
<br />
Hazelcast&#8217;s PC/EC configuration performs distributed agreement on data structure state via the <a href="https://raft.github.io/">Raft consensus protocol</a>. Raft is known for achieving strong availability. Even when a network partition occurs, the majority of servers can remain available (the consistency guarantee only requires that the minority partition must lose availability). <br />
<br />
Separately from the consistency issue, another well-known problem with distributed implementations of lock data structures is liveness. A server can acquire the lock and then fail for an indefinite period of time while holding the lock. Meanwhile the rest of the distributed system remains alive, but unable to acquire the lock and make progress. Therefore, in practice, distributed locks typically include timeouts, in order to prevent servers that fail while holding the lock from causing the rest of the system to stall indefinitely. Unfortunately, as soon as it is possible for a lock to timeout, it is <a href="https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html">possible for a process to get timed out while holding the lock, and yet be temporarily unaware that the lock timed out.</a> In such a scenario, it is possible for two different processes to concurrently believe they have the lock, and perform concurrent side-effects that the lock was designed to prevent. Hazelcast&#8217;s distributed lock implementation <a href="https://hazelcast.com/blog/long-live-distributed-locks/">includes a fencing mechanism</a> which enables downstream code --- code that is designed to be run while locks are being held --- to participate in the locking protocol and be able to distinguish which process is correct when multiple processes concurrently believe that they hold the lock. <br />
<br />
As far as the PA/EL option in Hazelcast, they have recently added <a href="https://docs.hazelcast.org/docs/3.12.1/manual/html-single/index.html#pn-counter">PN Counters </a>--- a CRDT counter implementation that enables some correctness guarantees despite the potential for inconsistent reads. In particular, when there is no consistency guarantee, it is possible for a server to read a stale value of the counter. For example, process A may update the value of a counter from 4 to 5. Afterwards, process B sees the stale value of the counter (4) and also adds one to it (to get 5). In versions of Hazelcast prior to 3.10, the final value of the counter --- even after whatever event caused the inconsistency is resolved --- would be 5. In other words, one of the two increments of the counter would be lost. With PN Counters (introduced in Hazelcast 3.10), the counter state will eventually converge to the correct value (in this case --- 6 --- that reflects the value after two increments to an initial value of 4). PN Counters also support decrements of the counter (in addition to increments), and guarantees (1) read-your-own-writes and (2) monotonic reads in addition to (3) what I described above --- the eventual convergence of the counter value to the correct value. <br />
<br />
Furthermore, inconsistent reads in Hazelcast prior to version 3.10 --- under PA/EC or PA/EL configurations --- could potentially result in duplicate IDs being generated. Hazelcast 3.10 introduced <a href="https://docs.hazelcast.org/docs/3.12.1/manual/html-single/index.html#flakeidgenerator">Flake ID generators</a> which guarantee global unique IDs even in the absence of a global consistency guarantee. <br />
<br />
<br />
<h3>
Conclusion</h3>
<div>
<br /></div>
PA/EC systems sound good in theory, but are not particularly useful in practice. Our one example of a real PA/EC system --- Hazelcast --- has spent the past 1.5 years introducing features that are designed for alternative PACELC configurations --- specifically PC/EC and PA/EL configurations. PC/EC and PA/EL configurations are a more natural cognitive fit for an application developer. Either the developer can be certain that the underlying system guarantees consistency in all cases (the PC/EC configuration) in which case the application code can be significantly simplified, or the system makes no guarantees about consistency at all (the PA/EL configuration) but promises high availability and low latency. CRDTs and globally unique IDs can still provide limited correctness guarantees despite the lack of consistency guarantees in PA/EL configurations. </div>
<div style='clear: both;'></div>
</div>
<div class='post-footer'>
<div class='post-footer-line post-footer-line-1'>
<span class='post-author vcard'>
Posted by
<span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'>
<meta content='https://www.blogger.com/profile/16753133043157018521' itemprop='url'/>
<a class='g-profile' href='https://www.blogger.com/profile/16753133043157018521' rel='author' title='author profile'>
<span itemprop='name'>Daniel Abadi</span>
</a>
</span>
</span>
<span class='post-timestamp'>
at
<meta content='http://dbmsmusings.blogspot.com/2019/07/the-dangers-of-conditional-consistency.html' itemprop='url'/>
<a class='timestamp-link' href='http://dbmsmusings.blogspot.com/2019/07/the-dangers-of-conditional-consistency.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2019-07-15T09:37:00-07:00'>9:37&#8239;AM</abbr></a>
</span>
<span class='post-comment-link'>
</span>
<span class='post-icons'>
<span class='item-control blog-admin pid-2045359914'>
<a href='https://www.blogger.com/post-edit.g?blogID=8899645800948009496&postID=6521959894959786533&from=pencil' title='Edit Post'>
<img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/>
</a>
</span>
</span>
<div class='post-share-buttons goog-inline-block'>
<a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=8899645800948009496&postID=6521959894959786533&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=8899645800948009496&postID=6521959894959786533&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=8899645800948009496&postID=6521959894959786533&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=8899645800948009496&postID=6521959894959786533&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=8899645800948009496&postID=6521959894959786533&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a>
</div>
</div>
<div class='post-footer-line post-footer-line-2'>
<span class='post-labels'>
</span>
</div>
<div class='post-footer-line post-footer-line-3'>
<span class='post-location'>
</span>
</div>
</div>
</div>
<div class='comments' id='comments'>
<a name='comments'></a>
<h4>No comments:</h4>
<div id='Blog1_comments-block-wrapper'>
<dl class='avatar-comment-indent' id='comments-block'>
</dl>
</div>
<p class='comment-footer'>
<div class='comment-form'>
<a name='comment-form'></a>
<h4 id='comment-post-message'>Post a Comment</h4>
<p>
</p>
<a href='https://www.blogger.com/comment/frame/8899645800948009496?po=6521959894959786533&hl=en&saa=85391&origin=http://dbmsmusings.blogspot.com' id='comment-editor-src'></a>
<iframe allowtransparency='true' class='blogger-iframe-colorize blogger-comment-from-post' frameborder='0' height='410px' id='comment-editor' name='comment-editor' src='' width='100%'></iframe>
<script src='https://www.blogger.com/static/v1/jsbin/3790099508-comment_from_post_iframe.js' type='text/javascript'></script>
<script type='text/javascript'>
BLOG_CMT_createIframe('https://www.blogger.com/rpc_relay.html');
</script>
</div>
</p>
</div>
</div>
</div></div>
</div>
<div class='blog-pager' id='blog-pager'>
<span id='blog-pager-newer-link'>
<a class='blog-pager-newer-link' href='http://dbmsmusings.blogspot.com/2019/07/overview-of-consistency-levels-in.html' id='Blog1_blog-pager-newer-link' title='Newer Post'>Newer Post</a>
</span>
<span id='blog-pager-older-link'>
<a class='blog-pager-older-link' href='http://dbmsmusings.blogspot.com/2019/06/correctness-anomalies-under.html' id='Blog1_blog-pager-older-link' title='Older Post'>Older Post</a>
</span>
<a class='home-link' href='http://dbmsmusings.blogspot.com/'>Home</a>
</div>
<div class='clear'></div>
<div class='post-feeds'>
<div class='feed-links'>
Subscribe to:
<a class='feed-link' href='http://dbmsmusings.blogspot.com/feeds/6521959894959786533/comments/default' target='_blank' type='application/atom+xml'>Post Comments (Atom)</a>
</div>
</div>
</div></div>
</div>
</div>
<div class='column-left-outer'>
<div class='column-left-inner'>
<aside>
</aside>
</div>
</div>
<div class='column-right-outer'>
<div class='column-right-inner'>
<aside>
<div class='sidebar section' id='sidebar-right-1'><div class='widget Image' data-version='1' id='Image1'>
<h2>Daniel Abadi</h2>
<div class='widget-content'>
<img alt='Daniel Abadi' height='449' id='Image1_img' src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjq7IZ-b9X74S5hxbSo0XZg6tWgFnU-Tkkg2SrZbH0sRSvLi37d5oAaTx5gj3DQG6jxEcvzmQIyduk9EiMPxzlvHVgl33-67YLUpDn-ns_DrXBNbQxKRAx1EDfjo5kmrW1qGIhnxdJgZw/s1600/dan_2019.jpg' width='315'/>
<br/>
</div>
<div class='clear'></div>
</div><div class='widget Profile' data-version='1' id='Profile1'>
<h2>About Me</h2>
<div class='widget-content'>
<dl class='profile-datablock'>
<dt class='profile-data'>
<a class='profile-name-link g-profile' href='https://www.blogger.com/profile/16753133043157018521' rel='author' style='background-image: url(//www.blogger.com/img/logo-16.png);'>
Daniel Abadi
</a>
</dt>
<dd class='profile-textblock'>Daniel Abadi is the Darnell-Kanal Professor of Computer Science at University of Maryland, College Park. He is best-known for the development of the storage and query execution engines of the C-Store (column-oriented database) prototype, which was commercialized by Vertica and eventually acquired by Hewlett-Packard in 2011, for his HadoopDB research on fault tolerant scalable analytical database systems which was commercialized by Hadapt and acquired by Teradata in 2014, and deterministic, scalable, transactional, distributed systems such as Calvin which is currently being commercialized by <a href="https://fauna.com/">Fauna</a>. Abadi has been a recipient of a
Churchill Scholarship, a NSF CAREER Award, a Sloan Research Fellowship, a VLDB Best Paper Award, two VLDB <b>10 year</b> Best Paper Awards, the 2008 SIGMOD Jim Gray Doctoral Dissertation Award, the 2013-2014 Yale Provost's Teaching Prize, and the 2013 VLDB Early Career Researcher Award. He received his PhD in 2008 from MIT.
He blogs at <a href="http://dbmsmusings.blogspot.com">DBMS Musings</a> and tweets at <a href="http://www.twitter.com/daniel_abadi">@daniel_abadi</a>.</dd>
</dl>
<a class='profile-link' href='https://www.blogger.com/profile/16753133043157018521' rel='author'>View my complete profile</a>
<div class='clear'></div>
</div>
</div></div>
<table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'>
<tbody>
<tr>
<td class='first columns-cell'>
<div class='sidebar section' id='sidebar-right-2-1'><div class='widget BlogArchive' data-version='1' id='BlogArchive1'>
<h2>Blog Archive</h2>
<div class='widget-content'>
<div id='ArchiveList'>
<div id='BlogArchive1_ArchiveList'>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2021/'>
2021
</a>
<span class='post-count' dir='ltr'>(1)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2021/03/'>
March
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate expanded'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy toggle-open'>
&#9660;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/'>
2019
</a>
<span class='post-count' dir='ltr'>(8)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/10/'>
October
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/08/'>
August
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate expanded'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy toggle-open'>
&#9660;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/07/'>
July
</a>
<span class='post-count' dir='ltr'>(2)</span>
<ul class='posts'>
<li><a href='http://dbmsmusings.blogspot.com/2019/07/overview-of-consistency-levels-in.html'>Overview of Consistency Levels in Database Systems</a></li>
<li><a href='http://dbmsmusings.blogspot.com/2019/07/the-dangers-of-conditional-consistency.html'>The dangers of conditional consistency guarantees</a></li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/06/'>
June
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/05/'>
May
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/01/'>
January
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2018/'>
2018
</a>
<span class='post-count' dir='ltr'>(3)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2018/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2018/09/'>
September
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2018/03/'>
March
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2017/'>
2017
</a>
<span class='post-count' dir='ltr'>(3)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2017/10/'>
October
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2017/04/'>
April
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2015/'>
2015
</a>
<span class='post-count' dir='ltr'>(1)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2015/10/'>
October
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/'>
2012
</a>
<span class='post-count' dir='ltr'>(4)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/11/'>
November
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/10/'>
October
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/06/'>
June
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/05/'>
May
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/'>
2011
</a>
<span class='post-count' dir='ltr'>(6)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/10/'>
October
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/07/'>
July
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/05/'>
May
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/03/'>
March
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/02/'>
February
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/'>
2010
</a>
<span class='post-count' dir='ltr'>(8)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/08/'>
August
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/07/'>
July
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/04/'>
April
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/03/'>
March
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/01/'>
January
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/'>
2009
</a>
<span class='post-count' dir='ltr'>(21)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/11/'>
November
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/10/'>
October
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/09/'>
September
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/08/'>
August
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/07/'>
July
</a>
<span class='post-count' dir='ltr'>(5)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/06/'>
June
</a>
<span class='post-count' dir='ltr'>(8)</span>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class='clear'></div>
</div>
</div></div>
</td>
<td class='columns-cell'>
<div class='sidebar section' id='sidebar-right-2-2'><div class='widget Followers' data-version='1' id='Followers1'>
<h2 class='title'>Followers</h2>
<div class='widget-content'>
<div id='Followers1-wrapper'>
<div style='margin-right:2px;'>
<div><script type="text/javascript" src="https://apis.google.com/js/platform.js"></script>
<div id="followers-iframe-container"></div>
<script type="text/javascript">
window.followersIframe = null;
function followersIframeOpen(url) {
gapi.load("gapi.iframes", function() {
if (gapi.iframes && gapi.iframes.getContext) {
window.followersIframe = gapi.iframes.getContext().openChild({
url: url,
where: document.getElementById("followers-iframe-container"),
messageHandlersFilter: gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER,
messageHandlers: {
'_ready': function(obj) {
window.followersIframe.getIframeEl().height = obj.height;
},
'reset': function() {
window.followersIframe.close();
followersIframeOpen("https://www.blogger.com/followers/frame/8899645800948009496?colors\x3dCgt0cmFuc3BhcmVudBILdHJhbnNwYXJlbnQaByM2NjY2NjYiByMyMTk4YTYqByNmZmZmZmYyByM2NjY2NjY6ByM2NjY2NjZCByMyMTk4YTZKByNjY2NjY2NSByMyMTk4YTZaC3RyYW5zcGFyZW50\x26pageSize\x3d21\x26hl\x3den\x26origin\x3dhttp://dbmsmusings.blogspot.com");
},
'open': function(url) {
window.followersIframe.close();
followersIframeOpen(url);
}
}
});
}
});
}
followersIframeOpen("https://www.blogger.com/followers/frame/8899645800948009496?colors\x3dCgt0cmFuc3BhcmVudBILdHJhbnNwYXJlbnQaByM2NjY2NjYiByMyMTk4YTYqByNmZmZmZmYyByM2NjY2NjY6ByM2NjY2NjZCByMyMTk4YTZKByNjY2NjY2NSByMyMTk4YTZaC3RyYW5zcGFyZW50\x26pageSize\x3d21\x26hl\x3den\x26origin\x3dhttp://dbmsmusings.blogspot.com");
</script></div>
</div>
</div>
<div class='clear'></div>
</div>
</div></div>
</td>
</tr>
</tbody>
</table>
<div class='sidebar no-items section' id='sidebar-right-3'></div>
</aside>
</div>
</div>
</div>
<div style='clear: both'></div>
<!-- columns -->
</div>
<!-- main -->
</div>
</div>
<div class='main-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<footer>
<div class='footer-outer'>
<div class='footer-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left footer-fauxborder-left'>
<div class='fauxborder-right footer-fauxborder-right'></div>
<div class='region-inner footer-inner'>
<div class='foot no-items section' id='footer-1'></div>
<table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'>
<tbody>
<tr>
<td class='first columns-cell'>
<div class='foot no-items section' id='footer-2-1'></div>
</td>
<td class='columns-cell'>
<div class='foot no-items section' id='footer-2-2'></div>
</td>
</tr>
</tbody>
</table>
<!-- outside of the include in order to lock Attribution widget -->
<div class='foot section' id='footer-3' name='Footer'><div class='widget Attribution' data-version='1' id='Attribution1'>
<div class='widget-content' style='text-align: center;'>
Ethereal theme. Powered by <a href='https://www.blogger.com' target='_blank'>Blogger</a>.
</div>
<div class='clear'></div>
</div></div>
</div>
</div>
<div class='footer-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</footer>
<!-- content -->
</div>
</div>
<div class='content-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</div>
<script type='text/javascript'>
window.setTimeout(function() {
document.body.className = document.body.className.replace('loading', '');
}, 10);
</script>
<script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/1363620594-widgets.js"></script>
<script type='text/javascript'>
window['__wavt'] = 'AAPvtVm_6cL4WOHpe2dYa30mgPWT:1789171829705';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d8899645800948009496','//dbmsmusings.blogspot.com/2019/07/the-dangers-of-conditional-consistency.html','8899645800948009496');
_WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '8899645800948009496', 'title': 'DBMS Musings', 'url': 'http://dbmsmusings.blogspot.com/2019/07/the-dangers-of-conditional-consistency.html', 'canonicalUrl': 'http://dbmsmusings.blogspot.com/2019/07/the-dangers-of-conditional-consistency.html', 'homepageUrl': 'http://dbmsmusings.blogspot.com/', 'searchUrl': 'http://dbmsmusings.blogspot.com/search', 'canonicalHomepageUrl': 'http://dbmsmusings.blogspot.com/', 'blogspotFaviconUrl': 'http://dbmsmusings.blogspot.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': false, 'httpsEnabled': true, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': 'G-WPSPKTZ8VQ', 'analytics4': true, 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22DBMS Musings - Atom\x22 href\x3d\x22http://dbmsmusings.blogspot.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22DBMS Musings - RSS\x22 href\x3d\x22http://dbmsmusings.blogspot.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22DBMS Musings - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/8899645800948009496/posts/default\x22 /\x3e\n\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22DBMS Musings - Atom\x22 href\x3d\x22http://dbmsmusings.blogspot.com/feeds/6521959894959786533/comments/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/1890a9484e710b1c', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'item', 'postId': '6521959894959786533', 'pageName': 'The dangers of conditional consistency guarantees', 'pageTitle': 'DBMS Musings: The dangers of conditional consistency guarantees'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'Ethereal', 'localizedName': 'Ethereal', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': false, 'variant': 'hummingBirds2', 'variantId': 'hummingBirds2'}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'The dangers of conditional consistency guarantees', 'description': 'The ease of writing an application on top of infrastructure that guarantees consistency can not be overstated . It\u2019s just so much easier to ...', 'url': 'http://dbmsmusings.blogspot.com/2019/07/the-dangers-of-conditional-consistency.html', 'type': 'item', 'isSingleItem': true, 'isMultipleItems': false, 'isError': false, 'isPage': false, 'isPost': true, 'isHomepage': false, 'isArchive': false, 'isLabelSearch': false, 'postId': 6521959894959786533}}]);
_WidgetManager._RegisterWidget('_NavbarView', new _WidgetInfo('Navbar1', 'navbar', document.getElementById('Navbar1'), {}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'lightboxEnabled': true, 'lightboxModuleUrl': 'https://www.blogger.com/static/v1/jsbin/700075392-lbx.js', 'lightboxCssUrl': 'https://www.blogger.com/static/v1/v-css/828616780-lightbox_bundle.css'}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_ImageView', new _WidgetInfo('Image1', 'sidebar-right-1', document.getElementById('Image1'), {'resize': true}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_ProfileView', new _WidgetInfo('Profile1', 'sidebar-right-1', document.getElementById('Profile1'), {}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar-right-2-1', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_FollowersView', new _WidgetInfo('Followers1', 'sidebar-right-2-2', document.getElementById('Followers1'), {}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull'));
</script>
</body>
</html>