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下不增长)
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
总是在删除实例之前将其加载到内存中。我会尝试用原始SQLdelete
语句替换它,看看会发生什么。@Vasilyfaronov:即使对象退出scop之后此外,这并不能解释为什么manage.py命令中的内存使用量是恒定的,而芹菜中的内存使用量不是恒定的。这确实有助于内存泄漏。正如旁注,如果超出限制,这不会杀死正在运行的任务,而是会在任务完成后杀死工作人员。