如何限制 django 网站的 redis/celery 任务?

Posted

技术标签:

【中文标题】如何限制 django 网站的 redis/celery 任务?【英文标题】:How to throttle redis/celery tasks for a django web site? 【发布时间】:2021-12-29 01:41:26 【问题描述】:

我有一个 django v3.0.2 站点 (python v3.6.9),我在其中上传图像,处理图像,然后将其显示在网站上。通过处理图像,我创建了一个图像的不同大小,查找和识别面部,识别任何文本并在需要时进行翻译,使用几种不同的算法来计算每个图像与其他图像的相似程度,以及其他图像处理算法。我使用 celery v4.3.0 和 redis v4.0.9 在不同的 celery 任务中在后台进行所有计算。

我遇到的问题是,当我尝试在一个循环中上传和处理超过 4 张图像时,内存不足并且计算开始引发异常。由于内存不足,我的 5 GB 交换空间和 16 GB 内存都用完了,chrome 甚至崩溃了。在我的数据库中,我会记录每个任务的进度以及它是否成功完成。我可以看到许多错误和许多未启动的任务。

如果我将time.sleep(10) 放在上传图像的循环中,并且在为每个图像启动 celery 工作者之后,我可以在同一个循环中上传 60 多张图像,而不会在我的任务日志中出现任何异常、崩溃或错误.

我搜索了一些方法来限制 celery 中的工人,因此我不必使用 sleep,并在 celery 问题论坛中发现可能 celery 没有此功能 Celery rate limiting with multiple workers。我发现这篇文章可能对Celery throttling - setting rate limit for queues有帮助。

在我开始像上面的参考那样自己构建一些东西之前,我想我会问集体意识是否有比time.sleep(10) 更好的(对吗?)方法来扼杀芹菜工人,所以我不会用完内存不足并产生大量任务错误。

这里的代码太多了,所以这里是我在做什么的概述。

admin.py

def save_model(self, request, obj, form, change):
    if form.is_valid():
        if not change:
            files = request.FILES.getlist('storage_file_name')
            for f in files:
                obj = Document()       # model for each image
                # add some data to the model
                obj.save()
                time.sleep(10)
                doc_admin_workflow(<some parameters>)
        else:
            # some different housekeeping on the model fields
            doc_admin_workflow(<some different parameters>)
            super().save_model(request, obj, form, change)

def doc_admin_workflow(<some parameters>):
    if not change:
        # Decide which of the image processing steps to perform. 
        # Each processing step is a celery task of the form task_name.si(params)
        # in a list called 'jobs' ~ 3-5 tasks
        transaction.on_commit(lambda: chain(group(jobs), 
                              change_state_task.si(document_id, 'new')).delay()) 
        time.sleep(10) 
    else:
        # decide what other processing steps (i.e. celery tasks) to perform
        transaction.on_commit(lambda: chain(step_1, step_2, faces_2, ocr_job, 
                              change_state_task.si(document_id, 'ready')).delay())
        time.sleep(10)

上面使用的所有 celery 任务都是自包含的,因为它们不会将数据传递给下一个任务,也不会以任何方式相互交互。他们只是计算和读/写数据库。

此外,这些上传是由网站管理员完成的。与站点交互的用户不会将图像上传到站点,也不会使用图像处理 celery 任务。所以,time.sleep(10) 是一个可能的解决方案,但它似乎是一个巨大的杂物,而且不是很健壮。

谢谢!

【问题讨论】:

【参考方案1】:

请查看此相关帖子的答案:celery redis tasks don't always complete

从我的任务中取出所有的和弦和组,仅仅使用链似乎已经解决了内存不足的问题。现在无需限制 celery 任务,也无需将任何 time.sleep() 语句放入流中。

【讨论】:

以上是关于如何限制 django 网站的 redis/celery 任务?的主要内容,如果未能解决你的问题,请参考以下文章

Python Django Middleware中间件限制IP访问频率及判断搜索引擎爬虫

Django 将页面限制为特定用户

我们如何比较 django 中的请求对象?

如何限制 Django 错误邮件

如何根据用户组更改 Django 模板?

django/celery - 芹菜状态:错误:在时间限制内没有节点回复