Guaranteed order of updates is claimed to be hard in distributed systems. It's not - if you read this…

The Problem

Suppose you want to apply updates in the same order across different parts of a distributed system. For instance, perhaps you want to keep 2 inventory database replicas in-sync with TransactionsEssentials. Now imagine two distributed (JTA/XA) transactions T1 and T2, each updating the two replicas of the inventory of the same product P:

  • T1 wants to update both replicas to set the stock of P to 3, and
  • T2 wants to update both replicas to set the stock of P to 2

If T1 and T2 update each database in a different order, then the inventory of P would end up being 2 in one replica, and 3 in the other. Now they are not replicas any more… So can we avoid that? Yes, we can! Read on to learn how…

Order-Preserving Writes With JDBC

First, let's take the case of a primitive application that updates the two databases directly (via JDBC):

Screenshot 2018-10-11 16.41.18.png

The Application

We're assuming that the application is a transactional Java application that uses the Atomikos transaction manager. It's the application that takes care of the replication (contrast this to DBMS-internal replication which is not even required here).

DBMS 1

The first replica database. We assume that this database uses locking to protect the data from concurrent transactions.

DBMS 2

The second replica database. We assume that this database uses locking to protect the data from concurrent transactions.

The Solution

The solution is pretty simple:

  • If both DBMS use locking, and
  • If both transactions T1 and T2 use two-phase commit as per TransactionsEssentials

… then the order of the writes is guaranteed to be the same at both databases. Now, how much simpler can it get?

Order-Preserving Writes With Microservices (REST or SOAP)

So what if we want to have microservices instead? That's no problem, but you'll need ExtremeTransactions to do the same thing across microservices.

The Application

Now the application is a transactional Java application that uses ExtremeTransactions. Once again, it's the application that takes care of the replication - but this time by calling two microservices:

Screenshot 2018-10-11 16.42.11.png

Microservice 1

This service manages the first replica database. We assume that the database uses locking to protect the data from concurrent transactions.

Microservice 2

This service manages the second replica database. We assume that the database uses locking to protect the data from concurrent transactions.

The Solution

The solution is exactly the same as in the previous case, but the application and each microservice need to use ExtremeTransactions so everything is part of one and the same distributed transaction.

Why Does This Work?

The reason that this works is thanks to the combination of locking and two-phase commit. The logic relies on two specific behavioural properties:

  1. The order of the updates by T1 and/or T2 in each DBMS corresponds to the order of lock acquisition by T1 and/or T2.
  2. In either DBMS, T1 can only acquire a lock on P after T2 commits (or vice versa, whichever transaction gets a lock first).
  3. Either transaction will only commit after it has acquired all its locks on P (meaning, a lock on P in both databases).

The proof is by contraction: supposed that T1 updates first in DBMS 1 and T2 updates first in DBMS 2. That would imply that:

  • T1 commits before T2 in DBMS 1, which by (3) would imply that T1 has gotten all its locks first in both DBMS.
  • T2 commits before T1 in DBMS 2, which by (3) would imply that T2 has gotten all its locks first in both DBMS.

Conclusion: both cannot be true at the same time, so it is impossible for the order of updates to be different in either DBMS.

It should be easy to see how this can be generalised to non-replica scenarios. The locks don't need to be on replicated items, they can be on any item concurrently accessed by either transaction and the same conclusion would hold.

By the way, a very nice property of this solution is that this works regardless in what order T1 and T2 are trying to access either service or database. The DBMS lock manager will take care of that…

Pitfall

The proof does not hold if locks are released before commit time. This should not be a problem since usually, locks are not released before commit.

Verification of this is left as an exercise to the reader.

What about deadlocks?

Some critics will claim that distributed transactions cause deadlocks. That's possible, but at least distributed transactions will break deadlocks after a timeout. You can always have deadlocks even if using only one database, and (what's worse) without distributed transactions there will typically be NO timeout for those.

This also works for exactly-once delivery

Actually, this solution also works for exactly-once delivery - which is really cool don't you think?

Ready to Try? Apply here for a free trial of ExtremeTransactions

  • ENJOY FREE EVALUATION SUPPORT: get on-boarded fast - no need to wait for paperwork
  • Evaluate the full set of power functionality exclusive to customers
  • Avoid late risks by upgrading to the real thing today - so you're all configured to go live without stress
  • No rush or hard deadlines - pay only when you're happy and ready to go live

Tell us about yourself

Name
Email
Phone
Company
Industry
Timing
Please specify the timeframe in which you would be going live with your project.

Start My Free Trial

Our privacy policy is brief and clear: we do not sell the information you give us. Plus, we'll send you relevant content (only).

Contact Us

Atomikos Corporate Headquarters
Hoveniersstraat, 39/1, 2800
Mechelen, Belgium

E info@atomikos.com
E sales@atomikos.com
T +3215613055

Subscribe to our newsletter

Never miss an update

Copyright 2018 Atomikos BVBA
This website is using cookies. More info. That's Fine