Celery使用过程中的内存泄露问题和解决办法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Celery使用过程中的内存泄露问题和解决办法相关的知识,希望对你有一定的参考价值。

Celery使用过程中的内存泄露问题

问题描述

celery 异步任务在定时循环的执行异步任务,隔了半个月左右,收到内存告警的信息,连续一周内内存是在缓慢增加的。
进行top命令查询内存的占用率是很高的 如下图所示

技术图片
技术图片

问题定位

使用 Memory Profiler工具包进行debug,
发现异步任务中存在内存增量的地方大多是发送request请求的地方。例如下面的例子

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
5  23.94531 MiB  23.94531 MiB           1   @profile(precision=5)
6                                         def my_func(url):
7                                         
8  25.59375 MiB   1.64844 MiB           1       resp = requests.get(url)
9  25.59375 MiB   0.00000 MiB           1       print(resp)
10  25.59375 MiB   0.00000 MiB           1       return resp

解决过程

去网上查询相关Celery内存泄露的问题,在github上Celery项目中发现也有出现类似的内存泄露问题的issue,
主要介绍的是Celery向RabbitMQ发起重连请求的时候,也产生了内存的泄露问题。但是这个问题还没有解决依然处于open状态

又查询了requests请求的内存泄露问题:使用requests请求时会造成内存泄漏,请求完后内存不会释放。 使用requests.Session()则是使用的一个实例,可以解决这个问题
但是,requests.Session()有线程安全问题 最好是一个线程使用一个Session() 但requests.Session()并不会随着线程结束而结束。这个问题尚未完全解决

这显然不能解决问题又看了看,Celery官方文档中的Max tasks per child setting,
中说明如果在Celery任务程序中存在内存的泄露问题,但又无法在程序内部控制时。可以使用此选项,您可以配置这个worker在执行了最大的task任务数之后,启动一个新的进程代替并关闭之前的进程。

目前因为程序中使用了大量的requests包,无法很快的去替换并找到不存在内存泄露的办法(而且看了网上的资料大概都是urllib3,urllib,requests都会存在内存的泄露问题)

所以目前可以解决燃眉之急的办法就是使用CELERYD_MAX_TASKS_PER_CHILD在worker执行了30个任务数之后,进行重建。

CELERYD_CONCURRENCY = 1  # celery worker 的并发数
CELERYD_PREFETCH_MULTIPLIER = 1  # 一次预取多少消息乘以并发进程数。默认值为4 要禁用预取将其设置1 若为0 将允许工作程序继续使用所需数量的消息。
CELERYD_MAX_TASKS_PER_CHILD = 30  # 池工作进程可以被新任务替换之前执行的最大任务数。默认值是没有限制。

但是重建进程并不是很好的解决方案,还是需要研究一下requests请求的内存泄露问题该怎么解决。放在之后进行研究。


  • From: xaohuihui
  • 手搓不易,记得star哦

以上是关于Celery使用过程中的内存泄露问题和解决办法的主要内容,如果未能解决你的问题,请参考以下文章

PHP CURL内存泄露的解决方法

swoole 内存泄露的问题有没有好的办法解决

swoole 内存泄露的问题有没有好的办法解决

CELERY 内存中的变量串数据

什么是内存泄露?内存泄露如何解决?

使用SDWebImage加载大量图片后造成内存泄露的解决办法 转载