我注意到的一件事是,如果我不洁净地杀死一个消费者(模仿一个崩溃的程序),服务器会认为这个消费者仍然存在很长时间。结果是每个其他消息都将被忽略。
例如,如果您杀死消费者1次并重新连接,则将忽略1/2消息。如果您杀死另一个消费者,则将忽略2/3消息。如果你杀了第3个,那么将忽略3/4个消息,依此类推。
我已尝试启用确认,但似乎没有帮助。我找到的唯一解决方案是手动停止服务器并重置它。
有更好的方法吗?
如何重新创建此方案
运行rabbitmq。
取消归档this library。
下载消费者和发布商here。 运行amqp_consumer.py两次。运行amqp_publisher.py,输入一些数据并观察它是否按预期工作。消息以循环方式接收。
使用kill -9或任务管理器杀死其中一个使用者进程。
现在,当您发布消息时,50%的消息将会丢失。
答案 0 :(得分:11)
我在tarball中看不到amqp_consumer.py
或amqp_producer.py
,因此重现错误很棘手。
当操作系统告知套接字已关闭时,RabbitMQ终止连接,释放未确认的消息以便重新传递给其他客户端。你的症状非常奇怪,因为即使kill -9
也应该正确清理TCP套接字。
有些人注意到套接字存在的问题比在AMQP客户端和服务器之间运行防火墙或NAT设备时存在的时间长。这可能是一个问题,还是你在localhost上运行一切?另外,您在运行系统的各个组件的操作系统是什么?
ETA:从下面的评论中我猜测,当您在Linux上运行服务器时,您可能正在Windows上运行客户端。如果是这种情况,则可能是Windows TCP驱动程序没有正确关闭套接字,这与Unix上的kill-9行为不同。 (在Unix上,内核将正确关闭任何被杀死进程的TCP连接。)
如果是这种情况,则坏消息是RabbitMQ只能在套接字关闭时释放资源,因此如果客户端操作系统不这样做,那么它就无法做到。这与几乎所有其他基于TCP的服务相同。
好消息,但AMQP支持“心跳”选项,恰好适用于网络结构不可靠的情况。您可以尝试启用心跳。启用后,如果服务器在可配置的时间间隔内没有收到任何流量,则会确定连接必须已经死亡。
然而,坏消息是我认为py-amqplib目前不支持心跳。值得一试!答案 1 :(得分:5)
RabbitMQ没有来自客户端的确认已超时处理消息的超时:请参阅this post(整个帖子可能很有用)。帖子中的一些重点:
订阅的AMQP ack模型 和“拉”是相同的。同时 消息保存在 服务器,但其他人不可用 消费者,直到它已经 ack'ed(并被删除),nack'ed (使用basic.reject;虽然是RabbitMQ 没有实现那个)或者 通道/连接已关闭(在此处 指出消息可用 给其他消费者。)
和(我的重点)
等待时没有超时 的ACK。通常这不是问题 自从失踪的常见情况 确认 - 网络或客户端故障 - 将导致连接得到 掉线(从而触发了 上述行为)。仍然, 例如,超时可能对我有用 处理活着但没有反应 消费者即可。这已经出现了 之前的讨论。有具体的吗? 用例你记得那个 需要这样的功能吗?
问题可能正在发生,因为在客户端拉模型中,服务器更难以检测到断开的连接(而不是活着但没有响应的消费者),特别是因为服务器似乎很乐意等待永远的确认。
更新:在Linux上,您可以为SIGTERM和/或SIGKILL和/或SIGINT附加信号处理程序,并希望从客户端以有序的方式关闭连接。在Windows上,我相信从任务管理器关闭会调用Win32 TerminateProcess
API,MSDN会说:
如果进程终止
TerminateProcess
,所有线程 进程立即终止 没有机会运行额外的代码。 这意味着线程没有 在终止处理程序中执行代码 块。另外,没有附加的DLL 通知该过程是 剥离
这意味着可能难以有序地捕获终止和关闭。
可能值得在RabbitMQ列表中使用您自己的用例进行ack超时。
答案 2 :(得分:2)
请提供有关您声明的组件的更多细节。通常(并且独立于客户端实现)具有属性
的队列就会被删除。但是,这对共享队列没有帮助。请详细说明您的确切模型。