繁体   English   中英

Python:Kombu + RabbitMQ死锁 - 队列被阻止或阻塞

[英]Python: Kombu+RabbitMQ Deadlock - queues are either blocked or blocking

问题

我有一个RabbitMQ服务器 ,作为我的一个系统的队列中心。 在过去一周左右,它的制作人每隔几个小时就会完全停止。

我试过了什么

蛮力

  • 停止消费者会释放锁定几分钟,但随后阻止返回。
  • 重启RabbitMQ解决了几个小时的问题。
  • 我有一些自动脚本可以完成丑陋的重启,但显然远非正确的解决方案。

分配更多内存

cantSleepNow的回答之后 ,我将分配给RabbitMQ内存增加到90% 服务器有16GB的内存,消息数量不是很高(每天数百万),所以这似乎不是问题。

从命令行:

sudo rabbitmqctl set_vm_memory_high_watermark 0.9

并使用/etc/rabbitmq/rabbitmq.config

[
   {rabbit,
   [
     {loopback_users, []},
     {vm_memory_high_watermark, 0.9}
   ]
   }
].

代码与设计

我为所有消费者和生产者使用Python。

生产者

生产者是提供呼叫的API服务器。 每当呼叫到达时,都会打开一个连接,发送一条消息并关闭连接。

from kombu import Connection

def send_message_to_queue(host, port, queue_name, message):
    """Sends a single message to the queue."""
    with Connection('amqp://guest:guest@%s:%s//' % (host, port)) as conn:
        simple_queue = conn.SimpleQueue(name=queue_name, no_ack=True)
        simple_queue.put(message)
        simple_queue.close()

消费者

消费者彼此略有不同,但通常使用以下模式 - 打开连接,并等待消息到达。 连接可以长时间保持打开状态(比如几天)。

with Connection('amqp://whatever:whatever@whatever:whatever//') as conn:
    while True:
        queue = conn.SimpleQueue(queue_name)
        message = queue.get(block=True)
        message.ack()

设计推理

  • 消费者总是需要与队列服务器保持开放连接
  • Producer会话应仅在API调用的生命周期内存在

直到大约一周前,这种设计没有引起任何问题。

Web视图仪表板

Web控制台显示,消费者在127.0.0.1172.31.38.50阻止消费者从172.31.38.50172.31.39.120172.31.41.38172.31.41.38

阻止/阻止队列

系统指标

为了安全起见,我检查了服务器负载。 正如预期的那样,负载平均值和CPU利用率指标很低。

在此输入图像描述

为什么兔子MQ每次都这么僵局?

这很可能是由R​​abbitMQ 3.6.2的管理模块中的内存泄漏引起的。 这已在RabbitMQ 3.6.3中修复,可在此处获得

问题本身在这里描述,但也在RabbitMQ消息板上进行了广泛讨论; 例如这里这里 众所周知,这会导致许多奇怪的问题, 这里报告的问题就是一个很好的例子。

作为临时修复,直到新版本发布,您可以升级到新的版本,降级到3.6.1或完全禁用管理模块。

我写这个作为答案,部分是因为它可能有所帮助,部分原因是因为它太大而无法作为评论。

首先,我很抱歉错过了这条message = queue.get(block=True) 免责声明 - 我不熟悉python或PIKA API。

AMQP的basic.get实际上是同步的 ,你设置的是block=true 正如我所说,不知道这对PIKA意味着什么,但结合不断汇集队列,听起来效率不高。 因此,出于某种原因,由于消费者阻止了队列访问,发布者可能会被拒绝连接。 它实际上非常适合你暂时解决问题的方法, Stopping the consumers releases the lock for a few minutes, but then blocking returns.

我建议尝试使用AMQP的basic.consume而不是basic.get 我不知道获得的动机是什么,但在大多数情况下(无论如何我的体验)你应该选择消费。 只是引用上述链接

此方法使用专为特定类型的应用程序设计的同步对话框直接访问队列中的消息,其中同步功能比性能更重要。

RabbitMQ文档中,它表示当代理资源不足时连接被阻止,但是当你写入时,负载非常低。 为了安全起见,您可以检查内存消耗和可用磁盘空间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM