客户端崩溃时如何确保 JMS 消息重新传递

How to ensure JMS message redelivery when client crashes

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

考虑一个 JMS 客户端 - spring + activeMq - 接收不能丢失或重复的消息。因为消息的处理是昂贵的,所以客户端对它们进行批处理。剧情播放如下:

生产者现在的设置方式 - DefaultJmsListenerContainerFactorySession.AUTO_ACKNOWLEDGE - 消息一旦被删除就会被删除已交付,无论它们是否已被线程拾取。如果客户端在 T4 之前关闭,消息 A 到 F 将丢失。

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

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

我的objective是为了保证万一客户端出现故障,例如VM 关闭,所有未被线程成功处理的正在运行的消息都保留在 topic/queue 中。然后它们可以在客户端恢复时被拾取。

知道如何实现吗?

S

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

messages are removed as soon as they are delivered, whether they have been picked up by a thread or not

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

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

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