如果某些消息重复或丢失,是否可以?当 JMS 客户端通过网络连接到 JMS 代理时,任何 API 调用都分为三个阶段。
- API 调用(包括任何消息数据)通过线路传输到代理。
- API 调用由代理执行。
- 结果代码和任何消息数据都会传回客户端。
考虑一下制作人。如果在第一步中连接中断,那么代理永远不会收到消息,应用程序需要再次发送它。如果在第三步中连接断开,则消息已成功发送,再次发送将产生重复消息。该应用程序无法分辨这些之间的区别,因此唯一安全的选择是在出错时重新发送消息。如果会话被处理,则在所有情况下都可以安全地重新发送消息,因为如果原始消息已发送到代理,它将被回滚。
考虑消费者。如果在第三步中连接丢失,则消息将从队列中删除,但从未返回客户端。但是如果会话被处理,消息将在应用程序重新连接时重新传递。
在事务之外,可能会丢失或重复消息。在事务内部存在相同的模糊窗口,但它在 COMMIT 调用而不是 PUT 或 GET 上。通过事务会话,可以两次发送或接收消息,但不会丢失一次。
JMS 规范识别出这种不明确的窗口并提供以下指导:
如果在之间发生故障
客户提交工作的时间
会话和提交方法
返回,客户无法确定
如果事务已提交或
回滚。存在同样的歧义
当之间发生故障时
持久性的非事务性发送
消息和返回
发送方式。
由 JMS 应用程序来处理
带着这种模棱两可。在某些情况下,
这可能会导致客户产生
功能上重复的消息。
由于以下原因重新发送的消息
会话恢复不被视为
重复消息。
应始终处理 JMS 会话,但丢失消息确实可以的情况除外。如果会话被处理,那么由于 JMS 线程模型,您需要每个线程的会话和连接。
任何有关性能影响的建议都将是特定于供应商的,但一般来说,同步点之外的持久消息会在 API 调用返回之前固化到磁盘。但是事务调用可以在持久消息写入磁盘之前返回只要消息在 COMMIT 返回之前保持。如果供应商基于此进行优化,那么将几条消息写入磁盘然后分批提交它们的性能要高得多。这允许代理通过磁盘块而不是每个消息来优化写入和磁盘刷新。放入事务中的消息数量随着消息的大小而减少,超过一定的消息大小会减少到一个。
如果您的 20k 消息相对较小(以 k 而非 mb 为单位),那么您可能希望使用每个线程的事务处理会话并调整提交间隔。