【问题标题】:Anyone know exactly which JMS messages will be redelivered in CLIENT_ACKNOWLEDGE mode if the client crashes?如果客户端崩溃,任何人都知道哪些 JMS 消息将在 CLIENT_ACKNOWLEDGE 模式下重新传递?
【发布时间】:2011-02-28 19:16:49
【问题描述】:

规范说“确认已消费的消息会自动确认已收到其会话已交付的所有消息”-但我需要知道的是“已交付”的含义。

例如,如果我调用 consumer.receive() 6 次,然后在第三条消息上调用 .acknowledge - 是 (a) 只是前 3 条消息被确认,还是 (b) 全部 6 条?

我真的希望它是选项 a,即在您调用确认之后的消息将被重新传递,否则很难看到在我的接收器进程崩溃的情况下如何防止消息丢失有机会坚持和确认消息。但是该规范的措辞尚不清楚。我的印象是 JMS 规范的作者认为代理失败,但并没有花太长时间思考如何防止客户端失败:o(

谢谢 本

【问题讨论】:

  • 我仍然很想听听任何可以告诉我其他提供者(除了 SonicMQ)是否通过仅确认您调用 ack() 的消息而超越/违反标准的人在 CLIENT_ACKNOWLEDGE 模式下开启...

标签: jakarta-ee jms


【解决方案1】:

根据规范,选项 (b) 是正确的行为。如果您获得选项 (a) 并依赖它,则该应用程序将不可移植。

在下面的解释中,我特别指的是 JMS 规范 2002 年 4 月 12 日版本 1.1

确认方法是从消息对象调用的,而实际上它是在会话级别运行的,这会引起一些混淆。因为它是一种消息方法,所以从直觉上看,可以在消息流中选择一个点来生成确认似乎是正确的。

真正发生的是消息确认正在推动会话级别的提交调用。由于会话一次只能有一个事务处于活动状态,因此每个确认不是在消息流中划定一个点,而是在 时间 中划定一个点。 ack 提交现有的工作单元并开始下一个。在 ack 之前传递的消息必须包含在 ack 提交的工作单元中。

术语“已传递”通常被认为是 API 调用的完成,该调用将消息从队列中移除并导致程序内存中的填充对象。实际上,当消息从队列中移除时,无论它是否进入程序,它都被视为已传递。例如,考虑以下事件序列:

  1. 应用请求消息。
  2. 请求通过 TCP 套接字传递到充当应用程序代理的服务器上的进程。
  3. 代理向队列发出 GET。
  4. 消息被锁定在一个工作单元中并传递给代理进程。
  5. 代理进程尝试通过 TCP 套接字将消息传递给调用应用程序。如果此时断开连接,应用程序将永远不会看到该消息,但 JMS 提供者认为它已被传递。当检测到断开的连接时,工作单元被取消,消息被回滚到队列中并且重新传递计数增加。
  6. 应用程序收到消息。
  7. 应用程序确认消息。
  8. 代理进程接收到提交调用并执行它。

在 6 和 8 之间有一个窗口可以断开 TCP 套接字。在 JMS 提供者方面,它无法真正区分这与第 5 步的失败。无论哪种方式,消息都会回滚并稍后重新传递。但是在这种情况下,应用程序将看到该消息两次。该规范在 4.4.13 中预测了这种情况,其中指出:

如果在客户端提交其对 Session 的工作和 提交方法返回,客户端无法确定事务是否 提交或回滚。发生故障时也存在同样的歧义 在 PERSISTENT 消息的非事务性发送和返回之间 从发送方法。

由 JMS 应用程序来处理这种歧义。在某些情况下,这 可能会导致客户端产生功能上重复的消息。

由于会话恢复而重新传递的消息不被视为 重复消息。

在您的示例中,您“调用 consumer.receive() 6 次,然后在第 3 条消息上调用 .acknowledge”并观察到消息 4 到 6 被重新传递,可能的解释是 a) 这六条消息是并非全部来自同一个会话,或者 b) 行为不符合规范。

【讨论】:

  • 谢谢,这很有帮助。不是我希望的答案(!),但我有一种感觉可能就是这种情况。那么,确认方法放在 Message 对象而不是 Session 上只是一个意外吗?正如你所说,它确实给人一种相当误导的印象。
  • 我仍然想知道是否有许多其他提供商(除了 SonicMQ)通过仅确认您调用 ack() 的消息来超越/违反标准...否则它似乎 CLIENT_ACKNOWLEDGE 的局限性使其对于真正可靠的消息传递毫无用处。在实践中,是每个人最终要么使用重量级 XA 事务,要么放弃完全一次性语义,转而在应用层实现可靠性?
  • 我怀疑确认方法在消息上,因为会话是容器管理的模型,并且消息是应用程序唯一可用的对象。无法回答有关其他传输提供商的问题,因为我对特定提供商的唯一了解是 WebSphere MQ。也许其他人会回应。如果您想吸引更多的 cmets,请不要忘记接受/投票。
  • XA 在时间范围内而不是在消息流中的某个点确定事务边界的范围,与 CLIENT_ACK 相同。在调用 COMMIT 时,在 XA 提交之前传递的任何消息都在同一个工作单元中。我不会说 CLIENT_ACKNOWLEDGE 对于可靠的消息传递毫无用处,因为它实现了与 XA 相同的模型,但我很好奇是什么要求导致您想要阅读 6 条消息并只确认前 3 条消息。我认为首选方法是使用选择器或相关 ID 仅选择感兴趣的。
  • “XA 及时确定事务边界的范围,而不是消息流中的某个点”——这是非常有用的信息,尽管我的计划又一次落空了! :o( 我想做的就是在我的客户端崩溃时可靠地接收消息而不会丢失(即,在我将消息确认到 JMS 并失去重新传递的机会之前,我需要自己坚持或完全处理消息)......但它会如果在确认消息“1..n”时我无法接收和处理消息 n+1、n+2 等,那么性能会受到很大影响 - 但如果一切都基于时间而不是 msg 流 pos,我猜只是没有这样做的方法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-16
  • 2016-04-30
  • 2019-04-21
  • 2019-06-10
  • 2021-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多