MSMQ消息发送到群集MSMQ实例的传输队列中时会被阻塞。

7
我们为一组NServiceBus服务集群化了MSMQ,一切都很好,直到出现问题。一个服务器上的输出队列开始填满,很快整个系统就会挂起。
更多细节:
我们在N1和N2之间建立了一个集群MSMQ。其他集群资源只是直接在集群队列上作为本地服务运行的服务,即NServiceBus分发器。
所有工作进程都驻留在单独的服务器Services3和Services4上。
对于那些不熟悉NServiceBus的人,工作进入由分发器管理的集群工作队列。Service3和Services4上的工作应用程序向同一分发器管理的集群控制队列发送“我已准备好工作”消息,分发器通过将工作单元发送到工作进程的输入队列来响应。
在某些时候,这个过程可能完全停顿。当系统挂起时,这是集群MSMQ实例的输出队列的图片:
如果我将集群故障转移到另一个节点,就像整个系统被踢了一下。以下是故障转移后不久相同集群MSMQ实例的图片:
有人能解释这种行为以及我可以采取什么措施来避免它,保持系统平稳运行吗?

次要节点最终会挂起吗?工作节点的表现如何?它们是否正在积极处理消息? - Adam Fyles
这种情况并不经常发生,我不能权威地说它只会在一个节点上发生还是两个节点上都会发生。工作节点的行为是正常的 - 当本地输入队列中有消息需要处理时,它们会积极地处理消息。 - David Boike
奇怪。这种情况经常发生吗?每个节点有多少个NIC卡?我在想,MSMQ是否会因为不知道使用哪张卡而混淆,因此偶尔无法完成ACK的返回。应该有一个注册表设置来锁定它。 - Adam Fyles
可能每周会发生2-3次。所有涉及的服务器(集群节点和工作节点)都虚拟化在VSphere上。集群节点分别位于单独主机上的VSphere客户端上。在它们的虚拟配置中,每台服务器只有一张网卡。当然,在集群服务中,会有多个IP地址来回跳动。 - David Boike
你最终解决了这个问题吗?就好像有些东西正在将节点从分发器中移除。 - Adam Fyles
还没有。我认为这可能与集群实例无法绑定到正确的IP地址有关。有一个注册表键似乎可以解决这个问题,但似乎需要一个热补丁,但是热补丁无法安装-说它不适用于我们的操作系统(Windows 2008 Server)。目前看来它似乎运行良好,但是我们的2个MSMQ集群在群集中运行在不同的节点上,即不都在同一个节点上。当我们想要添加第三个MSMQ实例时,我们有点紧张。 - David Boike
3个回答

2
也许您的服务器被克隆了,因此共享相同的队列管理器ID(QMId)。
MSMQ使用QMId作为哈希来缓存远程计算机的地址。如果您的网络中有多台计算机具有相同的QMId,则可能会出现消息卡住或丢失的情况。
请查看此博客文章中的解释和解决方案:链接

这对我来说并不是这种情况,但是非常好的信息。而且,正如MSMQ所表现出的那样,它非常难以发现。希望它能帮助其他人。而我,另一方面,将继续搜索... - David Boike

2
一年多后,似乎我们的问题已经得到解决。关键要点似乎是:
  • 确保您有一个稳定的DNS系统,以便当MSMQ需要解析主机时可以使用。
  • 在Windows故障转移群集上只创建一个群集实例的MSMQ。
当我们设置Windows故障转移群集时,我们假设在不活动节点上“浪费”资源是不好的,因此,在那个时候有两个相关的NServiceBus集群,我们为Project1创建了一个群集化的MSMQ实例,为Project2创建了另一个群集化的MSMQ实例。大部分时间,我们认为它们会在不同的节点上运行,在维护窗口期间,它们会共同位于同一节点上。毕竟,这是我们对SQL Server 2008的主要和开发实例的设置方式,而且一直工作得很好。
但是,我开始对这种方法产生怀疑,特别是因为每次故障转移每个MSMQ实例一两次似乎总能使消息再次移动。
我向NServiceBus的作者Udi Dahan询问了这个集群主机策略,他面露困惑,问道:“你为什么想做这样的事情?”实际上,Distributor非常轻量级,所以没有必要在可用节点之间均匀分配它们。
之后,我们决定将我们学到的一切都用来重新创建一个只有一个MSMQ实例的故障转移群集。自那以后我们就没有遇到这个问题了。当然,确保解决了这个问题是证明负面的,因此是不可能的。至少已经六个月没有出现这个问题了,但谁知道呢,也许明天它就会出现!让我们希望不会。

1

你的端点是如何配置以保持其订阅的?

如果你的一个或多个服务遇到错误并由故障转移群集管理器重新启动,那么这个服务将永远不会再次收到其他服务的“我已准备好工作”的消息。

当你切换到另一个节点时,我猜想所有的服务都会再次发送这些消息,结果一切都恢复正常。

为了测试这种行为,请执行以下操作:

  1. 停止并重新启动所有服务。
  2. 仅停止其中一个服务。
  3. 重新启动已停止的服务。
  4. 如果你的系统没有挂起,请对每个单独的服务重复此操作。

如果你的系统现在再次挂起,请检查你的配置。在这种情况下,你至少有一个,如果不是全部,服务在重新启动之间失去了订阅。如果你还没有这样做,请将订阅持久化到数据库中。


订阅已经被保存在共享数据库中。集群分发器将其状态存储在集群 MSMQ 队列中。如果工作程序被故障转移群集管理器重新启动,它在任何启动时要做的第一件事情之一就是发送 ReadyMessage。 - David Boike
确实,工作线程在启动时发送ReadyMessage。我要求持久化订阅是因为我遇到了类似的问题。其中一个订阅没有正确保存在数据库中,因此在重新启动后,尽管它发送了消息,其他订阅完全忽略了它,因为它们只检查了数据库。唯一的例外是当所有服务一起重新启动时,然后再次接收到有关该服务的消息。在服务重新启动时:消息再次失败。 - Jens H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接