我有一个架构问题,关于如何在Java / Java EE中处理事务性和可伸缩性的大任务。
一般挑战
我有一个Web应用程序(Tomcat现在,但不应该限制解决方案空间,所以只需要用它来说明我想要实现的目标)。这个Web应用程序分布在几个(虚拟和物理)节点上,连接到中央DBMS(在这种情况下是MySQL,但同样,这不应该限制解决方案......)并且能够处理大约1000个用户,服务页面,正如你对平均基于网络的信息系统所期望的那样,做一些事情。
现在,有些任务影响了大部分数据,系统应该进行优化,以便合理地快速执行这些任务。 (比顺序处理所有内容更快,即)。因此,我将任务并行化并将其分布在多个(或所有)节点上:
(注意:处理的数据部分是独立的,因此这里没有数据库或锁定冲突。)
问题是,我希望(整个)任务是事务性的。因此,如果其中一个并行子任务失败,我希望将所有其他任务作为结果回滚。否则,从域的角度来看,系统可能处于可能不一致的状态。
当前实施
正如我所说,当前的实现使用Tomcat和MySQL。节点使用JMS进行通信(因此有一个JMS服务器,调度程序为每个子任务发送消息;执行程序从消息队列中获取任务,执行它们,并将结果发布到调度程序收集的结果队列中。调度程序阻塞并等待所有结果进入,如果一切正常,它将以OK状态终止。
这里的问题是所有执行程序都有自己的本地事务上下文,所以图片看起来像这样:
如果由于某种原因导致其中一个子任务失败,则会回滚本地事务,并且调度程序会收到错误结果。 (这里有一些故障保护机制,它试图重复失败的事务,但由于某种原因,我们假设一个任务无法完成)。 问题是系统现在处于一个状态,其中除了一个之外的所有事务都已提交并完成。而且因为我不能让最后一笔交易成功完成,所以我无法摆脱这种状态。
可能的解决方案
这些是我到目前为止所遵循的想法:
我自己可以以某种方式实现特定于域的回滚机制。因为分发器知道已经执行了哪些任务,所以它可以明确地恢复效果(例如,在某处存储旧值并将已提交的值恢复回先前的值)。当然,在这种情况下,我必须保证其他任何进程都不会发生变化,所以只要大运行正在运行,我也必须将系统设置为只读状态。 或多或少,我需要在业务逻辑中模拟交易...
我可以选择不在一个大事务中并行化并在一个节点上执行所有操作(但正如开头所述,我需要加快处理速度,因此这不是一个选项...)
我一直试图找出有关XATransactions或分布式事务的信息,但这似乎是一个高级的Java EE功能,它并没有在所有Java EE服务器中实现,并且无法真正解决这个基本问题,因为似乎没有办法将事务上下文转移到异步调用中的远程节点。 (例如EJB Specification 3.1的第4.5.3节:"客户端事务上下文不会通过异步方法调用传播。从Bean Developer的视图来看,永远不会有来自客户端的事务上下文。 " )
问题
我忽略了什么吗?是不是可以在多个节点上异步分发任务,同时具有可以作为一个整体回滚的(共享)事务状态?
感谢您提出任何建议,提示和建议......
答案 0 :(得分:1)
如果您想按照描述分发您的应用程序,JTA是您在Java EE环境中的朋友。由于它是Java EE规范的一部分,因此您应该能够在任何兼容容器中使用它。与规范的所有实现一样,细节或配置也存在差异,例如JPA,但在现实生活中,经常更换应用程序服务器非常罕见。
但是在不知道问题的细节和复杂性的情况下,我的建议是重新考虑是否真的需要为一个用例共享任务执行,或者如果不可能并且更好地至少拥有属于该用例的所有内容即使您可能需要多个节点用于整个应用程序,但在一个节点内的情况。如果你真的必须使用几个节点来满足你的需求,那么我会选择不直接写入数据库的分布式任务,而是返回结果,然后在启动任务的一个组件中提交/回滚它们。
在过度使用架构之前,不要忘记先测量。首先尝试保持简单,假设一个节点可以处理它,然后编写压力测试,试图破坏您的系统,了解它可以使用给定的体系结构处理的最大可能负载。