【问题标题】:Celery and RabbitMQ eventually stopping due to memory exhaustionCelery 和 RabbitMQ 最终因内存耗尽而停止
【发布时间】:2016-03-18 01:36:45
【问题描述】:

我有基于 Celery 的任务队列,其中 RabbitMQ 作为代理。我每天处理大约 100 条消息。我没有设置后端。

我这样启动任务大师:

broker = os.environ.get('AMQP_HOST', None)
app = Celery(broker=broker)
server = QueueServer((default_http_host, default_http_port), app)

...我这样启动工人:

broker = os.environ.get('AMQP_HOST', None)
app = Celery('worker', broker=broker)
app.conf.update(
    CELERYD_CONCURRENCY = 1,
    CELERYD_PREFETCH_MULTIPLIER = 1,
    CELERY_ACKS_LATE = True,
)

服务器正常运行了很长一段时间,但大约两周后它突然停止。我已经追踪到 RabbitMQ 由于内存耗尽而不再接收消息:

Feb 25 02:01:39 render-mq-1 docker/e654ac167b10[2189]: vm_memory_high_watermark set. Memory used:252239992 allowed:249239961
Feb 25 02:01:39 render-mq-1 docker/e654ac167b10[2189]: =WARNING REPORT==== 25-Feb-2016::02:01:39 ===
Feb 25 02:01:39 render-mq-1 docker/e654ac167b10[2189]: memory resource limit alarm set on node rabbit@e654ac167b10.
Feb 25 02:01:39 render-mq-1 docker/e654ac167b10[2189]: **********************************************************
Feb 25 02:01:39 render-mq-1 docker/e654ac167b10[2189]: *** Publishers will be blocked until this alarm clears ***
Feb 25 02:01:39 render-mq-1 docker/e654ac167b10[2189]: **********************************************************

问题是我无法弄清楚需要进行哪些不同的配置以防止这种耗尽。显然某处没有清除某些东西,但我不明白是什么。

例如,大约 8 天后,rabbitmqctl status 向我显示:

{memory,[{total,138588744},
      {connection_readers,1081984},
      {connection_writers,353792},
      {connection_channels,1103992},
      {connection_other,2249320},
      {queue_procs,428528},
      {queue_slave_procs,0},
      {plugins,0},
      {other_proc,13555000},
      {mnesia,74832},
      {mgmt_db,0},
      {msg_index,43243768},
      {other_ets,7874864},
      {binary,42401472},
      {code,16699615},
      {atom,654217},
      {other_system,8867360}]},

...刚开始时它要低得多:

{memory,[{total,51076896},
      {connection_readers,205816},
      {connection_writers,86624},
      {connection_channels,314512},
      {connection_other,371808},
      {queue_procs,318032},
      {queue_slave_procs,0},
      {plugins,0},
      {other_proc,14315600},
      {mnesia,74832},
      {mgmt_db,0},
      {msg_index,2115976},
      {other_ets,1057008},
      {binary,6284328},
      {code,16699615},
      {atom,654217},
      {other_system,8578528}]},

...即使所有队列都为空(当前正在处理的一项作业除外):

root@dba9f095a160:/# rabbitmqctl list_queues -q name memory messages messages_ready messages_unacknowledged
celery  61152   1   0   1
celery@render-worker-lg3pi.celery.pidbox    117632  0   0   0
celery@render-worker-lkec7.celery.pidbox    70448   0   0   0
celeryev.17c02213-ecb2-4419-8e5a-f5ff682ea4b4   76240   0   0   0
celeryev.5f59e936-44d7-4098-aa72-45555f846f83   27088   0   0   0
celeryev.d63dbc9e-c769-4a75-a533-a06bc4fe08d7   50184   0   0   0

我不知道如何找到内存消耗的原因。任何帮助将不胜感激。

【问题讨论】:

  • 似乎您的队列(或交换)正在进入流动状态。请检查一下 - 它在 rabbitmq 网络用户界面中可见
  • 此特定服务器未安装或配置 Web UI。有没有使用rabbitmqctl 或其他命令行工具查找这些信息的简单方法?另外,通过阅读Understanding flow control,我不确定这是怎么回事,因为描述暗示服务器无法跟上传入的连接,但请求从未超过每分钟 3-4 个。
  • 我不知道命令行...是的,流意味着发布者/s对于服务器来说太快了。这也可以解释为消费者太慢了处理消息,但最后似乎只有发布者冷导致此。 rabbitmq.com/memory.html
  • 我很确定这不是问题所在。我在等待处理的队列中从来没有超过 20 个项目。
  • 服务器的总内存是多少? 2GB 是 rabbitmq 内存消耗的适当限制吗?您是否检查过dmesg 输出以查看是否在任何阶段调用了内核OOM 杀手?你有没有运行htop 来查看服务器上的整体内存利用率是多少?

标签: rabbitmq celery


【解决方案1】:

日志说你使用了 252239992 字节,也就是 250Mb 左右,不算高。 你在这台机器上有多少内存,rabbitmq 的vm_memory_high_watermark 值是多少? (您可以通过运行rabbitmqctl eval "vm_memory_monitor:get_vm_memory_high_watermark()." 来检查它) 也许你应该增加水印。

另一种选择是让你的所有队列lazyhttps://www.rabbitmq.com/lazy-queues.html

【讨论】:

  • 我很确定这不是问题所在。问题不在于内存中的任务太多,而是随着时间的推移,即使队列大部分时间是空的,内存也会逐渐消耗。
  • 当前水印是默认值,在 600MB 机器上占系统 RAM 的 40%。如果这确实是正确的答案,我可以提高这个阈值,我担心内存使用的持续增长将达到我设置的任何标记,并且我将在不同的阈值处再次遇到相同的问题。我想找到增长的根本原因(如果可能)并然后适当地设置阈值。
  • 根据你的内存使用情况,大部分内存被message_indexbinary使用。这意味着消息尚未被垃圾收集,而已从队列中删除。如果您的消息小于 4KB,您可以将 queue_index_embed_msgs_below 设置为较低的值以将所有消息发送到 message_store 而不是 message_index(以提高垃圾收集率)并启用上面提到的惰性队列以在内存中存储更少的消息。无论如何,256MB 的内存对于 RabbitMQ 来说是相当小的数量。
  • 啊,太好了,好吧,我可以合作。谢谢,现在这开始变得更有意义了。
  • RabbitMQ 可用的“典型”内存量是多少?同样,总体流量非常低,因此实际上一次在队列中维护的活动项目不会超过 10-20 个(通常队列是空的)。
【解决方案2】:

您似乎没有生成大量消息,因此 2GB 内存消耗似乎异常高。尽管如此,您可以尝试让 rabbitmq 删除旧消息 - 在您的 celery 配置集中

CELERY_DEFAULT_DELIVERY_MODE = 'transient'

【讨论】:

  • 应该在排队任务的端点上还是在使用它们的端点上,或两者兼而有之?它看起来是特定于发件人的,但只是想确定一下。
  • Using Transient Queues 阅读此内容时,看起来这是关于将消息保存到磁盘而不是将它们保存在内存中,但是一旦它们完成,它们不会从磁盘中删除吗?此外,似乎保存到磁盘不应该随着时间的推移消耗越来越多的内存?
猜你喜欢
  • 2012-02-05
  • 2013-12-08
  • 1970-01-01
  • 2015-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-23
  • 2012-11-10
相关资源
最近更新 更多