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