2

我们的 Rebus/RabbitMQ 设置存在问题,Rebus 突然停止从 RabbitMQ 检索/处理消息。这在上个月发生了两次,我们不确定如何进行。

我们的 RabbitMQ 设置在不同的服务器上有两个节点,Rebus 端是一个 windows 服务。

我们在 Rebus 或运行 Rebus 的服务器上的事件日志中看不到任何错误。我们也没有在 RabbitMQ 服务器上看到错误。

当我们看到其他日志消息时,Rebus(和 Windows 服务)继续运行,例如 DueTimeOutSchedular 和 timeoutreplies。但是,工作线程似乎停止运行,但没有记录任何错误。

它会导致 RabbitMQ 输入队列不断增长 :(,我们正在添加日志记录来监控这一点,以便在再次发生时收到通知。

但我正在寻找有关如何继续“调查”的建议以及如何防止这种情况的想法。也许你们中的一些人以前经历过这种情况?

更新 似乎我们确实有一个节点崩溃,至少在上次发生时。RabbitMQ master 节点崩溃(服务器崩溃),slave 被提升为 master。据我从节点上的 RabbitMQ 日志中可以看出,一切都按计划进行。RabbitMQ 日志中没有其他错误。

发生这种情况时,Rebus 被配置为仅连接到从属节点(然后提升为主节点),因此 Rebus 没有遇到 rabbitmq 故障,因此没有 Rebus 连接错误。但是,似乎 Rebus 在发生故障时停止了处理消息。

实际上,我们似乎在几个队列上遇到了这种情况,其中一些,但似乎并非所有队列都最终处于非同步状态。

更新 2 我能够很容易地重现该问题,因此它可能是我们设置中的配置问题。但这就是我们复制它的方法

  1. 启动集群中的两个节点,例如。rabbit1(主)和rabbit2(从)
  2. Rebus 连接到从机 rabbit2
  3. 关闭rabbit1,主人。rabbit2晋升为 master

队列被镜像

我们有两个小型测试应用程序来重现这一点,一个每秒发送一条消息的“发送者”和一个处理消息的“消费者”。

rabbit1关闭时,“消费者”停止处理消息,但“发送者”继续发送消息,队列不断增长。

  1. 再次启动rabbit1,它作为slave加入

这没有任何效果,“消费者”仍然不处理消息。

  1. 重启“消费者”应用

当“消费者”重新启动时,它会检索所有消息并处理它们。

我想我已经正确地遵循了设置指南,但这可能是我们的配置问题。我似乎找不到任何可以表明我们做错了什么的东西。

Rebus 仍然连接到 RabbitMQ,我们看到在管理站点的连接选项卡中,当它停止处理消息时,“消费者”发送/接收 B/s 下降到大约 2 B/s

更新 3 好的,所以我下载了 Rebus 源并附加到我们的进程中,这样我就可以看到“RabbitMqMessageQueue”类停止时会发生什么。当“rabbit1*”关闭时,“BasicDeliverEventArgs”为空,这是代码

BasicDeliverEventArgs ea;
if (!threadBoundSubscription.Next((int)BackoffTime.TotalMilliseconds, out ea))
{
    return null;
}

// wtf??
if (ea == null)
{
    return null;
}

见:https ://github.com/rebus-org/Rebus/blob/master/src/Rebus.RabbitMQ/RabbitMqMessageQueue.cs#L178

我喜欢“wtf ??” 评论 :)

4

1 回答 1

3

这听起来很奇怪!

每当 Rebus 的 RabbitMQ 传输在连接上遇到错误时,它会抛出连接,等待几秒钟,并确保在可能的情况下再次重新建立连接。

您可以在此处查看源中的相关位置:https ://github.com/rebus-org/Rebus/blob/master/src/Rebus.RabbitMQ/RabbitMqMessageQueue.cs#L205

所以我想问题是RabbitMQ客户端库是否可以以某种方式进入故障状态,静默,当Rebus尝试获取下一条消息时不会抛出异常......?

当您遇到错误时,您是否检查了 RabbitMQ 管理 UI 中的“连接”选项卡并查看客户端是否仍然连接?

更新:

感谢您的彻底调查:)

“wtf??” 之所以在那里,是因为我曾经在ea显然为空时遇到过打嗝,这在当时是出乎意料的,因此导致NullReferenceException后来我的日志中出现异常呕吐。

根据文档,当它到达“流结束”时,Next将返回 true 并将其设置result为 null,这显然是底层模型关闭时发生的情况。

在这种情况下,Rebus 的正确行为是抛出一个适当的异常并让连接重新建立——我会马上实现!

坐等,我会在几分钟内为您准备好解决方案!

于 2014-01-07T21:38:18.313 回答