Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 大芹菜任务内存泄漏_Python_Django_Memory Leaks_Celery_Newrelic - Fatal编程技术网

Python 大芹菜任务内存泄漏

Python 大芹菜任务内存泄漏,python,django,memory-leaks,celery,newrelic,Python,Django,Memory Leaks,Celery,Newrelic,我有一个巨大的芹菜任务,基本上是这样: @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

我有一个巨大的芹菜任务,基本上是这样:

 @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命令,它只运行我的_任务(int(args[0]),因此它可以排队或在命令行上运行

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

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

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

其他说明:

  • 调试已关闭
  • 这在RabbitMQ和Amazon的SQS作为队列时都会发生
  • 这在本地和Heroku上都会发生(尽管它不会在本地被杀死,因为它有16 GB的RAM)
  • 这项任务实际上要做的不仅仅是删除对象。稍后,它通过MyModel.objects.get\u或\u create()创建新对象。这也表现出同样的行为(内存在芹菜下增长,在manage.py下不增长)

试试

您可以使用选项运行worker。若最小池数为0,芹菜将杀死未使用的工人,并释放内存

但这不是一个好的解决方案

django的收集器使用了大量内存—在删除之前,它会收集所有相关对象并首先删除它们。您可以在模型字段上设置为空

另一种可能的解决方案是删除有限制的对象,例如每小时删除一些对象。这将降低内存使用率


Django没有原始删除。您可以使用原始sql来实现这一点。

有一点,但这可以帮助将来的人们。虽然最好的解决方案应该是跟踪问题的根源,但有时这也不可能,因为问题的根源不在我们的控制范围之内。在这种情况下,您可以在生成芹菜工作进程时使用该选项。

这与芹菜无关。相反,是NewRelic的记录器消耗了所有的记忆。尽管DEBUG被设置为False,但它将每个SQL语句存储在内存中,以准备将其发送到日志服务器。我不知道它是否仍以这种方式运行,但在任务完全完成之前,它不会刷新内存

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

将其作为管理命令运行时不会出现问题的原因是NewRelic的记录器没有集成到命令框架中


提出的其他解决方案试图减少分块操作的开销,这对O(N)缩放问题没有帮助,或者在超过内存限制时强制芹菜任务失败(当时不存在此功能,但最终可能会无限次重试)。

尝试使用
itertools.islice(相关\u id,i,i+块大小)
而不是
相关\u id[i:i+块大小]
。这可能不是唯一的因素,但这可能会减少一些复制。哪个Django版本?Django 1.4的
QuerySet.delete
总是在删除实例之前将其加载到内存中。我会尝试用原始SQL
delete
语句替换它,看看会发生什么。@Vasilyfaronov:即使对象退出scop之后此外,这并不能解释为什么manage.py命令中的内存使用量是恒定的,而芹菜中的内存使用量不是恒定的。这确实有助于内存泄漏。正如旁注,如果超出限制,这不会杀死正在运行的任务,而是会在任务完成后杀死工作人员。