17

我正在使用这个python 绑定来尝试RabbitMQ 。

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

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

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

有没有更好的办法?

如何重新创建此场景

  • 运行rabbitmq。

  • 取消归档此库

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

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

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

4

3 回答 3

11

我没有看到amqp_consumer.pyamqp_producer.py在 tarball 中,所以重现故障很棘手。

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

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

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

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

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

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

于 2009-09-06T11:14:32.143 回答
5

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

订阅和“拉”的 AMQP 确认模型是相同的。在这两种情况下,消息都保留在服务器上,但其他消费者不可用,直到它被确认(并被删除)、确认(使用 basic.reject;尽管 RabbitMQ 没有实现)或通道/连接关闭(此时消息可供其他消费者使用)。

和(我的重点)

等待确认没有超时。通常这不是问题 ,因为缺少 ack 的常见情况 - 网络或客户端故障 - 将导致连接被丢弃(并因此触发上述行为)。尽管如此,超时对于处理活着但没有响应的消费者可能还是有用的。之前讨论过这个问题。您是否想到了需要此类功能的特定用例?

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

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

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

这意味着可能很难以有序的方式捕获终止和关闭。

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

于 2009-09-05T22:46:53.030 回答
2

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

  • 独家和
  • 自动删除

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

于 2009-09-04T12:37:25.310 回答