In my last post, I explained how the Oracle Transaction Manager for Microservices (MicroTx) can help applications adopt microservices without giving up consistency. In this post I’ll show how easy it is for a microservices based application to adopt XA transactions to ensure strong consistency. The XA distributed transaction protocol is one of the most widely used distributed transaction protocols in the world. Virtually every application server, transaction processing monitor, database, and messaging system provides support for XA transactions.
If we replace a monolithic application with a set of microservices using XA transactions, we will see something like the following picture. A client or other microservice calls microservice A, which starts the XA transaction by calling the Transaction Manager. A’s business logic updates its resource manager and calls B which also calls the transaction manager to enlist in the transaction. B’s business logic does some updates to its resource manager and calls C. Likewise, C calls the transaction manager to enlist in the transaction and its business logic updates its resource manager. Finally, A calls the transaction manager to commit or rollback the transaction. The transaction manager then prepares and commits A, B, and C’s resource managers or rolls them back.
Figure 1 Multiple Resource Managers
Which is a little complicated and we’ll explain how this can be simplified.
Simplifying XA Transactions for Microservices
XA transactions are often considered an anti-pattern in microservices because of the perceived complexity and the potential for performance issues due to locking. There are many articles decrying the use of XA transactions in microservices because of these potential issues. While it is certainly true that XA transactions can be problematic, the same can be said about any solution to distributed consistency. The question in some sense is whether one trusts the implementation of the transaction manager in the case of XA, or one trusts their developers to correctly code the completion and compensation functions under all failure scenarios in eventual consistency models. Transaction managers tend to be well tested and highly available.
Part of the perceived difficulty in using XA are all the interactions that must take place. However, these can easily be hidden from the application developer and make their lives far easier than trying to hand code compensation logic required for eventual consistency. In its simplest form, an application using XA, only needs to demarcate the transactions boundaries. Handling the commitment or rolling back of the transaction is left up to the transaction manager and associated resource managers.
One of the major differences between XA and Sagas or Try-Confirm/Cancel is that XA participants hold locks for the duration of the transaction. Sagas and Try-Confirm/Cancel use local transactions that only span the duration of the participant’s business logic. Otherwise, from the developer’s perspective they are all very similar. An initiator starts the distributed transaction, invokes one or more participant microservices which enlist in the transaction, and then decides to commit/complete/confirm or rollback/compensate/cancel the transaction.
The major difference between XA and either Sagas or Try-Confirm/Cancel comes from what happens once the initiator has decided to commit/complete/confirm the transaction. In XA, the transaction manager uses a two-phase commitment protocol whereas Sagas and Try-Confirm/Cancel use a one-phase commitment protocol. However, these differences should largely be up to the transaction manager to deal with and not the microservices themselves.
In XA, the flow is as follows:
1. Initiator starts the distributed transaction
2. Called microservices enlist in the transaction
3. Initiator asks transaction manager to commit or rollback the transaction
4. If the initiator decided to commit, the transaction manager asks each microservice to prepare
1. If all participants successfully prepare, they are all asked to commit
2. If any of the participants fail to prepare, they are all asked to rollback
5. If the initiator decided to rollback the transaction, the transaction manager asks each microservice to rollback
In LRA and TCC, the flow is as follows:
1. Initiator starts the distributed transaction
2. Called microservices enlist in the transaction
3. Initiator asks transaction manager to complete/confirm or compensate/cancel the transaction.
4. Transaction manager asks each enlisted microservice to complete/confirm or compensate/cancel
The primary differences are around what the transaction manager must perform and for Sagas what participants must provide in their business logic to complete or compensate the transaction. With XA there is no application logic required to perform the commit or rollback functions as these are handled by the infrastructure and resource managers.
XA RM Proxy
In the XA protocol, the transaction manager needs to communicate with the resource managers to complete committing or rolling back the resource managers involvement in the transaction. In a monolithic application this is trivial as the transaction manager is essentially built into the monolithic application, typically by using an application server such as WebLogic Server or Tuxedo. So, a monolithic application already has connections to the resource managers. In the microservices world, each microservice may have its own resource manager. Thus, the transaction manager would need to connect to each resource manager to prepare/commit/rollback the transaction. This means the transaction manager must have unique client libraries and credentials for each resource manager that is used by the microservices. This makes it very difficult for a transaction manager to support an arbitrary set of resource managers.
Figure 2 Without RM Proxy
To solve this problem in MicroTx, a resource manager proxy is provided by the MicroTx client libraries. When the transaction manager needs to prepare/commit/rollback a participating resource manager, it simply makes a callback to the microservice and the proxy relays the request to the resource manager being used by the microservice. These REST based callbacks allow the transaction manager to be agnostic to the resource manager being used by the microservice. However, this also means that participant microservices must use the MicroTx client libraries which registers the callbacks and provides the implementation of the callbacks for the resource manager being used.
Figure 3 With RM Proxy
Request/Reply Interceptors
Another issue in any distributed transaction protocol is how to handle enlistment in the transaction for a microservice. In MicroTx, interceptors are provided in the MicroTx client libraries to intercept both incoming and outgoing REST calls and their replies and responses. These interceptors use headers to propagate the transaction context such that called microservices can automatically be enlisted in the transaction by the interceptor. The interceptors also ensure the appropriate transaction headers are propagated in any outgoing REST call.
The typical flow looks like:
Figure 4 Interceptors
When a microservice using the MicroTx client libraries makes an outbound REST request, the library’s interceptors will add transaction headers to the outbound request if the microservice has started a distributed transaction or is currently participating in a distributed transaction. When the recipient of the request receives the request, the interceptors in the recipient will see the transaction headers and automatically enlist the participant in the distributed transaction. As well for XA, the interceptors will automatically start an XA transaction on the participant’s resource manager.
Adopting XA Transactions in a Microservice Based Applications
For microservices to use XA with MicroTx, the only significant changes required are to:
1. Include the MicroTx client library in their microservice implementation
2. Use CDI annotations or MicroTx client library APIs to register the required interceptors and callbacks
3. Use CDI annotations or MicroTx client library APIs in participant microservices to obtain the connection to their XA compliant resource manager.
4. Use MicroTx client libraries API to delineate transaction boundaries indicating an XA transactions has been started, and then committing or rolling back the transaction.
Source: oracle.com
0 comments:
Post a Comment