我本來以為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執行完畢。