django+celery 模型简单查询卡死的诡异问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
piaochen0
V2EX    Python

django+celery 模型简单查询卡死的诡异问题

  •  
  •   piaochen0 2022-01-16 19:44:59 +08:00 3860 次点击
    这是一个创建于 1430 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目是 django 使用 celery 做一些异步任务执行。 目前发现部署后,django view 中调用 celery 异步执行任务时,遇到一个诡异的问题 方法中的一条模型查询语句,在该异步方法被执行一定次数后会直接卡死。
    例如 Person.objects.get(id=1)
    执行到这一句后,后续语句就不会执行了。几十分钟后仍然不会执行。
    也没有任何报错。 数据库表里面肯定有这条数据,而且只有一条数据。 使用 Person.objects.filter(id=1).first()的方式,也是同样的问题。

    但是我改成直接用 django.db.connections 执行 sql 语句去查询结果,就没这个问题。

    目前发现异步任务方法大概被执行一定数量范围后,就会触发卡死的问题。 而且在这个次数范围内必现。

    当次执行卡死后,再次执行该异步任务,大概率就不会卡死了。

    不知道有没有其他小伙伴遇到这么诡异的问题的,或者有没有原因的可能思路。
    django 版本用的是 2.1.5
    celery 版本是 4.4.2
    感激不尽。

    第 1 条附言    2022-02-14 22:43:27 +08:00
    感谢各位老哥的赐教
    经过摸索,算是把问题全搞明白了
    卡死的问题是数据库连接池全部被占用,ORM 查询的时候,一直在等待连接
    使用 8 楼老哥的方法发现没有效果,每次执行 celery Task 后,发现 mysql 的连接数还在涨的很厉害
    今天偶然看到这段代码
    from django.db import connections
    # 每一个线程都有专属的 connections ,把本线程名下的所有连接关闭。
    connections.close_all()

    立马在线程里面加了上去,不停运行 Task 测试,发现连接数每次用完都被释放了。
    这个方法只有在线程方法内部使用有效,在线程外无效。

    基本猜测是 celery 的 Task 启动多线程后,线程中使用模型查询后,连接不会被自动释放。
    哪怕在调用这些线程的进程上释放,都没用。(也可能是我没找到方法)
    必须要在线程内部释放。

    希望能给需要的人帮助
    10 条回复    2022-01-20 11:01:53 +08:00
    LemonK
        1
    LemonK  
       2022-01-16 20:17:05 +08:00
    mysql ?排查一下有没有其他线程共享同一个 DB 连接且事务未关闭。
    piaochen0
        2
    piaochen0  
    OP
       2022-01-16 20:55:49 +08:00
    @LemonK 是的,mysql 。
    当时运行的场景其实是起了好多线程来执行同一个方法,所有的线程都会卡死在那一行。都没有使用事务。
    后来使用单线程来跑,本来以为应该没问题了,但是跑着跑着,也出现了同样的问题。
    当时也没有其他异步任务在执行。
    darkengine
        3
    darkengine  
       2022-01-16 21:07:47 +08:00   1
    看下 mysql 日志是不是连接池满了
    zachlhb
        4
    zachlhb  
       2022-01-17 08:13:04 +08:00 via iPhone
    有没有用线程?用线程要在每个线程执行完手动关闭数据库连接,否则连接数会爆掉
    kidblg
        5
    kidblg  
       2022-01-17 09:41:14 +08:00
    hscxrzs
        6
    hscxrzs  
       2022-01-17 09:49:52 +08:00
    如果有可以复现的最小代码集就好了
    ibuler
        7
    ibuler  
       2022-01-17 10:53:52 +08:00
    @kidblg 的思路是对的,如果 celery 使用了线程模型,使用完数据库后应该手动关闭连接,这些动作如果在 view 中不用处理,django 自己操作的。

    ```
    # from django.db import close_old_connections 点进去

    # Register an event to reset transaction state and close connections past
    # their lifetime.
    def close_old_connections(**kwargs):
    for conn in connections.all():
    conn.close_if_unusable_or_obsolete()

    signals.request_started.connect(close_old_connections)
    signals.request_finished.connect(close_old_connections)

    ```

    所以在 celery 中,用到的查询,都应该手动执行 close_old_connections ,如果是 celery 是 process 模型就不用处理了
    ibuler
        8
    ibuler  
       2022-01-17 11:04:11 +08:00
    也可以通过信号机制来处理,任务执行前,执行后做同样的动作,这样可能更优雅,其他开发人员,不需要再去处理连接的事情

    ```
    # ops/signal_handlers.py
    from django.db import close_old_connections
    from celery.signals import task_prerun, task_postrun

    @task_prerun.connect()
    def on_celery_task_pre_run(task_id='', **kwargs):
    # 关闭之前的数据库连接
    close_old_connections()


    @task_postrun.connect()
    def on_celery_task_post_run(**kwargs):
    close_old_connections()


    # ops/apps.py app 中导入信号处理器

    class OpsConfig(AppConfig):
    name = 'ops'

    def ready(self):
    from . import signal_handlers
    super().ready()

    ```
    leven87
        9
    leven87  
       2022-01-18 14:58:44 +08:00
    用 pgsql 想复现,但是没发现有问题
    piaochen0
        10
    piaochen0  
    OP
       2022-01-20 11:01:53 +08:00
    @ibuler 我在 celery 中加了这段逻辑,log 日志看也执行了,但是每次运行异步任务后,查看 mysql 的 Max_used_connections ,还在不停的涨。不知道什么原因?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5173 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 05:59 PVG 13:59 LAX 21:59 JFK 00:59
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86