我观察到,如果回滚 TX(MDB 容器管理的 TX)稍后从队列中读取 msg(破坏性调用),则将 msg 放回队列(原始队列或退出队列,具体取决于队列的倒计时和阈值设置) . 可以说,如果由于 TX 回滚失败而发生某些事情(重复网络问题或某些问题),那么 Msgs 就会丢失。
是真的吗??
谢谢
正如我在对前面问题的评论中指出的那样,简短的回答是“不,如果失败,WMQ 不会丢失这些消息COMMIT
”,但让我们更详细地了解一下。
当客户端通过网络连接到 MQ 时,幕后发生的事情是 MQ 启动一个进程,该进程创建一个到 MQ 的共享内存连接和一个到客户端应用程序的套接字连接。保持事务打开的是共享内存进程,在 WMQ 术语中称为“通道代理”。
从应用程序的角度来看,有两种情况COMMIT
似乎失败了。在其中的第一个中,将COMMIT
传递给通道代理并执行,但由于网络问题,确认永远不会返回给应用程序。从 MQ 的角度来看,消息并没有“丢失”,因为应用程序有意提交了GET
调用。
第二种情况是在COMMIT
到达通道代理之前发生网络故障。在这种情况下,COMMIT
确实失败了,因为应用程序无法恢复事务所在的连接句柄。当通道代理意识到 TCP 连接失败时,它会退出事务并关闭通道。这个过程中的问题是通道代理可能需要一段时间才能意识到连接已经断开。事实上,大多数平台上默认的 TCP 超时时间是两个小时。根据您服务器的 TCP 设置,交易的GET
可能会将该消息在同步点下保存长达两个小时,使其看起来已被消耗。这是强烈推荐使用当前级别的 QMgr 和客户端的原因之一——它们较少依赖 TCP,而更多地依赖内部通道心跳协议来检测丢失的连接。
从应用程序的角度来看,这两种情况似乎都是相同的——应用程序调用COMMIT
并返回 2009 MQRC_CONNECTION_BROKEN
。但是在第一种情况下,消息由于 的原因而消失了,COMMIT
而在第二种情况下,消息可能会再次传递。由于这种模糊性,应用程序必须能够检测并优雅地处理欺骗消息。
现在在声明这是 MQ 中的一个缺陷之前,让我指出这种结果的模糊性是在网络上使用消息传递时固有的,而不是特定于 WebSphere MQ 的任何东西。事实上,JMS 1.1 规范在 4.4.13 中直接解决了这个问题,它说:
如果在客户端在 Session 上提交其工作和 commit 方法返回之间发生故障,则客户端无法确定事务是提交还是回滚。当在 PERSISTENT 消息的非事务性发送和发送方法的返回之间发生故障时,存在同样的歧义。
由 JMS 应用程序来处理这种歧义。在某些情况下,这可能会导致客户端生成功能上重复的消息。
由于会话恢复而重新传递的消息不被视为重复消息。
所以使用同步点可以消除丢失消息的情况,因为任何后面都GET
必须跟一个aCOMMIT
才能将消息从队列中永久删除。根据定义,COMMIT
直到应用程序看到消息才能到达。但是,同步点不能消除重复消息的可能性,因为如果COMMIT
一个GET
失败,应用程序可能会再次看到该消息。同样,如果COMMIT
一个PUT
失败,应用程序无法知道是COMMIT
在到达通道代理之前还是之后失败,只能重新连接并PUT
再次发送消息。
如果实际上您遇到“丢失”消息,则可能是:
COMMIT
但没有放置消息的另一个副本。GET
ting 应用程序在 上失败,消息COMMIT
没有丢失,但实际上在同步点下。在这种情况下,停止任何孤立通道以回滚事务。除了这两种情况,WMQ 不会丢失该持久消息。
不会。消息不会丢失。在事务中,只有在成功提交后,消息才会从队列中删除。如果提交或回滚失败,消息会重新出现。如果在调用提交或回滚之前应用程序和队列管理器之间的连接中断,WebSphere MQ 会自动执行回滚。这样可以确保消息不会丢失。