java - JMS事务如何与并发使用者一起工作?

标签 java jms ibm-mq messaging

嘿,我有一个需要顺序处理的消息队列。现在,此处理涉及调用Web服务(有时可能会关闭),因此我必须使消息检索具有事务性。据我所知,当中途有任何异常时,整个交易都会回滚,消息不会丢失吗?

但是,还需要消息使用者具有高可用性,因此我在队列中有两个侦听器实例。现在,事务将确保在第一个消息完全处理完第一个消息之前,侦听器的另一个实例不会检索到第二个消息吗?还是我需要做更多的事情来确保在完全处理之前,没有消息从队列中发送出去。

如果需要任何其他配置,是在MQ中还是在侦听器中?

我正在使用websphere mq作为消息代理和spring集成来检索消息。谢谢您的帮助。

编辑:

对于 token 而言,首先要考虑的是队列管理器本身的高可用性。持有此 token 的队列必须是某个队列管理器的一部分。现在,如果我们进行了故障转移,该控制队列将不再可访问。这有点意味着在发生故障转移时,我们需要准备另一个控制队列。

但是,在正常操作期间,我们不能让监听器监听该DR控制队列。 (假设我们有一种机制可以确保“数据”队列得到完美复制)。侦听器实例应知道故障转移已启动,以便它可以在正常操作期间停止侦听控制队列并切换到辅助节点。我不能仅使用侦听器实例来做到这一点。将消息放入队列中的实际生产者将必须通知侦听器实例,以停止侦听正常的ops控制队列并切换到辅助侦听器。如果存在任何中间连接问题(并且普通的ops队列管理器并没有真正关闭),这将有些棘手,但这太过分了。

在控制队列的高可用性得到照顾的情况下,我们有点像在低负载情况下不可共享的问题。现在,我们的负载偶尔会出现峰值,但会有低迷时期。 (晚上和东西)。这个 token 系统真的不是反应性的吧?这更多是周期性的事情。假设我们几个小时都没有收到任何消息。侦听器仍将不断检查队列,因为 token 消息不断触发另一个实例。哪个或多或少实际上使它成为了一个轮询器。我还可以有多个侦听器实例,每个实例在每小时的不同时间进行轮询,对吗?它本身并不是事件驱动的。

第三,实际上是插入 token 消息的问题。在首次安装或故障回复期间,我们将获得手动插入此 token 的额外手动步骤(因为该 token 有时会在故障转移中丢失)。我们真的不能让其中一个侦听器实例执行此操作,因为如果侦听器实例找不到消息,则有点意思是其他侦听器实例具有 token 。因此,此逻辑必须分开。而且,如果我们实际上在此 token 消息中添加了一些有意义的信息,则它必须是必须被触发的实用程序,而不是通过UI插入的实用程序。

我猜第一个和第三个并不是真正的问题,但是只是额外的开销,如果我们要进行轮询器实现,则将不需要这些开销。第二个是最让我困扰的事情。

最佳答案

您需要传递 token 。运作方式如下:

首先,创建第二个队列并将单个消息放入其中。现在,使用以下逻辑启动每个程序。

  • 使用无限或较长的等待时间间隔和FAIL_IF_QUIESCING选项在同步点下的 token 队列中获取 token 消息。
  • 将 token 消息放回同一UOW中的 token 队列中。
  • 从同一UOW下的应用程序队列中获取下一条消息。
  • 正常处理应用程序的消息。
  • 提交UOW。

  • 您可以根据需要使用任意数量的应用程序实例。您将在每个应用程序实例的两个队列中的每个队列上看到一个输入句柄。没有应用实例会因为排他性使用队列而处理错误。

    由于只有一个 token 消息,并且一次只有一个应用程序可以将其保持在同步点下,因此只有一个应用程序可以积极地处理应用程序消息。由于应用程序队列之外的GET取决于 token 队列之外的成功GET,因此将严格按顺序处理所有应用程序消息。

    注意:应用程序将使用与 token 队列中的 token 消息一样多的并发线程来处理应用程序消息。如果有人曾经向 token 队列添加另一个 token 消息,则严格的序列处理将丢失。因此,除应用程序服务帐户外,不得将对该队列的读/写访问权限授予任何人。而且,通常会对该 token 消息进行结构化,以便应用程序可以识别它。如果杂散无关的消息降落在该位置,则应用程序应忽略它并发出警告。

    您将看到两个应用程序之间的消息分布相当均匀。如果您使用两个以上的应用程序,则可能会看到分布不均的情况,因为队列句柄是在堆栈中管理的。当实例提交其UOW时,下一个实例的句柄在堆栈的顶部,因此它获取下一条消息。在处理该消息时,刚刚提交的实例会将其GET放在堆栈顶部。如果您有3个或更多侦听实例,则只有前两个机会看到任何流量。

    这样可确保一次将消息从队列中处理一次。它不会而不是以确保您不会受骗。

    如果您在同步点下进行所有操作,则不会丢失任何消息。但是,在某些情况下,将检索和处理一条消息,然后COMMIT调用将失败。在这种情况下,事务将回滚,并且相同的消息将再次变为可用。如果您使用的是一阶段提交,而不是XA,则对该消息的处理将不会回滚。

    令人高兴的是, token 消息也将在同步点下,并且解决了孤立的客户端通道花一些时间才能释放事务的问题。新的连接将获得比孤立事务在同步点下保存的消息更旧的消息。最终,通道代理超时,将消息释放回队列,但实际上将其位置更改为在隔离消息时处理的任何消息之后。

    在这种情况下, token 消息也被隔离,因此在这种类型的连接丢失消息处理之后,暂时停止处理并等待通道代理超时。如果发生这种情况,只需在具有UOW的实例上发出STOP CHANNEL命令即可。

    根据针对此答案的其他问题详细信息进行更新

    持有此 token 的队列必须是某个队列管理器的一部分。
    现在,如果我们进行了故障转移,则该控制队列将不再是
    无障碍。这有点意味着我们需要另一个控制队列
    在发生故障转移时准备就绪。

    token 队列与应用程序队列一样可用或不可用。只需要一个。如果应用程序需要HA,则应使用多实例QMgr或硬件HA群集。这些共享磁盘使故障转移中出现的QMgr与应用程序已连接到的磁盘相同,只是位于不同的物理位置。

    如果应用程序需要灾难恢复,则可以将QMgr的日志和数据目录下的磁盘复制到灾难恢复站点。但是,在主数据中心中进行处理时,没有任何实例可以监听这些实例。

    侦听器实例应知道故障转移已启动,因此
    它可以在正常操作期间停止监听控制队列,并且
    切换到辅助。我无法使用监听器执行此操作
    仅实例。

    为什么不? WMQ拥有可重新连接的客户端已有很长时间了,而v7.0.1中的多实例功能使重新连接drop-dead变得简单。作为管理员,您的工作是确保最多有一个应用程序和 token (不是触发器!)队列可用。在中断期间,客户端无需任何应用程序代码即可重试。它查找任何实例启动并进行连接。

    将消息放入队列的实际生产者将不得不
    通知侦听器实例停止侦听正常操作
    控制队列并切换到辅助队列。

    问题是与并发使用者进行序列化。这是关于一种设计,生产者和消费者必须在一个共同的位置会合。恰好与此序列重叠的另一个问题是序列化使它有些复杂。询问其他问题是否需要探索拓扑。

    这个 token 系统不是真的
    反应性吧?这更多是周期性的事情。所以说我们没有得到
    几个小时的任何消息。听众仍会不断
    检查队列,因为 token 消息不断触发一个实例
    接another而至。

    这不使用触发。它使用 token (不是触发器!)消息,就像文件系统或数据库使用锁来促进序列化一样。无论哪个侦听器获取 token 消息,然后在应用程序队列上进行无限等待即可获取。其他侦听器在 token (没有触发!)队列上有无限等待的获取。基本上,他们闲着闲着直到消息到达。零重新连接,零轮询,零CPU周期。如果您需要知道它们还活着,请不时让它们在应用程序队列中超时。这会在 token 队列上回滚其UOW, token 队列将 token 传递给另一个侦听器。

    第三,实际上是插入 token 消息的问题。
    在首次安装或故障回复期间,我们将获得额外的收益
    手动插入此 token 的手动步骤(因为该 token 将是
    有时会因故障转移而丢失)。

    为什么?您是否经常遇到MQ在同步点下丢失持久性消息的情况?如果是这样,则说明您做错了。 ;-)在有严格序列化要求的情况下,队列只能有一个 Activity 实例。如果由于某种原因,除了通过磁盘复制以外,还有其他预定义的应用程序队列实例,则将在 token 队列旁边同时预定义一个 token (未触发!)实例,并在每个队列中等待一个 token (未触发!)消息。队列。面对严格的消息顺序要求,当然没有人会做这种事情,但是如果他们这样做了,那些队列肯定会在不使用时被禁用。

    我们真的不能成为听众之一
    实例这样做是因为,如果侦听器实例找不到消息
    有点意思是其他监听器实例具有 token 。

    正确。侦听器可以检查队列深度,事务,输入句柄等,但是通常明智的做法是避免将应用程序逻辑与控制逻辑混合在一起。

    所以
    这种逻辑必须分开。如果我们实际上投入一些有意义的
    信息添加到此 token 消息中,它必须是一个实用程序,必须
    触发,而不是通过用户界面进行插入。

    为什么?您的编码人员可以处理应用消息中的结构化数据,对吗?如果认为这要困难得多,那说明有人做错了。 ;-)将格式化 token (不是触发器!)消息的实例写入队列,然后将其卸载到文件中。当您需要重新初始化队列时,请使用Q或QLoad首先清除队列,然后将文件加载到其中。 实用程序将是在执行魔术之前打开队列以供排他使用,检查深度,检查手柄等的工具。当我向客户咨询时,通常会定义一个服务,该服务在MQ启动时初始化队列,并在应用程序GUI中为操作和支持人员提供功能。只要管理 token (而不是触发器)队列的应用程序在这些操作期间将其获得排他性访问,它的执行方式或控制应用程序的实例数实际上就无关紧要。

    通常,我还使用消息中的结构将命令发送给侦听器。有真正的 token 消息,然后有消息命令应用程序实例执行操作。例如,具有非事务性的“ping”功能真的很好。如果我在单个UOW中在 token (而不是触发器!)队列上丢弃了更多的ping消息,而不是让我的应用程序实例在监听,则可以保证与他们联系。这样我就可以发现僵尸了。取决于需要多少工具,侦听器可以通过在日志,控制台,事件队列等中提供状态(正常运行时间,已处理消息等)来对ping做出反应。

    我猜第一个和第三个不是真正的问题,只是额外的
    如果我们去投票站则不需要
    实施。

    很好,因为这都是非常标准的东西。问题主要在于与HA / DR的序列化需求冲突。您正在寻找的是全局事务原子性,以实现跨多个物理位置的单个逻辑队列。尽管WAS消息引擎已经提供了,但IBM MQ从未尝试提供该功能。最接近的MQ是使用两个具有消息和事务数据的内存到内存复制功能的MQ设备,但这在光速延迟开始显着影响吞吐量之前只有几英里之遥。它不能满足您的灾难恢复需求。实际上,如果要在DR数据中心上将恢复点设置为零,那么除了同步复制外,其他操作都不会做。

    关于java - JMS事务如何与并发使用者一起工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33637289/

    相关文章:

    java - 如何输入字符作为输入以跳出寻找整数的循环?

    java - 将字符串压缩为a2b3...等

    java - Linux 高 CPU 负载上的 HornetQ 消费者

    c# - MessageListener,是否会获取并发消息

    java - PostgreSQL 找不到列

    ejb-3.0 - 在MQ系列中配置 'retry delay'

    java - 有什么方法可以确保 JMS 事件发生或告诉 JMS 事件在特定时间开始和完成?

    java - 解析长日志文件时出错?

    java - IBM 中的 MQJE001 : Completion Code '2' , 原因 '2033' 问题仅用于获取一些消息

    java - 邮件发送问题