In my previous post, I pointed out the simplicity of using XA transactions. However I used a diagram that made it appear XA was more complex.  While it’s true that XA is more complex than ignoring data consistency, the complexity is in the XA infrastructure and transaction coodinator and not in the developer’s code.  The key is that XA makes the developers life simpler by ensuring ACID data consistency without and application provided logic beyond demarcating the transactions boundaries.  The consistency is immediate, guaranteed, and with complete isolation which sagas give up and allow dirty reads. 

Dirty Reads

Dirty reads can lead to data inconstency as a decision may be made on stale data.  A classic example of this occurs when you have 2 overlapping sagas.  The first saga S1 deposit $100 into an account, but has not yet closed/finalized the saga.  The second saga S2 withdraws that $100 and closes/finalizes.  For some reason the first saga S1 ends up needing to be compensated, so its compensation logic tries to withdraw the $100 originally deposited.  However due to the dirty read made by S2, S1 may not be able to compensate as there may no longer be $100 to withdraw.  In sagas, this issue is typically pushed on to the developer as is seen in my second post in this series.  In that post, we can see that S1 doesn’t actually update the account balance as part of the deposit request, but instead that amount is effectively placed in escrow by keeping the amount in the journal until the saga completes.  This may not seem very complex, but this is also a trivial example and already one can see the complexity being pushed on to the developer by using sagas.

Purist vs Pragmatist

The microservice purist will claim that every service should have its own database, and that there should be no coupling between services such as introduced by a distributed transaction.  Likewise a data consistency purist (if there is such a term) will claim that ACID is the only acceptable solution and that isolation is absolutely necessary.  A pragmatist would say that both of those positions are extremes and trade-offs must be made.  In real life there aren’t many one size fits all solutions except maybe for scarves and headbands, and the same is true with software architectures.  Usually the best solution is somewhere between the extremes or at least a mix of the extremes. So how do you find that mix or make those trade-offs?

Making Trade-offs

It’s key to understand why you choose a specific solution to dealing with the issue of data consistency.  Choosing sagas simply because you’re a microservice purist ignores the real world issues of adopting an eventual consistency pattern.  Likewise choosing strong consistency via ACID simply because you’re a data purist makes little sense.  One must examine what trade-offs are being made in choosing one over the other and the same decision doesn’t need to be made for all of your microservices.  One of most common examples of when it really makes sense to use a saga is when the data that needs to be updated consistently is in flux for a relatively long period of time such as waiting for user input.  While one could use ACID transactions such as XA, it’s generally not recommended due to the increased potential for lock contention.  However if you’re designing an application that requires immediate consistency, it’s hard to beat XA, especially considering how easy it is to use.

Sagas, Escrow, and Oracle Database

In my next post I describe how Oracle Database sagas, externally managed by MicroTx, can automatically handle the escrowing of the funds using RESERVABLE columns.  RESERVABLE columns can allow multiple transactions to update a row concurrently by not locking the row.  I get into the details of how that works in this next post.

For more information on MicroTx, please visit here.  To get started right away, check out this quick start guide.