How to design global distributed transaction(none database)? Can JTA use for none db transaction?
Asked Answered
B

3

17

I think this is a fairly common question: how to put my business logic in a global transaction in distributed systems environment? Cite an example, I have a TaskA containing couples of sub tasks:

TaskA {subtask1, subtask2, subtask3 ... }

each of these subtasks may execute on local machine or a remote one, I hope TaskA executes in an atomic manner(success or fail) by means of transaction. Every subtask has a rollback function, once TaskA thinks the operation fails(because one of subtask fails), it calls each rollback function of subtasks. Otherwise TaskA commits the whole transaction.

To do this, I follow "Audit trial" transaction pattern to have a record for each subtask, so TaskA can know operation results of subtasks then decide rollback or commit. This sounds like simple, however, the hard part is how to associate each subtask to the global transaction?

When TaskA begins, it starts a global transaction about which subtask knows nothing. To make subtask aware of it, I have to pass the transaction context to every invocation of subtask. This is really dreadful! My subtask may either execute in a new thread or execute in remote by sending a message through AMQP broker, it's hard to consolidate the way of context propagation.

I did some research like "Transaction Patterns - A Collection of Four Transaction Related Patterns", "Checked Transactions in an Asynchronous Message Passing Environment", none of these solve my problem. They either don't have practical example or don't solve the context propagation issue.

I wonder how people solve this? as this sort of transaction must be common in enterprise software.

Is X/Open XA only the solution for this? Can JTA help here(I have't look into JTA as most stuff for it relate to database transaction, and I am using Spring, I don't want to involve another Java EE application server in my software).

Can some expert share some thoughts with me? thank you.

Conclusion

Arjan and Martin gave out really good answers, thank you. Finally I didn't go with this way. After more research, I chose another pattern "CheckPoint" 1.

Looking into my requirement, I found my intention to "Audit Trial Transaction Pattern" is to know which level the operation has proceeded to, if it's failed, I can restart it at the failed spot after reloading some context. Actually this is not transaction, it didn't rollback other successful steps after failure. This is essence of CheckPoint pattern. However, studying distributed transaction stuff makes me learned lot of interesting things. Apart from what Arjan and Martin have mentioned. I also suggest people digging into this area take a look at CORBA which is a well-known protocol for distributed system.

Boyceboycey answered 20/3, 2012 at 22:0 Comment(2)
today I read JTA stuff, I think it's way to go, I need to implement my XAResource to integrate into global transaction. This is a funny topic, looks like not many people have done it before. I am continue investigating.Boyceboycey
In fact, EJB calls between Java servers thanks to RMI/IIOP is "almost" CORBA. Some vendors are CORBA-compliant, others are not.Barros
B
11

You're right, you need two-phase commit support thanks to a XA transaction manager provided by the JTA API.

As far as I know Spring does not provide a transaction manager implementation itself. The JtaTransactionManager only delegates to existing implementation usually provided from JavaEE implementations.

So you will have to plugin a JTA implementation into Spring to get effective job done. Here are some proposals:

Then you will have to implement your resource manager to support two-phase commit. In the JavaEE worlds, it consists in a resource adapter packaged as a RAR archive. Depending on the type of resource, the following aspects are to read/implement:

As examples, I recommend you to look at implementations for the classical "transactions with files" issue:

Barros answered 21/3, 2012 at 20:50 Comment(0)
A
7

If you want to write your own transactional resource, you indeed need to implement an XAResource and let it join an ongoing transaction, handle prepare and commit requests from the transaction manager etc.

Datasources are the most well known transactional resources, but as mentioned they are not the only ones. You already mentioned JMS providers. A variety of Caching solutions (e.g. Infinispan) are also transactional resources.

Implementing XAResources and working with the lower level part of the JTA API and the even lower level JTS (Java Transaction Service) is not a task for the faint of heart. The API can be archaic and the entire process is only scarcely documented.

The reason is that regular enterprise applications creating their own transactional resources is extremely rare. The entire point of being transactional is to do an action that is atomic for an external observer.

To be observable in the overwhelming majority of cases means the effects of the action are present in a database. Nearly each and every datasource is already transactional, so that use case is fully covered.

Another observable effect is whether a message has been send or not, and that too is fully covered by the existing messaging solutions.

Finally, updating a (cluster-wide) in memory map is yet another observable effect, which too is covered by the major cache providers.

There's a remnant of demand for transactional effects when operating with external enterprise information systems (EIS), and as a rule of thumb the vendors of such systems provide transaction aware connectors.

The shiver of use cases that remain is so small that apparently nobody ever really bothered to write much about it. There are some blogs out there that cover some of the basics, but much will be left to your own experimentation.

Do try to verify for yourself if you really absolutely need to go down this road, and if your need can't be met by one of the existing transactional resources.

Atheist answered 21/3, 2012 at 20:52 Comment(0)
E
0

You could do the following (similar to your checkpoint strategy):

  1. TaskA executes in a (local) JTA transaction and tries to reserve the necessary resources before it delegates to your subtasks

  2. Subtask invocations are done via JMS/XA: if step 1 fails, no subtask will ever be triggered and if step 1 commits then the JMS invocations will be received at each subtask

  3. Subtasks (re)try to process their invocation message with a JMS max redelivery limit set (see your JMS vendor docs on how to do this)

  4. Configure a "dead letter queue" for any failures in 3.

This works, assuming that:

-retrying in step 3 makes sense

-there is a bit of human intervention needed for messages in the dead letter queue

If this is not acceptable then there is also TCC: http://www.atomikos.com/Main/DownloadWhitepapers?article=TccForRestApi.pdf - this can be seen as a "reservation" pattern for REST services.

Hope this helps

Guy

http://www.atomikos.com

Elenor answered 22/7, 2015 at 8:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.