{"id":1879,"date":"2021-03-23T01:24:55","date_gmt":"2021-03-23T08:24:55","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/"},"modified":"2021-03-23T01:24:55","modified_gmt":"2021-03-23T08:24:55","slug":"distributed-multi-document-acid-transactions","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/","title":{"rendered":"How we implemented Distributed Multi-document ACID Transactions in Couchbase"},"content":{"rendered":"\n<p><span><a href=\"https:\/\/www.couchbase.com\/transactions\/\">ACID Transactions<\/a> are a must when you have strict data consistency requirements in your application. The costs of running transactions on distributed systems can rapidly create bottlenecks at scale. In this article, we will give you an overview of some of the challenges faced by NoSQL and NewSQL databases. Then, we&#8217;ll deep dive into how Couchbase implemented a scalable distributed transaction model with no central coordination and no single point of failure. Additionally, I will also give a short overview of how the support for transactions in N1QL looks like on Couchbase 7.0.<\/span><\/p>\n\n\n\n<p><span>Some minor details were omitted for the sake of simplicity.<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>Relational vs NewSQL vs NoSQL Transactions<\/span><\/h2>\n\n\n\n<p><span>Before I start explaining how Couchbase implemented support for transactions, I need to first explain the inherent characteristics of atomicity in relational and NoSQL databases (using semi-structured data models like JSON):<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Atomicity in RDBMS<\/span><\/h3>\n\n\n\n<p><span>Let&#8217;s say you need to save a new user in the database. Naturally, as it has many other tables associated with it, inserting a user will also require inserts on many other tables:<\/span><\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10954\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/Picture1.png\" alt=\"Transactions on Relational\" width=\"750\" height=\"419\"><\/p>\n\n\n\n<p><span>Because the relational model forces you to store everything on \u201cboxes\u201d and split your data into small pieces, adding a new user should always run inside of a transactional context. Otherwise, if one of your inserts fail, your user will end up half-saved. Notice how an RDBMS relies heavily on transactions, as applications are far more complex than when the relational model was originally designed back in the seventies.<\/span><\/p>\n\n\n\n<p><span>Luckily, as these databases are designed to run on a single node, you can use a central transaction coordinator to commit the data at once without any performance impact. <\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Atomicity in NewSQL<\/span><\/h3>\n\n\n\n<p><span>On the NewSQL side (distributed relational), things are a little bit more complicated. As most of these databases reuse the relational model, your entity\u2019s data (or <\/span><a href=\"https:\/\/martinfowler.com\/bliki\/DDD_Aggregate.html\"><span>aggregate root<\/span><\/a><span>) tends to be spread throughout multiple nodes.<\/span><\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10966\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2021-03-05-at-2.46.28-PM-1024x415-1.png\" alt=\"atomicity in newsql\" width=\"656\" height=\"266\"><\/p>\n\n\n\n<p><span>In the image above, if we need to load the user into memory, we would need to first get the user from Server 1, then load the association between users and roles on Server 2 and finally load the target role from Server 3. This simple operation requires data to travel at least twice over the network, which will ultimately limit your read performance. In a real-world scenario, a user has many more tables associated with it. This is why distributed relational is not yet practical when you need to read\/write as fast as possible.<\/span><\/p>\n\n\n\n<p><span>You can try to minimize the issues above by limiting the size of your cluster, by relying heavily on indexes to track all relationships, or by some sharding techniques to keep all related data in the same node (which is difficult to implement in practice). The last two approaches, even when well implemented, will consume significant resources from the database to be managed properly.<\/span><\/p>\n\n\n\n<p><span>ACID transactions in NewSQL databases require more coordination than in NoSQL, as the data related to an entity is split into multiple tables which might live in different nodes. The relational model, as we use today, requires transactions for the majority of the writes, updates, and cascading deletes. The extra coordination that the NewSQL architecture requires comes at a cost of reduced throughput for applications requiring low latency operations.<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Atomicity in Document Databases<\/span><\/h3>\n\n\n\n<p><span>The use of semi-structured data like JSON can drastically reduce the number of \u201ccross-node joins\u201d, therefore delivering better read\/write performance without the need to rely too much on indexing. This was one of the key insights of the <\/span><a href=\"https:\/\/www.allthingsdistributed.com\/files\/amazon-dynamo-sosp2007.pdf\"><span>Dynamo Paper<\/span><\/a><span> (first published ~13 years ago) which was the<\/span><span> catalyst to create the NoSQL databases as we know them today.<\/span><\/p>\n\n\n\n<p><span>Another interesting characteristic of a semi-structured data model is that it is less transactional, as you could fit the whole user data in a single document:<\/span><\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10956\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/JSON-Denis.png\" alt=\"atomicity nosql\" width=\"332\" height=\"399\"><\/p>\n\n\n\n<p><span>As you can see in the image above, the user preferences and roles can easily fit inside a \u201cUser Document\u201d, so there is no need for a transaction to insert or update a user as the operation is atomic. We insert the document or the whole operation fails. The same is valid for many other common use cases: shopping carts, products, tree structures, and <\/span><a href=\"https:\/\/martinfowler.com\/bliki\/DDD_Aggregate.html\"><span>aggregate roots <\/span><\/a><span>in general.<\/span><\/p>\n\n\n\n<p><span>In the majority of the applications using document databases, 90% of the transactional operations will fall in this single document category. But\u2026 what about the other 10%? Well, for those we will need multi-document transaction support, which has been added in Couchbase since version 6.5 and is the main focus of this article.<\/span><\/p>\n\n\n\n<p><span>Here is a presentation about transactions that was delivered at Couchbase Connect 2020. Matt Ingenthron gives you an explanation of when and why you might need multi-document ACID transactions:<\/span><\/p>\n\n\n\n<h6 class=\"wp-block-heading\"><span>Watch the full version at <\/span><a href=\"https:\/\/www.youtube.com\/watch?v=2fsZVe2cT3M&amp;ab_channel=Couchbase\"><span>https:\/\/www.youtube.com\/watch?v=2fsZVe2cT3M&amp;ab_channel=Couchbase<\/span><\/a><\/h6>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Video Transcript<\/span><\/h3>\n\n\n\n<details>\n<summary>Click to read the full transcription.<\/summary>\n<p><span>Let&#8217;s talk about how this is applied to a fictitious but maybe kind of realistic example of a document model for a Couchbase system. So we&#8217;ve raised some money, and we&#8217;re going to build a massively multiplayer online role-playing game (an MMORPG), with players and monsters. So we need a data model.\u00a0<\/span><\/p>\n<p><span>We are going to have players who fight monsters and then based on that fight, win or lose, they&#8217;re going to. If they win, they&#8217;re going to get a weapon, if they lose, uh, they lose some hit points so nobody can die. You always can come back to life, you can always find another day. But your players fight monsters, and we get our version 1.0 built. Great! Okay, Got our funding, got our 1.0 built.<\/span><\/p>\n<p><span>The problem is, we forgot to do the massively multiplayer part. There&#8217;s no collaborative play. I can&#8217;t have multiple players fight the same monster. So I need to fix that, right? So let&#8217;s roll out a new version. So players are going to continue to fight monsters and win weapons.<\/span><\/p>\n<p><span>So we roll out our version two 2.0, and in version 2.0 players can fight monsters together. I can coordinate with my friends, we could go find a monster, and we can kill that monster.\u00a0<\/span><\/p>\n<p><span>But we left a bug in there. It&#8217;s possible for multiple players to deliver the death blow and the reason that&#8217;s a problem is the players of the game figure it out. Instead of battling a monster together to death, what they do is, they, in this massively multiplayer world, they\u2019ll battle it till close to death, and then a bunch of players will gather up together, and they all deliver the death blow or many will deliver the death blow at the same time.\u00a0<\/span><\/p>\n<p><span>The problem is, they win items, they win multiple items, and because items have rarity, and if you don&#8217;t have a certain amount of rareness for an item, the gameplay is not very interesting. This bug has allowed too many items to exist in the world, and the players are just spending time hacking the game, and then they get bored and leave. We need to keep the gameplay interesting.<\/span><\/p>\n<p><span>So let&#8217;s think about this. How can we fix this? I think what we&#8217;ll need to do is probably introduce a fix. We\u2019ll still allow players and monsters, multiple players to fight a monster. But what we&#8217;re gonna do is take one of those tricks that we have, we&#8217;re gonna take <\/span><a href=\"https:\/\/docs.couchbase.com\/java-sdk\/current\/howtos\/concurrent-document-mutations.html\"><span>Couchbase CAS <\/span><\/a><span>Operations.<\/span><\/p>\n<p><span>With the <\/span><a href=\"https:\/\/docs.couchbase.com\/java-sdk\/current\/howtos\/concurrent-document-mutations.html\"><span>CAS operation<\/span><\/a><span> what happens is now multiple players are fighting that monster, lowering its hit points until it gets down to zero. But only one of those players is going to be able to deliver the death blow to that monster and win an item.<\/span><\/p>\n<p><span>So the way this works is if two players are trying to deliver that death blow, the application <\/span><span>server that&#8217;s handling the request is going to try to modify the document. It has to pick up a little piece of opaque information that we call the<\/span><a href=\"https:\/\/docs.couchbase.com\/java-sdk\/current\/howtos\/concurrent-document-mutations.html\"><span> CAS (that&#8217;s for Check And Set)<\/span><\/a><span>, and so that means that if that opaque does not match, then the documents have already been modified, and so you need to retry that operation. In the scenario that two actors within the system are trying to grab that document at the same time, what we want is one to succeed and one to fail, and the CAS will give us that in a very efficient way.<\/span><\/p>\n<p><span>We pull out that trick, we introduce CAS operations, the bug is fixed, gameplay is now much more interesting and 2.1 does really well, so that&#8217;s great.<\/span><\/p>\n<p><span>So now let&#8217;s try a , uh, we wanna move on, we wanna make things more interesting. Imagine now that I introduce another feature: &#8220;Players can still fight monsters together, but they have to do it outside the city. So you have to be outside the city wall where the players are, and if you go into the city, you will do trade in a bizarre&#8221;<\/span><\/p>\n<p><span>This works really well at first, but then players figure something out.<\/span><\/p>\n<p><span>So imagine player1, I have to retrieve the document for player1. Then I have to retrieve the document for player2. Then I have to move the sword from player1 to player2, that&#8217;s very easy to do in the application logic, and then I go to store that change back to the system with the CAS operation, and then I go to store the other change back, right? Sounds like it&#8217;ll be great. Except there&#8217;s a bug.<\/span><\/p>\n<p><span>The bug here is that my players can start a trade and then disconnect, and then items that might we that we might want to be rare are not going to be rare. They can be duplicated within the system.<\/span><\/p>\n<p><span>In massively multiplayer online role-playing games, it&#8217;s called a Dup Bug. If you were to go to Google and search search for a &#8220;Dup Bug&#8221;, you&#8217;ll find lots of scenarios.<\/span><\/p>\n<p><span>Here&#8217;s one from just a couple of weeks ago where Final Fantasy Crystal Chronicles on switch had to be patched because of a Dup bug. And then there was one just a few days before that, this is from a blog where a game blogger showing people how to use this dup glitch to retrieve&#8230; to get additional items within the game.<\/span><\/p>\n<p><span>So we need to fix this bug. How are we going to do that? Well, so we&#8217;re going to reach into our Couchbase bag of tricks.<\/span><\/p>\n<p><span>We&#8217;re going to introduce Couchbase transactions. The gameplay is almost exactly the same. But what are we gonna do with Couchbase transactions? And so this is the one slide where I&#8217;m going to talk a little bit about the code.<\/span><\/p>\n<\/details>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>Multi-Document Distributed ACID Transactions in Couchbase<\/span><\/h2>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<p><span>Now that you understand how transactions behave in different data models, it is time to deep dive into how we have implemented it at Couchbase and what led to our design choices. First, let\u2019s go through the syntax:<\/span><\/p>\n\n\n<p>[crayon lang=&#8221;java&#8221; decode=&#8221;true&#8221;]transactions.run((ctx) -&gt; {<br \/>\n        \/\/ get the account documents for userA and UserB<br \/>\n        TransactionJsonDocument userA = ctx.getOrError(collection, &#8220;userA&#8221;);<br \/>\n        JsonObject userAContent = userA.contentAsObject();<br \/>\n        int userABalance = userAContent.getInt(&#8220;account_balance&#8221;);<br \/>\n        TransactionJsonDocument userB = ctx.getOrError(collection, &#8220;Beth&#8221;);<br \/>\n        JsonObject userBContent = userB.contentAsObject();<br \/>\n        int userBBalance = userBContent.getInt(&#8220;account_balance&#8221;);<\/p>\n<p>        \/\/ if userB has sufficient funds, make the transfer<br \/>\n        if (userBBalance &gt; transferAmount) {<br \/>\n                userAContent.put(&#8220;account_balance&#8221;, userABalance + transferAmount);<br \/>\n                ctx.replace(userA, userAContent);<br \/>\n                userBContent.put(&#8220;account_balance&#8221;, userBBalance &#8211; transferAmount);<br \/>\n                ctx.replace(userB, userBContent);<br \/>\n        }<br \/>\n        else throw new InsufficientFunds();<br \/>\n});[\/crayon]<\/p>\n\n\n\n<p><span>The Java example above is the classic example of how to transfer money between two clients.\u00a0 Notice that we decided to use a <\/span><a href=\"https:\/\/en.wikipedia.org\/wiki\/Anonymous_function\"><span>lambda function<\/span><\/a><span> to express the transaction. Proper error handling can be challenging in this scenario and wrapping your transaction with an anonymous function allows the Couchbase Java SDK to do that work for you (i.e retry if something fails).<\/span><\/p>\n\n\n\n<p><span>When we first launched support for transactions we were trying to avoid verbosity. This was how one competitor&#8217;s transaction syntax used to look:<\/span><\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10958\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/mdb-transaction-1024x577-1.png\" alt=\"\" width=\"575\" height=\"324\"><\/p>\n\n\n\n<p><span>Lately, it seems like handling transactions inside lambda functions is becoming the norm for NoSQL databases.<\/span><\/p>\n\n\n\n<p><span>For those who were expecting it to be similar to the relational syntax for transactions (e.g. BEGIN\/COMMIT\/ROLLBACK SQL commands), keep reading: you can also run transactions through N1QL! Now, let\u2019s try to understand what is happening under the hood.<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Couchbase Architecture Review<\/span><\/h3>\n\n\n\n<p><span>For those unfamiliar with Couchbase\u2019s architecture, I need to quickly explain 4 important concepts before going any further:<\/span><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span>Couchbase is highly scalable, you can easily go from 1 to 100 nodes in a single cluster <\/span><span>with minimal effort<\/span><span>\u00a0<\/span><\/li>\n\n\n<li><span>JSON Documents have a \u201cMeta\u201d space called <\/span><b>xAttr<\/b> <a href=\"https:\/\/docs.couchbase.com\/java-sdk\/current\/concept-docs\/xattr.html\"><span>where you can store metadata about your document<\/span><\/a><span>.<\/span><\/li>\n\n\n<li><span>Inside each Bucket (similar to a schema in RDBMS), Couchbase automatically distributed the data into 1024 shards called <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/buckets-memory-and-storage\/vbuckets.html\"><span>vBuckets<\/span><\/a><span>. The sharding is totally transparent to the developer, and we also take care of the sharding strategy. Our sharding algorithm (CRC32) essentially guarantees that documents will be evenly distributed between these vBuckets and no resharding is ever needed. The vBuckets are evenly distributed between the nodes of your cluster(e.g. if you have a cluster of 4 nodes, each node contains 256 vBuckets).<\/span><\/li>\n\n<\/ul>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10961\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/docs-bucket-vBuckets-1024x398-1.png\" alt=\"\" width=\"506\" height=\"197\"><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span>The client\u2019s SDK stores a copy of the cluster map, which is a hashmap of vBuckets and the node responsible for them. By hashing the document\u2019s key, the SDK can find in which vBucket the document should be located. And thanks to the cluster map it can talk directly to the node responsible for the document during save\/delete\/update operations.\u00a0<\/span><\/li>\n\n<\/ul>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10962\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/vbucketToNodeMapping-1024x651-1.png\" alt=\"bucket to server mapping\" width=\"554\" height=\"352\"><\/p>\n\n\n\n<p><span>The design choices above allow Couchbase to have a masterless architecture (also referred to as master\/master) instead of the traditional master\/slave used in other NoSQL databases. There are a number of advantages of this kind of architecture, but the ones relevant for us now are the following:<\/span><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span>The SDK saves \u201cone network hop\u201d during insert\/update\/delete operations as it knows where a given document is located (In the master\/slave architecture you have to ask the master where the document is).<\/span><\/li>\n\n\n<li><span>The database itself has no central coordinator, therefore, no single point of failure. In practice, the client acts indirectly as a lightweight coordinator, as it knows exactly which node in the cluster to talk to.<\/span><\/li>\n\n<\/ul>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Distributed Transactions without a Central Coordinator<\/span><\/h3>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<p><span>On Couchbase\u2019s architecture, each client is responsible for the coordination of its own transactions. Naturally, everything is done under-the-hood on the SDK level. To put it simply, if you have 100 instances of your application running transactions, then you have potentially ~100 coordinators. These coordinators add next-to-no overhead to your application, and you will soon understand why.<\/span><\/p>\n\n\n\n<p><span>If we reuse the money transfer example shown in our code example and assume that the 2 documents involved in this transaction live in two different nodes, from a 1,000-foot view the transaction follows these steps:<\/span><\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10963\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2021-03-10-at-4.25.34-PM.png\" alt=\"distribute transaction flow\" width=\"600\" height=\"355\"><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><span>Each vBucket has a single document responsible for the transaction log called <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/data\/transactions.html\"><span>Active Transaction Record <\/span><\/a><span>(ATR). The ATR can be easily identified by the\u00a0 <\/span><b>_txn:atr-<\/b> <span>id prefix. Before the first document mutation ( <span class=\"lang:java decode:true crayon-inline \">ctx.replace(userA, userAContent)<\/span>\u00a0in this case) a new entry is added in the <strong>ATR<\/strong> in the same vBucket with the transaction id and the \u201cPending\u201d status. Just one <strong>ATR<\/strong> is used per transaction.<\/span><\/li>\n\n\n<li><span>The transaction Id and the content of the first mutation, <span class=\"lang:java decode:true crayon-inline\">ctx.replace(userA, userAContent)<\/span>, is staged in the <\/span><b>xAttrs<\/b><span> of the first document (\u201cuserA\u201d).<\/span><\/li>\n\n\n<li><span>The transaction Id and the content of the second mutation, <span class=\"lang:java decode:true crayon-inline\">ctx.replace(userB, userBContent)<\/span>, is staged in the <\/span><b>xAttrs<\/b><span> of the second document \u201cuserB\u201d.<\/span><\/li>\n\n\n<li><span>The transaction is marked as \u201cCommitted\u201d in the <strong>ATR<\/strong>. We also leverage this call to update the list of document ids involved in the transaction.<\/span><\/li>\n\n\n<li><span>Document \u201cuserA\u201d is unstaged (removed from <strong>xAttrs<\/strong> and replaces the document body)<\/span><\/li>\n\n\n<li><span>Document \u201cuserB\u201d is unstaged (removed from <strong>xAttrs<\/strong> and replaces the document body)<\/span><\/li>\n\n\n<li><span>The transaction is marked as \u201cCompleted\u201d and removed from the <strong>ATR<\/strong><\/span><\/li>\n\n<\/ol>\n\n\n\n<p><span>Note that this implementation is not limited by <\/span><span><a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/learn\/data\/scopes-and-collections.html\">scopes, collections<\/a>,<\/span><span> or shards (vBuckets). In fact, you can even execute transactions across multiple buckets. As long as you have enough permissions,\u00a0 any document inside your cluster can be part of a transaction.<\/span><\/p>\n\n\n\n<p><span>At this point, I assume that you have many questions about all the potential failure scenarios. Let\u2019s try to cover the most important topics here. Feel free to leave comments and I will try to update the article accordingly.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Handling Isolation &#8211; Monotonic Atomic View<\/span><\/h3>\n\n\n\n<p><a href=\"https:\/\/jepsen.io\/consistency\"><span>Jepsen<\/span><\/a><span> has a brilliant graph that explains the most important consistency models for databases:<\/span><\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10964\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2021-03-10-at-4.55.38-PM.png\" alt=\"Consistency Models\" width=\"611\" height=\"434\"><\/p>\n\n\n\n<p><span>Couchbase has support for the <\/span><b>Read Committed<\/b><span>\/<\/span><b>Monotonic Atomic View<\/b><span>\u201d consistency models. But how good is that? Well, <\/span><b>Read Committed<\/b><span> is the default choice in Postgres, MySQL, MariaDB and many other databases out there; if you never changed that option, that&#8217;s what you are using right now.<\/span><\/p>\n\n\n\n<p><b>Read Committed<\/b><span> guarantees that your application can\u2019t read uncommitted data, which is what you likely expect from your database, but the interesting part here is how the commit process actually happens. In relational databases, quite often, there is a coordination between the new versions of the rows changed in a transaction to take over their previous ones all at the same time. This is commonly referred to as <\/span><b>write-point commit<\/b><span>.<\/span> <span>In order for that to happen, <\/span><a href=\"https:\/\/en.wikipedia.org\/wiki\/Multiversion_concurrency_control\"><span>Multiversion Concurrency Control(MVCC)<\/span><\/a><span> is required. This is problematic because of all the baggage that comes with it, not to mention how expensive it gets (in terms of performance) to be implemented in an ACID distributed database where fast reads\/writes are key.<\/span><\/p>\n\n\n\n<p><span>Another disadvantage of write-point commits is that you might spend valuable time synchronizing your commit but \u2026 no other thread reads it right after, wasting all effort spent with synchronization. That is when <\/span><b>Monotonic Atomic View(MAV)<\/b><span> comes into play. It was first described in the <\/span><a href=\"https:\/\/amplab.cs.berkeley.edu\/wp-content\/uploads\/2013\/10\/hat-vldb2014.pdf\"><span>Highly Available Transactions: Virtues and Limitations<\/span><\/a><span> paper and had a great influence on our design.<\/span><\/p>\n\n\n\n<p><span>With MAV we can provide an atomic commit at the read-point instead, which leads to a significant improvement in performance. Let\u2019s see how it works in practice:<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span>Repeatable Reads and Monotonic Atomic Views<\/span><\/h4>\n\n\n\n<p><span>In our transaction example, there is a fraction of time after <\/span><b>Step 4<\/b><span> where we have set the transaction in the ATR as \u201cCommitted\u201d but we haven\u2019t unstaged the data of the documents involved in the transaction yet. So what happens if another client tries to read the data during this interval?<\/span><\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-10992\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2021-03-22-at-5.40.37-PM.png\" alt=\"transaction failure scenario\" width=\"673\" height=\"640\"><\/p>\n\n\n\n<p><span>Internally, if by any chance the SDK finds a document that has staged content in it, it will also read the ATR to get the transaction state. If the state is \u201cCommitted\u201d, it will return the staged version instead. Boom! No need to synchronize writes if you can simply solve it WHEN it happens on read time.\u00a0<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>Durability in a Distributed Database<\/span><\/h3>\n\n\n\n<p><span>One of the most important jobs of a database is to ensure that what is written stays written. Even in the event of a node failure, no data should be lost. This is achieved in Couchbase through two features: Bucket Replicas and Durability in the SDK.<\/span><\/p>\n\n\n\n<p><a href=\"https:\/\/docs.couchbase.com\/server\/current\/manage\/manage-buckets\/create-bucket.html\"><span>During your bucket creation you can configure how many replicas (backups) of each document you want<\/span><\/a><span> (two is the most common choice). This option allows you to lose N number of nodes without implying any potential data loss.<\/span><\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10955\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2021-03-09-at-3.06.58-PM.png\" alt=\"Atomicity-new SQL\" width=\"620\" height=\"210\"><\/p>\n\n\n\n<p><span>Couchbase is configured by default to always take the fastest approach, so as soon as your data arrives on the server, an acknowledgment will be sent back to the client saying that your write was successful and all data replication will be handled under the hood. However, if your server fails before it gets the chance to replicate the data (we are talking about microseconds to a few milliseconds as the replication is made memory-to-memory) you might naturally lose your change. This might be fine for some low-value data, but .. hey! This totally violates the \u201cdurability\u201d in ACID. That is why we allow you to specify your <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/data\/durability.html#understanding-durability\"><span>durability requirements<\/span><\/a><span>:<\/span><\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-10967\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2021-03-09-at-3.36.43-PM-1024x77-1.png\" alt=\"durabilty options\" width=\"900\" height=\"68\"><\/p>\n\n\n\n<p><span>The <\/span><b>MAJORITY<\/b><span> (default option in the transaction\u2019s library) in the code above means that the mutation must be replicated to (that is, held in the memory allocated to the bucket on) a majority of the Data Service nodes. The other options are: <\/span><b><i>majorityAndPersistActive,<\/i><\/b><span> and <\/span><b><i>persistToMajority<\/i><\/b><span>. Please refer <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/data\/durability.html#durability-requirements\"><span>to the official documentation on durability requirements<\/span><\/a><span> to better understand how it works. This feature can also be used outside of a transaction in case you need to pessimistically guarantee that a document has been saved.<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span>What happens if something fails during a transaction?<\/span><\/h3>\n\n\n\n<p><span>You can configure how long your transaction should last before it is rolled back. The default value is 15 seconds. Within this timeframe, if there are concurrency or node issues, we will use a combination of wait and retry until the transaction reaches this time.<\/span><\/p>\n\n\n\n<p><span>If the client managing the transaction suddenly disconnects, it might leave some staged content on the document\u2019s metadata. However, other clients trying to modify the same document can recognize that the staged content can be overwritten as it is part of a transaction that already expired.<\/span><\/p>\n\n\n\n<p><span>Additionally, the transaction library will periodically run cleanups to remove non-active transactions from the ATRs to keep it as small as possible.<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>Distributed SQL Transactions with N1QL<\/span><\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><span>N1QL <\/span><span>is a query language that implements the SQL++ spec,\u00a0 it is compatible with SQL92 but designed for structured and flexible JSON documents. Learn more <\/span><a href=\"https:\/\/query-tutorial.couchbase.com\/tutorial\/#1\"><span>in this interactive N1QL tutorial<\/span><\/a><span>.<\/span><\/p>\n<\/blockquote>\n\n\n\n<p><span>The distributed transaction solution that we discussed so far is great for application-level transactions. But, sometimes we need to run ad hoc data changes. Or, due to the number of documents involved in the operation, manipulating them in the application memory becomes an expensive operation (e.g. adding 10 credits to all users\u2019 accounts). In Couchbase Server 7.0, you can run transactions through N1QL with virtually the same SQL syntax as most relational databases:<\/span><\/p>\n\n\n\n<p><a href=\"https:\/\/www.couchbase.com\/blog\/transactions-n1ql-couchbase-distributed-nosql\/\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-10968\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2021-03-12-at-2.18.31-PM-1024x834-1.png\" alt=\"NoSQL Transactions Vs Relational Transactions\" width=\"900\" height=\"733\"><\/a><\/p>\n\n\n\n<p><span>N1QL transactions have already been properly introduced at <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/couchbase-transactions-with-n1ql\/\"><span>Couchbase Transactions with N1QL<\/span><\/a><span> and <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/use-cases-and-best-practices-to-use-distributed-transactions-in-n1ql\/\"><span>&#8220;Use cases and Best Practices for Distributed Transactions through N1QL&#8221;<\/span><\/a><span>, so I won\u2019t deep dive on this topic. From a thousand-foot view, the transaction is managed by the <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/services-and-indexes\/services\/query-service.html\"><span>query service<\/span><\/a><span>. Since Couchbase is modular, you can increase your transaction throughput by scaling up or out your nodes running the query service.<\/span><\/p>\n\n\n\n<p><span>You can use both the N1QL and lambda transactions together, but using the transaction library only is preferred whenever possible<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>Conclusion: The Best NoSQL for Transactions<\/span><\/h2>\n\n\n\n<p><span>Couchbase already has had support for atomic single document operations and <\/span><a href=\"https:\/\/docs.couchbase.com\/java-sdk\/current\/howtos\/concurrent-document-mutations.html\"><span>Optimistic and Pessimistic Locking<\/span><\/a><span> for a long time. Last year, we introduced fast transactional support regardless of buckets, collections, scopes, or shards. With Couchbase 7.0 you can even use the same traditional relational transaction syntax. The combination of all these features makes <strong>Couchbase the best NoSQL for transactions at scale<\/strong>.<\/span><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span>Low Cost &#8211; Pay for what you use<\/span><\/h4>\n\n\n\n<p><span>The total transaction overhead is simply the number of document mutations + 3 (ATR marked as Pending, Committed, and Completed). For instance, running the money transfer example in a transactional context will cost you up to 5 additional calls to the database.\u00a0<\/span><\/p>\n\n\n\n<p><span>The transaction library is a layer on top of the SDK, we added support for transactions with zero impact on performance (something that other players can\u2019t easily claim). This could only be achieved thanks to our solid architecture.<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span>No Central Transaction Manager or Central Coordinator\u00a0<\/span><\/h4>\n\n\n\n<p><span>Given Couchbase\u2019s masterless architecture and the fact that clients are in charge of managing their own transactions, our implementation has no central coordination and no single point of failure.\u00a0<\/span><span>Even during a node failure, transactions that are not touching documents in the faulty server can still be completed successfully. In fact, with an appropriate max transaction time, even if you touch documents in a node that is failing, <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/clusters-and-availability\/failover.html\"><span>Couchbase\u2019s Node Failover <\/span><\/a><span>\u00a0can be fast enough to isolate the faulty server and promote a new node before your transaction expires<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span>No Internal Global Clock and no MVCC<\/span><\/h4>\n\n\n\n<p><span>Some transaction implementations require the concept of a global clock, which can be expensive to maintain without dedicated hardware in a distributed environment. In some cases, it can even bring the database down if the clock skew is higher than ~250 milliseconds.\u00a0<\/span><\/p>\n\n\n\n<p><span>With Multiversion Concurrency Control (MVCC) and global clocks, you can technically achieve higher levels of consistency. On the flip side, it will most likely impact the overall performance of the database. Couchbase supports the Read Committed consistency model, which is the same one that relational databases support by default.<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span>Flexibility<\/span><\/h4>\n\n\n\n<p><span>You can use the <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/data\/durability.html\"><span>durability options<\/span><\/a><span> inside and outside of a transactional context, use <\/span><a href=\"https:\/\/docs.couchbase.com\/java-sdk\/current\/howtos\/concurrent-document-mutations.html\"><span>optimistic and pessimistic locking<\/span><\/a><span> to avoid potential concurrency issues, and use transactions in the SDK and\/or via N1QL. There is a lot of flexibility for you to build any kind of application on top of Couchbase and fine-tune the performance according to your business needs.<\/span><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span>What is next?<\/span><\/h2>\n\n\n\n<p><span>Here are a few links for you to learn more about what we just discussed and to get started with Couchbase:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<tbody>\n<tr>\n<td><span>Learn more about transactions<\/span><\/td>\n<td><a href=\"https:\/\/www.couchbase.com\/transactions\/\"><span>https:\/\/www.couchbase.com\/transactions<\/span><\/a><\/td>\n<\/tr>\n<tr>\n<td><span>Java SDK transactions<\/span><\/td>\n<td><a href=\"https:\/\/docs.couchbase.com\/java-sdk\/current\/howtos\/distributed-acid-transactions-from-the-sdk.html\"><span>https:\/\/docs.couchbase.com\/java-sdk\/current\/howtos\/distributed-acid-transactions-from-the-sdk.html<\/span><\/a><\/td>\n<\/tr>\n<tr>\n<td><span>.NET SDK transactions<\/span><\/td>\n<td><a href=\"https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/howtos\/distributed-acid-transactions-from-the-sdk.html\"><span>https:\/\/docs.couchbase.com\/dotnet-sdk\/current\/howtos\/distributed-acid-transactions-from-the-sdk.html<\/span><\/a><\/td>\n<\/tr>\n<tr>\n<td><span>C++ SDK transactions<\/span><\/td>\n<td><a href=\"https:\/\/docs.couchbase.com\/cxx-txns\/current\/distributed-acid-transactions-from-the-sdk.html\"><span>https:\/\/docs.couchbase.com\/cxx-txns\/current\/distributed-acid-transactions-from-the-sdk.html<\/span><\/a><\/td>\n<\/tr>\n<tr>\n<td><span>N1QL Transactions<\/span><\/td>\n<td><a href=\"https:\/\/www.couchbase.com\/blog\/couchbase-transactions-with-n1ql\/\"><span>https:\/\/www.couchbase.com\/blog\/couchbase-transactions-with-n1ql\/<\/span><\/a><\/td>\n<\/tr>\n<tr>\n<td><span>Download Couchbase<\/span><\/td>\n<td><a href=\"https:\/\/www.couchbase.com\/downloads\/\"><span>https:\/\/www.couchbase.com\/downloads<\/span><\/a><\/td>\n<\/tr>\n<tr>\n<td><span>What&#8217;s New in Couchbase 7.0?<\/span><\/td>\n<td><a href=\"https:\/\/docs.couchbase.com\/server\/7.0\/introduction\/whats-new.html\"><span>https:\/\/docs.couchbase.com\/server\/7.0\/introduction\/whats-new.html<\/span><\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/figure>\n\n\n\n<p>\u00a0<\/p>\n","protected":false},"excerpt":{"rendered":"<p>ACID Transactions are a must when you have strict data consistency requirements in your application. The costs of running transactions on distributed systems can rapidly create bottlenecks at scale. In this article, we will give you an overview of some of the challenges faced by NoSQL and NewSQL databases. Then, we&#8217;ll deep dive into how [&hellip;]<\/p>\n","protected":false},"author":8754,"featured_media":1878,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[127,179,359],"tags":[],"ppma_author":[287],"class_list":["post-1879","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-couchbase-architecture","category-transactions"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.6 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Distributed Multi-Document ACID Transactions | Couchbase<\/title>\n<meta name=\"description\" content=\"When you have strict data consistency requirements in your application there will be challenges faced by NoSQL and NewSQL databases with ACID Transactions.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How we implemented Distributed Multi-document ACID Transactions in Couchbase\" \/>\n<meta property=\"og:description\" content=\"When you have strict data consistency requirements in your application there will be challenges faced by NoSQL and NewSQL databases with ACID Transactions.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-03-23T08:24:55+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/IntroductionToOttoman.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Denis Rosa, Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@deniswsrosa\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Denis Rosa, Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"21 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/\"},\"author\":{\"name\":\"Denis Rosa, Developer Advocate, Couchbase\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/fe3c5273e805e72a5294611a48f62257\"},\"headline\":\"How we implemented Distributed Multi-document ACID Transactions in Couchbase\",\"datePublished\":\"2021-03-23T08:24:55+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/\"},\"wordCount\":4255,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/IntroductionToOttoman.jpg\",\"articleSection\":[\"Application Design\",\"Couchbase Architecture\",\"Transactions\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/\",\"name\":\"Distributed Multi-Document ACID Transactions | Couchbase\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/IntroductionToOttoman.jpg\",\"datePublished\":\"2021-03-23T08:24:55+00:00\",\"description\":\"When you have strict data consistency requirements in your application there will be challenges faced by NoSQL and NewSQL databases with ACID Transactions.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/IntroductionToOttoman.jpg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/IntroductionToOttoman.jpg\",\"width\":1200,\"height\":628},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/distributed-multi-document-acid-transactions\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How we implemented Distributed Multi-document ACID Transactions in Couchbase\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"width\":\"1024\",\"height\":\"1024\",\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/fe3c5273e805e72a5294611a48f62257\",\"name\":\"Denis Rosa, Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f8d1f5c13115122cab89d0f229b904480bfe20d3dfbb093fe9734cda5235d419?s=96&d=mm&r=gbe0716f6199cfb09417c92cf7a8fa8d6\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f8d1f5c13115122cab89d0f229b904480bfe20d3dfbb093fe9734cda5235d419?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f8d1f5c13115122cab89d0f229b904480bfe20d3dfbb093fe9734cda5235d419?s=96&d=mm&r=g\",\"caption\":\"Denis Rosa, Developer Advocate, Couchbase\"},\"description\":\"Denis Rosa is a Developer Advocate for Couchbase and lives in Munich - Germany. He has a solid experience as a software engineer and speaks fluently Java, Python, Scala and Javascript. Denis likes to write about search, Big Data, AI, Microservices and everything else that would help developers to make a beautiful, faster, stable and scalable app.\",\"sameAs\":[\"https:\\\/\\\/x.com\\\/deniswsrosa\"],\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/author\\\/denis-rosa\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Distributed Multi-Document ACID Transactions | Couchbase","description":"When you have strict data consistency requirements in your application there will be challenges faced by NoSQL and NewSQL databases with ACID Transactions.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/","og_locale":"en_US","og_type":"article","og_title":"How we implemented Distributed Multi-document ACID Transactions in Couchbase","og_description":"When you have strict data consistency requirements in your application there will be challenges faced by NoSQL and NewSQL databases with ACID Transactions.","og_url":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/","og_site_name":"The Couchbase Blog","article_published_time":"2021-03-23T08:24:55+00:00","og_image":[{"width":1200,"height":628,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/IntroductionToOttoman.jpg","type":"image\/jpeg"}],"author":"Denis Rosa, Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_creator":"@deniswsrosa","twitter_misc":{"Written by":"Denis Rosa, Developer Advocate, Couchbase","Est. reading time":"21 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/"},"author":{"name":"Denis Rosa, Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/fe3c5273e805e72a5294611a48f62257"},"headline":"How we implemented Distributed Multi-document ACID Transactions in Couchbase","datePublished":"2021-03-23T08:24:55+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/"},"wordCount":4255,"commentCount":1,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/IntroductionToOttoman.jpg","articleSection":["Application Design","Couchbase Architecture","Transactions"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/","url":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/","name":"Distributed Multi-Document ACID Transactions | Couchbase","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/IntroductionToOttoman.jpg","datePublished":"2021-03-23T08:24:55+00:00","description":"When you have strict data consistency requirements in your application there will be challenges faced by NoSQL and NewSQL databases with ACID Transactions.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/IntroductionToOttoman.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/IntroductionToOttoman.jpg","width":1200,"height":628},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/distributed-multi-document-acid-transactions\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How we implemented Distributed Multi-document ACID Transactions in Couchbase"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","width":"1024","height":"1024","caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/fe3c5273e805e72a5294611a48f62257","name":"Denis Rosa, Developer Advocate, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f8d1f5c13115122cab89d0f229b904480bfe20d3dfbb093fe9734cda5235d419?s=96&d=mm&r=gbe0716f6199cfb09417c92cf7a8fa8d6","url":"https:\/\/secure.gravatar.com\/avatar\/f8d1f5c13115122cab89d0f229b904480bfe20d3dfbb093fe9734cda5235d419?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f8d1f5c13115122cab89d0f229b904480bfe20d3dfbb093fe9734cda5235d419?s=96&d=mm&r=g","caption":"Denis Rosa, Developer Advocate, Couchbase"},"description":"Denis Rosa is a Developer Advocate for Couchbase and lives in Munich - Germany. He has a solid experience as a software engineer and speaks fluently Java, Python, Scala and Javascript. Denis likes to write about search, Big Data, AI, Microservices and everything else that would help developers to make a beautiful, faster, stable and scalable app.","sameAs":["https:\/\/x.com\/deniswsrosa"],"url":"https:\/\/www.couchbase.com\/blog\/author\/denis-rosa\/"}]}},"acf":[],"authors":[{"term_id":287,"user_id":8754,"is_guest":0,"slug":"denis-rosa","display_name":"Denis Rosa, Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1879","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/8754"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=1879"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1879\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/1878"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=1879"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=1879"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=1879"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=1879"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}