如何在 RabbitMQ 服务器上设置超时检测?

Posted

技术标签:

【中文标题】如何在 RabbitMQ 服务器上设置超时检测?【英文标题】:How to set timeout detection on a RabbitMQ server? 【发布时间】:2010-11-23 15:12:07 【问题描述】:

我正在尝试RabbitMQ 与this python 绑定。

我注意到的一件事是,如果我不干净地杀死了一个消费者(模拟一个崩溃的程序),服务器会认为这个消费者仍然存在很长时间。这样做的结果是所有其他消息都将被忽略。

例如,如果您杀死消费者 1 次并重新连接,则 1/2 消息将被忽略。如果你杀死另一个消费者,那么 2/3 的消息将被忽略。如果您杀死 3rd,则 3/4 消息将被忽略,依此类推。

我尝试打开确认,但似乎没有帮助。我找到的唯一解决方案是手动停止服务器并重置它。

有没有更好的办法?

如何重现此场景

运行rabbitmq。

取消归档this library。

下载消费者和发布者here。 运行 amqp_consumer.py 两次。运行 amqp_publisher.py,输入一些数据并观察它是否按预期工作。消息以循环方式接收。

使用 kill -9 或任务管理器终止其中一个消费者进程。

现在,当您发布消息时,50% 的消息将丢失。

【问题讨论】:

我无法重现这个。你用的是什么版本的linux 好问题——如果在防火墙或 IP 负载平衡设备后面运行会在 N 秒后丢弃空闲套接字,这是一个关键问题,因为 RabbitMQ 和客户端都不会被告知套接字已经消失直到他们尝试使用它。 我确实对 RabbitMQ 3.2.1 和 puka 有完全相同的问题。似乎仍然没有好的解决方案。 【参考方案1】:

我在 tarball 中看不到 amqp_consumer.pyamqp_producer.py,因此重现故障很棘手。

每当操作系统通知套接字已关闭时,RabbitMQ 就会终止连接,释放它们未确认的消息以重新传递给其他客户端。你的症状很奇怪,即使是kill -9 也应该导致 TCP 套接字被正确清理。

有些人注意到,当在 AMQP 客户端和服务器之间使用防火墙或 NAT 设备运行时,套接字的存活时间超过了应有的时间。这可能是一个问题,还是您在本地主机上运行所有内容?另外,您在什么操作系统上运行系统的各个组件?

预计到达时间: 从您下面的评论中,我猜您在 Linux 上运行服务器时,您可能在 Windows 上运行客户端。如果是这种情况,那么可能是 Windows TCP 驱动程序没有正确关闭套接字,这与 Unix 上的 kill-9 行为不同。 (在 Unix 上,内核会正确关闭任何被杀死进程的 TCP 连接。)

如果是这样,那么坏消息是RabbitMQ只能在socket关闭时释放资源,所以如果客户端操作系统不这样做,它就无能为力了。这与几乎所有其他基于 TCP 的服务相同。

好消息,不过,AMQP 支持“心跳”选项,正是在这些情况下,网络结构是不可信的。您可以尝试启用心跳。启用它们后,如果服务器在可配置的时间间隔内没有接收到任何流量,它就会确定连接一定是死的。

坏消息,然而,我认为 py-amqplib 目前不支持心跳。不过值得一试!

【讨论】:

很抱歉。生产者和消费者在这里blogs.digitar.com/jjww/code-samples 我在运行生产者和消费者的同时在远程 linux 服务器上运行 rabbitmq。我意识到套接字可能没有完全关闭,但这正是我想要模仿的。我正在测试 rabbitmq 如何处理可能没有完全关闭套接字的崩溃进程,不幸的是它似乎不能很好地处理这个问题。 @Tony;如何在 RabbitMQ 服务器中启用“心跳”选项(例如在 /etc/rabbitmq/rabbitmq.config 中)? 没关系,我现在明白这是在客户端配置的。【参考方案2】:

RabbitMQ 对来自客户端的消息已处理确认没有超时:请参阅this post(可能对整个线程感兴趣)。帖子中的一些要点:

订阅的 AMQP ack 模型 和“拉”是相同的。同时 情况下,消息保留在 服务器,但其他人不可用 消费者,直到它已经 确认(并被删除),确认 (使用 basic.reject;虽然 RabbitMQ 没有实现)或 通道/连接关闭(此时 点消息变为可用 给其他消费者)。

和(我的重点)

等待没有超时 确认。通常这不是问题 由于失踪的常见情况 ack - 网络或客户端故障 - 将导致连接得到 丢弃(从而触发 上述行为)。仍然, 超时可能有用,例如, 处理活着但没有反应 消费者。这已经出现在 之前的讨论。有没有具体的 你想到的用例 需要这样的功能吗?

这个问题很可能会发生,因为在客户端拉取模型中,服务器更难检测到断开的连接(与活着但没有响应的消费者相反),特别是当服务器似乎很乐​​意永远等待确认时。

更新:在 Linux 上,您可以为 SIGTERM 和/或 SIGKILL 和/或 SIGINT 附加信号处理程序,并希望从客户端以有序的方式关闭连接。在 Windows 上,我相信从任务管理器关闭会调用 Win32 TerminateProcess API,MSDN 对此表示:

如果一个进程被终止 TerminateProcess,所有线程 进程立即终止 没有机会运行其他代码。 这意味着线程不 在终止处理程序中执行代码 块。此外,没有附加的 DLL 被通知该过程是 分离。

这意味着可能很难捕捉到终止和有序的关闭。

在 RabbitMQ 列表中使用您自己的 ack 超时用例可能值得追求。

【讨论】:

根据该邮件列表,如果消费者终止连接,它应该可以正常运行。但是,taskmanager 中的 kill -9 或结束进程也应该以这种方式终止连接。但它仍然无法正常工作。【参考方案3】:

请提供有关您声明的组件的更多细节。通常(并且独立于客户端实现)具有属性的队列

独家和 自动删除

应在声明客户端和代理之间的连接断开后立即删除。但是,这对共享队列没有帮助。请详细说明您要建模的内容。

【讨论】:

我不是在谈论队列何时被删除。我说的是 rabbitmq 如何在很长一段时间内都没有检测到崩溃的连接,并一直尝试向它们发送消息,就好像它们仍然在那里一样。

以上是关于如何在 RabbitMQ 服务器上设置超时检测?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 python 的 socket recv 方法上设置超时?

spring boot 连接rabbitMQ 失败汇总与解决

如何为加载已关闭的外部 javascript 文件设置超时

如何在一台机器上配置多个RabbitMQ

如何在一台机器上配置多个RabbitMQ

网络服务器的超时检测: