簡體   English   中英

大型芹菜任務內存泄漏

[英]Large celery task memory leak

我有一個巨大的芹菜任務,基本上是這樣工作的:

 @task
 def my_task(id):
   if settings.DEBUG:
     print "Don't run this with debug on."
     return False

   related_ids = get_related_ids(id)

   chunk_size = 500

   for i in xrange(0, len(related_ids), chunk_size):
     ids = related_ids[i:i+chunk_size]
     MyModel.objects.filter(pk__in=ids).delete()
     print_memory_usage()

我還有一個 manage.py 命令,它只運行 my_task(int(args[0])),因此它可以排隊或在命令行上運行。

在命令行上運行時,print_memory_usage() 顯示使用的內存量相對恆定。

在 celery 中運行時,print_memory_usage() 顯示內存量不斷增加,直到進程被終止(我使用的 Heroku 內存限制為 1GB,但其他主機也會​​有類似的問題。)內存泄漏似乎是與 chunk_size 對應; 如果我增加 chunk_size,每次打印的內存消耗會增加。 這似乎表明 celery 正在記錄查詢本身,或者我的堆棧中的其他內容。

celery 是否在其他地方記錄查詢?

其他注意事項:

  • 調試關閉。
  • RabbitMQ 和 Amazon 的 SQS 作為隊列都會發生這種情況。
  • 這在本地和 Heroku 上都會發生(盡管由於有 16 GB 的 RAM,它不會在本地被殺死。)
  • 該任務實際上會繼續做更多的事情,而不僅僅是刪除對象。 稍后它通過 MyModel.objects.get_or_create() 創建新對象。 這也表現出相同的行為(內存在芹菜下增長,在 manage.py 下不增長)。

有點死屍,但這可以幫助人們在未來。 雖然最好的解決方案應該是追蹤問題的根源,但有時這也是不可能的,因為問題的根源不在我們的控制范圍內。 在這種情況下,您可以在生成 Celery 工作進程時使用--max-memory-per-child選項。

結果證明這與芹菜無關。 相反,是新遺物的記錄器消耗了所有內存。 盡管 DEBUG 被設置為 False,它還是將每個 SQL 語句存儲在內存中,以准備將其發送到他們的日志服務器。 我不知道它是否仍然以這種方式運行,但是在任務完全完成之前它不會刷新該內存。

解決方法是對每個 id 塊使用子任務,對有限數量的項目進行刪除。

將此作為管理命令運行時這不是問題的原因是新遺物的記錄器未集成到命令框架中。

提出的其他解決方案試圖減少分塊操作的開銷,這對 O(N) 縮放問題沒有幫助,或者如果超出內存限制則強制 celery 任務失敗(該功能在當時不存在)時間,但最終可能會無限重試。)

您可以使用--autoscale n,0選項運行 worker。 如果池的最小數量為 0 celery 將殺死未使用的工人並釋放內存。

但這不是一個好的解決方案。

django 的收集器使用了大量內存 - 在刪除之前它收集所有相關對象並首先刪除它們。 您可以在模型字段上將 on_delete 設置為 SET_NULL。

另一種可能的解決方案是刪除有限制的對象,例如每小時刪除一些對象。 這將降低內存使用率。

Django 沒有 raw_delete。 您可以為此使用原始 sql。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM