1. celery worker占用内存情况
并发n个wokers,n如下表1的worker数,在不执行任务的情况下,n个worker对应rss值(/sys/fs/cgroup/memory/memory.stat)及每增加一个worker所增加rss值情况。
worker数 | RSS值(B) | RSS增量(MB)[n-(n-1)] |
0 | 364810240 |
|
1 | 407392256 | 40.609 [1-0] |
2 | 434069504 | 25.441 |
3 | 450125824 | 15.313 |
4 | 464175104 | 13.398 |
5 | 482721792 | 17.688 |
6 | 496492544 | 13.132 |
7 | 512901120 | 15.648 |
8 | 529100800 | 15.449 |
9 | 545804288 | 15.930 |
10 | 563519488 | 16.896 |
…… | …… | …… |
19 | 707670016 |
|
20 | 726679552 | 18.129 [20-19] |
表1 开启worker数占用内存情况
由此可以看出,每增加一个worker对应rss值增加16MB左右
(20workers对应rss值-0 workers对应rss值)/1024/1024/20=17.255MB
2. 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进行备份任务,每次任务执行完毕对应rss值如下表2,从下表可以看出,当worker没有执行到最大任务时(即销毁重建),每执行一次任务rss必然有所增加,任务数为9,10时(celery均匀调度,并发数*最大任务数),分别有原8228 worker被销毁,重新创建9386 worker及原8226 worker被销毁,重新创建9564 worker,此时,从表中可以看到运行第9次时,rss有所下降,运行第10次时,rss回到初如值,同样任务执行第19、20次情况类似。
任务数 | RSS值(B) |
0 | 437100544 |
1 | 444547072 |
2 | 449728512 |
3 | 449929216 |
4 | 450220032 |
5 | 450392064 |
6 | 450600960 |
7 | 450662400 |
8 | 450711552 |
9 | 440414208 |
10 | 435408896 |
11 | 441864192 |
12 | 451543040 |
13 | 451756032 |
…… | …… |
19 | 441851904 |
20 | 435810304 |
表2 celery每执行一次任务对应rss值情况
2.celery并发计算规则
celery任务并发只与celery配置项CELERYD_CONCURRENCY 有关,与CELERYD_MAX_TASKS_PER_CHILD没有关系,即CELERYD_CONCURRENCY=2,只能并发2个worker,此时备份较大的文件,执行两次可以看到两个task任务并行执行,而执行第三个任务时,开始排队,直到两个worker执行完毕。
4. 结论
celery执行完任务不释放内存与原worker一直没有被销毁有关,因此CELERYD_MAX_TASKS_PER_CHILD可以适当配置小点,而任务并发数与CELERYD_CONCURRENCY配置项有关,每增加一个worker必然增加内存消耗,同时也影响到一个worker何时被销毁,因为celery是均匀调度任务至每个worker,因此也不宜配置过大,适当配置。