【问题标题】:Take first message to arrive on one of 2 queues将第一条消息到达 2 个队列中的一个
【发布时间】:2014-09-10 15:37:27
【问题描述】:

我有一个应用程序,我想使用队列 A 中的消息,但如果队列 A 为空,我希望它使用队列 B 中的消息,而不是闲置。我只希望它一次处理 1 条消息,如果消费者正忙于处理一条消息(来自任一队列),则其他待处理消息(在任一队列上)应保留在其队列中,直到消费者再次空闲(这给出其他消费者有机会处理新消息)。

因此,例如,如果消息在消费者空闲(等待)时到达队列 A 或队列 B,则消费者会拾取它。如果在消费者当前正在处理消息时消息到达任一队列,则在消费者完成当前消息处理之前不会发生任何事情。如果消息在队列 A 和队列 B 上都可用,则消费者更愿意从队列 A 中选择消息。

编辑:实际上,我同样很高兴得知消息可以在 A 和 B 上使用,并实现我自己的逻辑来选择我真正想要从排队。

在不同的线程中同时订阅两个队列似乎不起作用,因为:

  • 如果消息 M 到达队列 A,消费者在处理消息 M 时必须取消订阅队列 B,然后重新订阅一次消息 M 被处理。除此以外, 如果一条消息到达队列 B,它可能会同时被拾取和发送 - 我不想一次处理多个消息。
  • 如果一条消息同时到达两个队列(或者当消费者启动或完成对前一条消息的处理时两个队列上已经有一条消息),那么有可能两条消息都将在消费者获得取消订阅队列 B 的机会。如果发生这种情况,我必须回滚其中一条消息,但如果这种情况频繁发生,消息将超过回滚计数并被移至失败队列。

理想情况下,我想将其推广到 N 个队列的情况。我对理想地通过 JMS 工作的解决方案感兴趣,但如果我必须使用 IBM MQ 特定的 API 来执行此操作,那也没关系。是否有有助于实现这一目标的使用模式或库?是否有其他排队方法/技术/技术允许它?

从所有队列中拉出所有消息并将它们放入单个队列是不行的;我们需要能够独立清除各个队列,并且不同的消费者可以订阅 N 个队列的不同子集。

【问题讨论】:

    标签: jms ibm-mq


    【解决方案1】:

    我不知道这是否会对你的代码产生很大的改变,但是你有没有想过在你的项目中添加 Spring Framework,尤其是 Spring Integration?您描述的此类问题已经在那里处理了。

    这个问题可以通过两个端点在两个队列和一个线程池上的事件驱动消费者来解决。

    http://www.eaipatterns.com/EventDrivenConsumer.html

    http://en.wikipedia.org/wiki/Thread_pool_pattern

    [编辑]

    如果您希望消息在线程释放之前一直留在队列中,您可以遵循轮询消费者的模式

    http://www.eaipatterns.com/PollingConsumer.html

    可以根据需要选择首先从哪个队列请求消息。请记住,使用这种技术,如果您的系统处理消息的速度比它们到达的速度快,您将遇到一些对队列的冗余轮询。

    【讨论】:

    • 我们使用 Apache Camel,它有相似之处,但我对 SI 不够熟悉,无法了解它如何解决问题。 IIUC,您建议使用事件驱动的消费者从队列中拉出消息并将它们发布到只有一个线程的线程池,但这不起作用 - 一旦从 MQ 队列中拉出第二条消息,它就位于线程池的任务队列在第一条消息完成处理之前什么都不做。我希望第二条消息保留在 MQ 上,直到第一条消息完成或其他消费者收到它为止。
    • 然后你可以将消费者从事件驱动转为轮询。
    • 我用一个关于调查消费者的简单文档编辑了我的答案。但是可以在本书中找到更好的描述eaipatterns.com/eaipatterns.htmlamazon.com/dp/0321200683/…
    • 我还有一条评论,当你说消息会在线程池的任务中闲置时,我不相信是这样的。任务是去消费一条消息,所以如果没有可用的线程,就不会消费任何消息,因此它会留在队列中。
    • 这是对您的事件驱动建议的回答。我的解释是线程池队列上的任务是处理从队列中拾取的消息;每当消息到达时,任务由事件驱动的消费者发布。您似乎在说任务是轮询队列并获取消息;对于事件驱动的消费者来说,这对我来说没有意义,而且什么会发布这样的任务?
    【解决方案2】:

    如果我要编写这个应用程序,我想我会使用异步消费者。我会在同一个连接句柄 (hConn) 上使用 MQCB 动词设置两个消费者,因此一次只能驱动一个。然后使用 MQCTL 启动消费者以进行设置。

    当您在回调函数中处理消息时,您不会再被来自任一队列的消息驱动。

    回答您的附加问题 - 如果两条消息同时到达,则无法保证始终优先驱动队列 A 的回调。显然,如果一条消息比队列 A 早一秒到达队列 B,那么您的要求是在队列 B 上处理该消息。所以这确实提出了一个问题,为什么在处理队列 B 上的一条消息之前处理一条消息很重要在同一时间到达时排队 A。

    我从您对问题的编辑中看到,您很高兴收到消息已到达的通知,然后您可以自己动手做。您还可以在浏览模式下使用 Async Consume,这意味着您可以在消息到达队列时被调用,然后在回调函数中您可以发出 MQGET 以使用破坏性获取来检索实际消息。

    然后,您可以让队列 B 的回调函数始终对队列 A 执行快速无等待 MQGET 调用,然后再选择处理它自己的消息以处理优先要求。这会有点低效,但肯定比轮询两个队列要好,因为这会增加你绝对不想要的等待间隔。这样做的低效率是否值得,将取决于您对它为何重要的回答。

    队列 A 的回调函数可以直接处理消息。

    【讨论】:

    • 如果消息在两个队列中都可用,消息将按什么顺序传递?我不清楚如何在其中进行选择,或者表示我总是更喜欢根据需要发送到队列 A 的消息。
    • 根据您上面的评论和您在问题中的编辑更新了我的答案。
    【解决方案3】:

    我对这个问题的第一反应是将队列处理外包给 Windows 服务(假设您在 Windows 服务器上运行它)。我认为您无法完全在 MQ 本身内完成此操作。

    将每个队列的触发设置为 First,并让触发的应用程序连接到 Service,并提供有关它代表哪个队列的信息,然后终止。然后,服务将根据您为其设置的任何规则处理每个队列。

    根据cmets中的问题修改答案:

    1. “在 MQ 本身内”是指描述功能可能不是您可以通过对 MQ 组件(例如队列管理器、通道、队列等)的任何设置来完成的。您必须在 MQ 之外设置某种服务应用程序才能执行此操作。

    2. “为什么它是服务、常规控制台应用程序还是 GUI 很重要?”这可能无关紧要,但 Windows 服务始终处于开启状态,无需用户干预即可运行,并且可以与其他有人参与和无人参与的应用程序进行交互。控制台应用程序或 GUI 可能能够做到这一点,但它们不是为此而设计的,并且可能无法始终如一地工作。另一方面,如果您必须与之交互,显然 GUI 或控制台应用程序将是您的选择。但是,我实际上并不知道您要做什么,所以我的想法可能对您来说完全不符合实际。

    3. “我不熟悉触发 - 你是在说这个吗?”是的。我已经使用 Websphere MQ 多年,几乎在每个应用程序中都使用过触发。

    如果您正在使用 GUI,那么您可能想要轮询各种队列以查看它们有什么并将它们排列在您的 GUI 中以供使用,而我的任何建议都与你。我假设是无人值守的操作,所以我们到了。

    【讨论】:

    • 我不知道您所说的“在 MQ 内部”是什么意思。我已经有一个作为消费者的应用程序。为什么它是服务、常规控制台应用程序还是 GUI 很重要?我不熟悉触发 - 你在说this
    猜你喜欢
    • 2014-04-13
    • 2012-02-06
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多