celery内存泄露分析问题


我本来以为1个工作节点执行完一项任务后,会释放任务申请的内存(毕竟一项任务执行完后它内部变量就不能引用了,python的垃圾回收机制应该会回收掉才对),这样的话最多同时有4个B工作节点在运行着,也就差不多消耗4G内存,绰绰有余!

然而,事实上,在celery中一个工作节点并不会释放一次任务的内存(至少从实验结果来看是这样的),而是不断累加。这样当我“轰炸式”的任务来袭时,明显机器就支撑不住了(囧)。那怎么办呢?经过上网搜索以及个人实验,觉得这个方法应该是可行的:

设置celery的每个worker能处理的最大任务数:CELERYD_MAX_TASKS_PER_CHILD = 10

一旦任务数超过这个数值时,当前worker进程就会被销毁(同时释放占用内存),并重新创建新的worker进程。

下图:一个worker节点,进程pid为15286,占用物理内存为10013324KB,约10GB,当前系统free内存5G。

 当任务数超过1?0个后,15286进程被销毁了,并新创建了19499进程,此时占用内存仅800M,且系统总free内存为10G,增多了!

 除此之外,还有一个选项也可以设置用于防止内存泄漏:CELERYD_MAX_MEMORY_PER_CHILD,单位是KB。一旦某个任务产生的内存超过这个限制的话(而不是指该任务导致当前worker节点的总内存超过这个限制),则这个任务仍然会执行下去,不过该任务执行完之后,当前worker进程就会被kill掉,重新创建新worker进程。

celery内存泄露分析

celery配置项如下

CELERYD_CONCURRENCY = 2      celery worker并发数
CELERYD_MAX_TASKS_PER_CHILD = 5   每个worker最大执行任务数

执行celery -A ansibleAPI.celery worker启动celery,通过ps -ef | grep celery可以看到两个celery worker进程(8226,8228)。

利用celery worker进行某个任务,当worker没有执行到最大任务时(即销毁重建),每执行一次任务占用内存必然有所增加,任务数为9,10时(celery均匀调度,并发数*最大任务数),分别有原8228 worker被销毁,重新创建9386 worker及原8226 worker被销毁,重新创建9564 worker,此时,运行第9次时,占用总内存有所下降,运行第10次时,总内存回到初如值,同样任务执行第19、20次情况类似。

celery并发计算规则

celery任务并发只与celery配置项CELERYD_CONCURRENCY 有关,与CELERYD_MAX_TASKS_PER_CHILD没有关系,即CELERYD_CONCURRENCY=2,只能并发2个worker,此时任务处理较大的文件时,执行两次可以看到两个task任务并行执行,而执行第三个任务时,开始排队,直到两个worker执行完毕。