嘿,我有一个需要顺序处理的消息队列。现在,此处理涉及调用Web服务(有时可能会关闭),因此我必须使消息检索具有事务性。据我所知,当中途出现异常时,整个事务回滚,消息不会丢失,对吗?
但是还需要消息消费者的高可用性,因此我有两个侦听器实例侦听我的队列。现在,事务是否确保侦听器的另一个实例在第一个实例完全处理完第一个消息之前不会检索第二个消息?或者我必须做更多的事情来确保没有消息被发送出队列,直到之前的消息完全完成处理。
如果需要任何额外的配置,是在MQ中还是在侦听器上?
我使用websphere mq作为消息代理和spring集成来检索消息。谢谢你的帮助。
编辑:
对于令牌,首先要考虑的是队列管理器本身的高可用性。持有此令牌的队列必须是某个队列管理器的一部分。现在,如果我们有一个故障转移,那么控制队列将不再是可访问的。这意味着我们需要另一个控制队列准备好,以防故障转移。我们不能让监听器在正常操作期间监听DR控制队列。(假设我们有一种机制来确保"数据"队列被完美地复制)。侦听器实例应该知道故障转移已经启动,以便它可以在正常操作期间停止侦听控制队列,并切换到辅助操作。我不能单独使用侦听器实例来做到这一点。将消息放入队列的实际生产者必须通知侦听器实例停止侦听正常的ops控制队列,并切换到辅助队列。如果存在任何中间连接问题(并且正常的ops队列管理器并没有真正关闭),这将有点棘手,但这是太多的角落情况。
考虑到控制队列的高可用性,我们在低负载情况下遇到了与不可共享相同的问题。现在我们偶尔会有负荷高峰,但也有低谷期。(在晚上之类的)。这个令牌系统并不是真正的反应性的,对吧?它更具有周期性。假设我们有几个小时没有收到任何消息。侦听器仍然会不断地检查队列,因为令牌消息会一个接一个地触发实例。这或多或少让它成为了一个民意调查机构。我还不如有多个侦听器实例每个实例在一小时的不同时间轮询,对吧?它本身并不是事件驱动的。
第三个问题是插入令牌消息的问题。在第一次安装或故障恢复期间,我们需要手动插入这个令牌(因为令牌有时会在故障恢复中丢失)。我们不能让一个监听器实例做这件事,因为如果一个监听器实例没有找到消息,那就意味着其他的监听器实例有这个令牌。所以这个逻辑是分开的。如果我们把一些有意义的信息放到这个令牌消息中,它必须是一个必须被触发的实用程序而不是通过UI插入。
我想第一个和第三个不是真正的问题,只是额外的开销,如果我们使用轮询器实现就不需要了。第二个问题是最困扰我的。
您需要传递令牌。下面是它的工作原理:
首先,创建第二个队列并将一条消息放入其中。现在用下面的逻辑启动每个程序。
- 使用无限制或长等待间隔和
FAIL_IF_QUIESCING
选项从同步点下的令牌队列中获取令牌消息。 - 将令牌消息放回同一UOW中的令牌队列。
- 从相同UOW下的应用程序队列中获取下一条消息
- 正常处理应用程序的消息
- 提交UOW
你可以使用任意数量的应用实例。您将看到每个应用程序实例的两个队列上各有一个输入句柄。任何应用实例都不必处理由于独占使用队列而导致的错误。
由于只有一个令牌消息,并且一次只有一个应用程序可以将其保存在同步点下,因此只有一个应用程序可以主动处理应用程序消息。由于应用程序队列的GET
关闭依赖于令牌队列的GET
成功关闭,因此所有应用程序消息都按照严格的顺序处理。
注意:应用程序将使用与令牌队列上的令牌消息相同数量的并发线程处理应用程序消息。如果有人将另一个令牌消息添加到令牌队列中,则会丢失严格的序列处理。因此,除了应用程序服务帐户之外,对该队列的读/写访问权限不能授予任何人。此外,令牌消息通常是结构化的,以便应用程序可以识别它。
如果一个不相关的消息出现在这里,应用程序应该忽略它并抛出警告。您将看到两个应用程序之间相当均匀的消息分布。如果你使用两个以上的应用程序,你可能会看到一个非常un均匀分布,因为队列句柄是在堆栈中管理的。当一个实例提交它的UOW时,下一个实例的句柄位于堆栈的顶部,因此它获得下一个消息。当它处理该消息时,刚刚提交的实例将把它的GET
放在堆栈的顶部。如果你有3个或更多的监听实例,可能只有前两个会看到任何流量。
这确保消息一次处理一个。不确保你不会被骗。
如果您在同步点下执行所有操作,则不会丢失任何消息。然而,有这样一种场景:检索和处理消息后,COMMIT
调用失败。在这种情况下,事务回滚,相同的消息再次可用。如果您使用的是1阶段提交而不是XA,则该消息的处理将不会回滚。
好处是令牌消息也将在同步点下,这解决了孤立的客户端通道需要一段时间才能释放事务的问题。新连接将获得比孤立事务在同步点下保存的消息更老的消息。最终,通道代理超时释放消息回队列,但有效地将其位置更改为在隔离期间处理的任何消息之后。
在此场景中,令牌消息也被隔离,因此在这种类型的连接丢失消息处理后暂时停止并等待通道代理超时。如果发生这种情况,只需在实例上使用UOW发出STOP CHANNEL
命令。
根据特定于此答案的其他问题详细信息更新
持有此令牌的队列必须是某个队列管理器的一部分。现在,如果我们有一个故障转移,控制队列将不再是可访问。这意味着我们需要另一个控制队列为故障转移做好准备。
令牌队列与应用程序队列一样可用或不可用。只需要一个。如果应用程序需要HA,那么应该使用多实例QMgr或硬件HA集群。这些共享磁盘,以便在故障转移中出现的QMgr与应用程序连接的QMgr相同,只是在不同的物理位置。
如果应用程序需要DR,可以将QMgr的日志和数据目录下的磁盘复制到DR站点。但是,在主数据中心进行处理时,不应该监听这些实例。
侦听器实例应该知道故障转移已经启动它可以在正常操作期间停止侦听控制队列切换到第二频道。我不能用监听器做这个实例。
为什么不呢?WMQ拥有可重新连接的客户端已经很长时间了,v7.0.1中的多实例特性使得重新连接变得非常简单。作为管理员,你的工作是确保应用程序和令牌(不是触发器!)队列的实例不超过一个可用。在中断期间,客户机进入重试状态,而不需要任何应用程序代码来驱动它。它查找任何一个已启动并连接的实例。
将消息放入队列的实际生产者必须这样做通知侦听器实例停止侦听正常操作控制队列并切换到次要队列。
问题是关于并发消费者的序列化。这是一种设计,生产者和消费者必须在一个共同的地点集合。不同的问题碰巧与这个问题重叠只是因为序列化使它变得复杂了一些。如果您需要探索拓扑,请提出不同的问题。
这个令牌系统不是真的反应性对吗?它更具有周期性。假设我们没有得到几小时内没有任何消息。听众仍然是不断的检查队列,因为令牌消息一直触发一个实例。
不使用触发。它使用令牌(而不是触发器!)消息,就像文件系统或数据库使用锁一样,以便于序列化。无论哪个侦听器获得令牌消息,然后在应用程序队列上执行一个无限等待的get操作。其他侦听器在令牌(不是触发器!)队列上有一个无限等待的get。基本上,它们闲置着,直到消息到达。零重新连接,零轮询,零CPU周期。如果您需要知道它们是否处于活动状态,请让它们在应用程序队列中偶尔超时一次。这将回滚它们在令牌队列上的UOW,令牌队列将令牌传递给另一个侦听器。
第三个问题是插入令牌消息的问题。在第一次安装或故障恢复期间,我们将有额外的手动插入此令牌的步骤(因为令牌将是有时会在故障转移中丢失)。
为什么?您是否经常遇到MQ丢失同步点下的持久消息的情况?如果是这样,那你就做错了。-)在有严格序列化要求的情况下,一个队列只能有一个活动实例。如果由于某种原因,除了通过磁盘复制之外,还预定义了应用程序队列的其他实例,那么将在它旁边预定义一个令牌(不是触发器!)队列实例,并在每个队列中等待一个令牌(不是触发器!)消息。当然,面对严格的消息顺序要求,没有人会这样做,但如果他们这样做了,这些队列肯定会在不使用时被禁用。
我们不能真正制造一个听众实例执行此操作,因为如果侦听器实例没有找到消息这意味着其他侦听器实例有这个令牌。
正确的。侦听器可以检查队列深度、事务、输入句柄等,但通常明智的做法是避免将应用程序逻辑与控制逻辑混合。
这个逻辑必须是分开的。如果我们放一些有意义的信息到这个令牌消息,它必须是一个实用程序,必须触发,而不是通过UI插入。
为什么?你的编码人员处理应用程序消息中的结构化数据,对吗?如果这被认为是非常困难的,那么有人做错了。-)将格式化令牌(不是触发器!)消息的实例写入队列,然后将其卸载到文件中。当需要重新初始化队列时,请使用Q或QLoad首先清除队列,然后将文件加载到队列中。实用程序将打开队列供独占使用,检查深度,检查句柄等,然后再执行其魔术。当我为咨询客户这样做时,我通常定义一个服务来初始化MQ启动上的队列,并且还在应用程序GUI中为操作和支持人员提供一个特性。只要管理令牌队列的应用程序(而不是触发器)在这些操作期间获得独占访问权,它是如何完成的,或者控制应用程序的多少个实例都无关紧要。
作为一项规则,我还使用消息中的结构向侦听器发送命令。有真正的令牌消息,然后有命令app实例去做事情的消息。例如,拥有非事务性的"ping"功能非常好。如果我在单个UOW中在令牌(不是触发器!)队列上丢弃的ping消息比我侦听的应用程序实例要多,我保证能联系到所有这些应用程序。这样我就能发现僵尸了。根据需要多少插装,侦听器可以通过在日志、控制台、事件队列等中提供状态(正常运行时间、已处理的消息等)来响应ping。
我想第一个和第三个不是真正的问题,只是额外的开销,如果我们用轮询器就不需要了实现。
这很好,因为这些都是非常标准的东西。问题主要在于序列化的需求与HA/DR的需求冲突。您正在寻找的是全局事务原子性,以便跨多个物理位置实现单个逻辑队列。IBM MQ从未尝试提供这种功能,尽管WAS消息传递引擎提供了这种功能。MQ最接近的情况是使用两个具有消息和事务数据的内存到内存复制的MQ设备,但在光速延迟开始显著影响吞吐量之前,这种情况最好只有几英里。它不能满足你的DR需求。实际上,如果您希望在DR数据中心实现零恢复点,除了同步复制之外,没有什么可以做到这一点。
关于你的HA问题…
如果你有两个队列接收器从一个队列读取,我不知道有什么自然的方法来避免它们之间的并行。
可能是一些供应商特有的功能,但这似乎是一个奇怪的事情,我不会有任何高的期望。
如果您在同步点下处理消息,那么您确实可以回滚事务,以便在发生错误时将处理过的消息放回输入队列。如果程序异常结束,则发生隐式回退。
http://www - 01. - ibm.com/support/knowledgecenter/ssfksj_7.5.0/com.ibm.mq.dev.doc/q026800_.htm?lang=en
消息的事务性处理不会阻止两个独立的消费者同时读取消息。队列上有一个名为Shareability的属性,可以将其设置为Not Shareable,以防止队列同时被不同的消费者打开。您应该使用此选项并准备应用程序重试打开队列,以便在第一个实例失败时,第二个实例将打开队列。