【问题标题】:How to ensure JMS message redelivery when client crashes客户端崩溃时如何确保 JMS 消息重新传递
【发布时间】:2017-09-25 11:49:49
【问题描述】:

我需要确保在消费者失败时重新传递 JMS 消息,但此处接受的类似问题的策略可能不适用于我的情况。

考虑一个 JMS 客户端 - spring + activeMq - 接收消息,这些消息不会丢失或重复。因为消息的处理成本很高,所以客户端对它们进行批处理。剧情如下:

  • T1 - 客户端收到消息 A、B、C 和 D
  • T2 - 线程在客户端唤醒并决定处理消息 A、B 和 C
  • T3 - 客户端收到消息 E 和 F
  • T4 - 线程在处理完 A、B 和 C 后返回。如果另一个线程尚未执行此操作,则它可以拾取下一批。

现在设置生产者的方式 - DefaultJmsListenerContainerFactorySession.AUTO_ACKNOWLEDGE - 消息在传递后立即被删除,无论它们是否已被线程与否。如果客户端在 T4 之前停机,则消息 A 到 F 将丢失。

我打算在生产者上使用 Session.CLIENT_ACKNOWLEDGE 并让每个线程在 T4 之后调用 msg.acknowledge(),但根据 documentation,这也会确认 E 和 F,如果客户端在 T4 之后失败,这将丢失。

我也不相信事务处理的会话在这里会有所帮助,因为它会涵盖消息 A 到 F,而线程完成仅保证其中的一部分已被处理。

我的目标是保证在客户失败的情况下,例如虚拟机宕机,所有未由线程成功处理的消息都保留在主题/队列中。然后,当它恢复时,它们可以被客户端拾取。

关于如何实现这一点的任何想法?

S

【问题讨论】:

    标签: java spring jms batch-processing spring-jms


    【解决方案1】:

    我要提到的第一件事是你不应该使用 CLIENT_ACKNOWLEDGE 因为你会变得更糟并增加丢失率。正如您所说,客户端确认也将确认相关本地 jms 会话中的所有消息,否则您从一批中获取的所有消息。

    消息一经发送即被删除,无论是否有 是否被线程拾起

    通常在 onMessage 方法调用完成后发回确认。你说的是什么线程?如果您的处理是在同一个线程中完成的,那么它似乎只有在调用成功后才会发送 ack。

    您是如何实现批量消费的?如果你的意思是活跃的 mq 消费者 (http://activemq.apache.org/performance-tuning.html) 并且你使用的是 Spring (WS 或 Integration) 和 AMQ 代码库提供的,那么你应该只把精力放在正确的配置上,而不是做一些复杂的自定义实现来实现 99.999999% 的成功速度。每个 jms 代理都会丢失消息或有重复消息,并且您永远不会获得 0 丢失率。对于大多数企业系统来说,例如百万分之一的消息丢失或重复是很正常的情况。

    为了获得某种可靠的交付,无论如何您都应该使用持久交付模式和 jms 事务。对我来说,重复的消息总比完全丢失要好(实际上所有的系统架构都应该是幂等的来处理这些事情)。正如你所说,也提到了 AMQ 文档批处理是可靠性和性能之间的权衡。并且基本上没有机会同时实现这两种特性。至少使用 AMQ 和 jms。因此,由您决定什么对您的可靠性或性能更重要。对您而言,最佳选择是定义权衡并确定在丢失或重复消息的情况下可接受的重复消息批次数量

    【讨论】:

    • 是的,一旦 onMessage() 完成,auto_ack 就完成了。目前,此方法仅将消息添加到集合(为了简化)并返回。当满足某些条件(时间、集合的大小......)时,线程决定是时候处理集合内的部分消息了。这意味着在 auto_ack 中,在 msg ack 和实际处理之间可能会有一段时间。也许我所追求的并不可行,正如你所说,我只需要配置集合的大小以最多容纳我能承受的最小数量的 msg 丢失。
    • 在这种情况下,实际上您可以使用一些持久性数据结构,如 mapdb 或类似的 smth。从消息被发送到某个内部渠道的那一刻起,您实际上有责任在进一步发送此消息后小心处理。试图让经纪人完成这项工作将导致没有任何必要的复杂逻辑。但对我来说,即使 mapdb 似乎也是一种开销,我怀疑在你的情况下这是一个好的架构。从我的角度来看,最好的选择就是建议您可能会丢失或重复一些低百分比的消息并设置适当的窗口大小
    猜你喜欢
    • 2019-04-21
    • 2011-02-28
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 2013-06-22
    相关资源
    最近更新 更多