6

问题

我有一个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()

设计推理

  • 消费者始终需要与队列服务器保持开放连接
  • 生产者会话应该只存在于 API 调用的生命周期内

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

Web 视图仪表板

Web 控制台显示消费者进入127.0.0.1172.31.38.50阻止消费者访问172.31.38.50172.31.39.120和。172.31.41.38172.31.41.38

阻塞/阻塞队列

系统指标

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

在此处输入图像描述

为什么兔子MQ每次都会出现这样的死锁?

4

2 回答 2

4

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

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

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

于 2016-06-19T10:18:12.723 回答
1

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

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

AMQPbasic.get实际上是同步的,您正在设置block=true. 正如我所说,不知道这在 PIKA 中意味着什么,但结合不断合并队列,听起来效率不高。因此,无论出于何种原因,发布者都可能由于队列访问被消费者阻止而拒绝连接。它实际上非常适合您通过以下方式暂时解决问题的方式Stopping the consumers releases the lock for a few minutes, but then blocking returns.

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

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

RabbitMQ 文档中,它说当代理资源不足时连接被阻塞,但正如您所写的那样,负载非常低。为了安全起见,您可以检查内存消耗和可用磁盘空间。

于 2016-06-05T10:54:24.280 回答