【问题标题】:JMS message re-delivery delayJMS 消息重新传递延迟
【发布时间】:2011-03-27 05:49:51
【问题描述】:

我有一个 JMS 客户端,它可以在收到消息后通过 ssh 连接到远程系统(并在那里做各种事情 - 与问题无关)。可能会有数百条此类消息在短时间内到达,需要尽快处理。

但是,也有可能某些远程系统在收到消息时不可用,因此应该推迟到稍后(例如 1 小时左右)。最好的解决方案是将消息放回队列并设置一些“延迟”值,这将告诉 JMS 代理不要在一小时内再次尝试传递消息。

什么不正常:在接收线程中休眠并在一个小时后醒来。由于消息消费者池是有限的(例如 8 个可用连接),有 8 个不可访问的系统会不必要地阻塞整个处理,这是不可接受的。

我没有找到这样一个“延迟”值的消息或队列本身的设置,它存在吗?

解决方法是使用第二个队列将消息存储到无法访问的系统,并分别处理这些消息。但这不是一个非常优雅的解决方案,并且需要额外的编程。也许有更好的方法。

【问题讨论】:

    标签: jms message-queue openmq


    【解决方案1】:

    这在 JMS 2.0 之前的 JMS API 中是不可能的。作为一般规则,消息传输经过优化以尽可能快地传递消息,并且缺少调度程序来保存消息以在某个任意时间间隔重新传递。假设有一个传输提供程序确实具有此类功能,那么您编写的任何内容都将绑定到该传输提供程序,因为尽管代码可能与 JMS 兼容,但应用程序本身将依赖于这种特定于供应商的行为。

    有关适用于支持 JMS 2.0 的 MQ 版本的答案,请参阅 @Shashi 的答案。

    【讨论】:

    • 我认为这仅适用于 JMS 1.0? (参照沙士的回答)
    • 是的。新的 MQ JMS 类支持延迟交付。
    • 此答案已过时,因为 JMS 2.0 支持延迟交付。应该接受另一个答案。
    • 我同意。我鼓励@egbokul 不接受我的,然后接受Shashi 的回答。我想我必须先编辑它 IIRC,所以我现在就这样做。
    【解决方案2】:

    在这种情况下,使用容器管理事务。事务在容器调用onMessage 方法时启动,并在onMessage 方法成功完成时提交(当抛出RuntimeException 或从MessageDrivenBean 上下文调用setRollBackOnly 时它将失败)。您还可以配置重新发送间隔和最大重新发送次数。

    如果您将 OpenMQ 与 Glassfish 服务器一起使用,您可以在 ejb-jar.xml 描述符中进行配置。在 ejb-jar.xml 描述符中设置属性 endpointExceptionRedeliveryInterval(以毫秒为单位)和 endpointExceptionRedeliveryAttempts(消息在发送到死消息队列之前被重新传递的次数)。这是一个例子:

    <?xml version="1.0" encoding="UTF-8"?>
    <ejb-jar  xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
        version="3.1">    
        <enterprise-beans>
            <message-driven>
                <ejb-name>EjbName</ejb-name>
                <ejb-class>com.example.MyMessageDrivenBean</ejb-class>
                <messaging-type>javax.jms.MessageListener</messaging-type>
                <transaction-type>Container</transaction-type>
                <activation-config>
                    <activation-config-property>
                        <activation-config-property-name>destination</activation-config-property-name>
                        <activation-config-property-value>someQueue</activation-config-property-value>
                    </activation-config-property>
                    <activation-config-property>
                       <activation-config-property-name>destinationType</activation-config-property-name>
                       <activation-config-property-value>javax.jms.Queue</activation-config-property-value>
                    </activation-config-property>
    
                    <activation-config-property>
                        <activation-config-property-name>endpointExceptionRedeliveryInterval</activation-config-property-name>
                        <activation-config-property-value>5000</activation-config-property-value>
                    </activation-config-property>
                    <activation-config-property>
                        <activation-config-property-name>endpointExceptionRedeliveryAttempts</activation-config-property-name>
                        <activation-config-property-value>4</activation-config-property-value>
                    </activation-config-property>
                </activation-config>
            </message-driven>
        </enterprise-beans>
    </ejb-jar>
    

    并且在消息驱动的 bean 内部抛出一个 RuntimeException 以将其标记为失败,并且消息将返回到队列中。

    以下也是 WebLogic Server 的配置属性: http://docs.oracle.com/cd/E12839_01/apirefs.1111/e13952/pagehelp/JMSjmstemplatesjmstemplateconfigredeliverytitle.html

    【讨论】:

    【解决方案3】:

    我会将问题视为: jms 消息消费者池可用...而 某些后端资源(即 ssh)无法完成消息。

    如果您同意这一点,那么问题就变成了为什么消费者池因为无法完成消费而可用? 如果您的池不可用,那么消息将堆积在队列中......直到可用......并且在可用时可以继续。 然后,如果是这种情况,您只需要一个监视组件来启动/停止池,具体取决于资源是否可用。您不必等待 1 小时,但只要后端不可用。 最后 jms 是一切,但不是监控工具。

    【讨论】:

      【解决方案4】:

      JMS 2.0 规范定义了一个“传递延迟”,客户端可以为它发送的每条消息指定一个传递延迟值(以毫秒为单位)。这个值定义了一个消息传递时间,它是消息的传递延迟和它发送的 GMT 的总和(对于事务发送,这是客户端发送消息的时间,而不是事务提交的时间)。

      消息的传递时间是 JMS 提供者可以使消息在目标目的地上可见并可传递给消费者的最早时间。提供者不得在到达传递时间之前传递消息。

      此功能对于上述场景非常方便。

      【讨论】:

        【解决方案5】:

        在 glassfish 上,可以使用以下参考资料。

        https://docs.oracle.com/cd/E19798-01/821-1794/aeooq/index.html

        在上面的参考资料中,您可以获得 glassfish 支持的激活属性列表。 例如。 endpointExceptionRedeliveryAttempts -
        消息传递过程中MDB抛出异常时重新传递消息的次数

        然后,您将获得以下参考,该参考描述了可在 glassfish 支持的 sun-ejb-jar.xml 上使用的有效 xml 元素。 https://docs.oracle.com/cd/E19798-01/821-1750/beaqm/index.html

        最后,您可以按照以下 sn-p 中的说明配置 Mdb。

        <ejb>
            <ejb-name>MyMdbWith0MsRedeliveryDelayAndMultipleRedeliveriesMdb</ejb-name>
            <bean-pool>
                <steady-pool-size>1</steady-pool-size>
                <resize-quantity>1</resize-quantity>
                <max-pool-size>1</max-pool-size>
            </bean-pool>
            <mdb-resource-adapter>
                <activation-config>
                    <activation-config-property>
                        <activation-config-property-name>endpointExceptionRedeliveryAttempts</activation-config-property-name>
                        <activation-config-property-value>1000</activation-config-property-value>
                    </activation-config-property>
                    <activation-config-property>
                        <activation-config-property-name>endpointExceptionRedeliveryAttempts</activation-config-property-name>
                        <activation-config-property-value>0</activation-config-property-value>
                    </activation-config-property>
                </activation-config>              
            </mdb-resource-adapter>
        </ejb>
        

        这应该确保对于这个特定的 mdb,glassfish 将立即传递一条消息,如果它失败,它将立即重试。

        在您的 WAR 项目中,创建一个 sub-ejb-jar.xml 并将其放在 WEB-INF/sun-ejb-jar.xml 下。

        如果您使用的是 maven,这将是您在 war 项目组件上的 src/main/webapp/WEB-INF/sub-ejb-jar.xml 路径。

        【讨论】:

          【解决方案6】:

          美好的一天!

          对于Oracle WebLogic Server,有两个参数:

          • Redelivery Delay Override - 在Queue 的级别上,并且
          • 默认重新发送延迟 - 在Connection factory 级别。

          【讨论】:

            猜你喜欢
            • 2019-07-18
            • 2014-09-27
            • 2012-05-08
            • 1970-01-01
            • 2022-12-14
            • 1970-01-01
            • 2013-06-22
            • 2020-03-29
            • 1970-01-01
            相关资源
            最近更新 更多