大芹菜任务内存泄漏

GDo*_*orn 5 python django memory-leaks celery

我有一个巨大的芹菜任务基本上像这样工作:

 @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()
Run Code Online (Sandbox Code Playgroud)

我还有一个manage.py命令,只运行my_task(int(args [0])),因此可以排队或在命令行上运行.

在命令行上运行时,print_memory_usage()会显示相对恒定的内存量.

当在celery中运行时,print_memory_usage()显示内存量不断增加,一直持续到进程被终止(我使用Heroku的内存限制为1GB,但其他主机会有类似的问题.)内存泄漏似乎与chunk_size对应; 如果我增加chunk_size,每次打印的内存消耗会增加.这似乎暗示芹菜正在记录查询本身,或者我的堆栈中的其他东西.

芹菜会在其他地方记录查询吗?

其他说明:

  • DEBUG已关闭.
  • RabbitMQ和Amazon的SQS都作为队列发生了这种情况.
  • 这在本地和Heroku上都会发生(尽管由于具有16 GB的RAM而不会在本地被杀死.)
  • 除了删除对象之外,任务实际上还要做更多的事情.稍后它通过MyModel.objects.get_or_create()创建新对象.这也表现出相同的行为(内存在芹菜下增长,不会在manage.py下增长).

GDo*_*orn 2

事实证明这与芹菜没有任何关系。相反,是 new relic 的记录器消耗了所有内存。尽管 DEBUG 设置为 False,它仍将每个 SQL 语句存储在内存中,准备将其发送到日志服务器。我不知道它是否仍然如此,但在任务完全完成之前它不会刷新该内存。

解决方法是对每个 id 块使用子任务,以对有限数量的项目进行删除。

当将其作为管理命令运行时这不是问题的原因是 new relic 的记录器没有集成到命令框架中。

提出的其他解决方案试图减少分块操作的开销,这对解决 O(N) 扩展问题没有帮助,或者在超出内存限制时强制 celery 任务失败(该功能在时间,但最终可能会进行无限次重试。)