我有一个巨大的芹菜任务基本上是这样的:
@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()会显示相对恒定的内存量。
当在芹菜中运行时,print_memory_usage()显示内存量不断增加,一直持续到该进程被终止(我使用Heroku并且内存限制为1GB,但其他主机也存在类似的问题。)内存泄漏似乎与chunk_size相对应;如果我增加chunk_size,每次打印的内存消耗会增加。这似乎表明celery正在记录查询本身,或者我的堆栈中的其他东西。
芹菜会在其他地方记录查询吗?
其他说明:
答案 0 :(得分:0)
答案 1 :(得分:0)
您可以使用--autoscale n,0选项运行worker。如果池的最小数量为0,则芹菜将杀死未使用的工人并释放内存。
但这不是一个好的解决方案。
django的收集器使用了大量内存 - 在删除它之前收集所有相关对象并首先删除它们。您可以在模型字段上将on_delete设置为SET_NULL。
另一种可能的解决方案是删除具有限制的对象,例如每小时一些对象。这将降低内存使用率。
Django没有raw_delete。你可以使用原始的sql。
答案 2 :(得分:0)
有点死板,但这可以在将来对人们有所帮助。尽管最好的解决方案应该是跟踪问题的根源,但是有时这是不可能的,因为问题的根源不在我们的控制范围之内。在这种情况下,您可以在生成Celery worker进程时使用--max-memory-per-child选项。
答案 3 :(得分:0)
事实证明,这与芹菜没有任何关系。相反,是新的遗物记录器消耗了所有内存。尽管将DEBUG设置为False,它仍将每个SQL语句存储在内存中,以准备将其发送到日志服务器。我不知道它是否仍会以这种方式运行,但是直到任务完全完成后,它才会刷新内存。
解决方法是对每个ID块使用子任务,以删除有限数量的项目。
作为管理命令运行时这不是问题的原因是新文物的记录器未集成到命令框架中。
提出的其他解决方案试图减少分块操作的开销,这对O(N)缩放问题没有帮助,或者如果超出内存限制,则迫使celery任务失败(该功能没有当时存在,但最终可能会进行无限次重试。)