Django-Q旧线程未被销毁导致CPU占用率升至100%故障求助
Django-Q线程不回收导致CPU占满故障排查与解决
你提供的systemd服务配置存在笔误,Service段的启动命令行需要修正为:
ExecStart=/home/ubuntu/.virtualenvs/env/bin/python manage.py qcluster修正配置后可按以下步骤定位和解决故障。
故障定位步骤
- 检查Django-Q配置:导出项目settings.py中的
Q_CLUSTER配置项,重点确认recycle、timeout、retry、worker_count参数是否配置合理。其中recycle参数控制单个worker处理多少任务后自动重启回收资源,未配置或配置值过高会导致资源无法正常释放。 - 排查业务任务逻辑:在
Q_CLUSTER配置中添加'log_level': 'DEBUG'开启 debug 日志,重启qcluster后观察日志中是否有任务卡住、未捕获异常、长时间运行不返回的情况。使用py-spy top --pid [qcluster主进程PID]工具可以直接查看占用CPU的代码栈,快速定位是业务代码问题还是框架本身问题。 - 确认依赖环境兼容性:检查虚拟环境中Django、Django-Q、协程库(gevent/eventlet等)的版本是否匹配,协程和线程混用极容易出现资源无法回收的问题。
故障解决方法
- 调整Django-Q配置:
- 显式添加
recycle参数,建议值为500~1000,即单个worker处理对应数量任务后自动重启,强制回收线程资源 - 合理设置
timeout参数,值略大于单任务最大执行时长即可,超时任务会被强制终止,避免一直占用线程 - CPU密集型场景下
worker_count不要超过服务器CPU核心数,减少不必要的线程上下文切换开销
- 显式添加
- 优化业务任务代码:
- 所有任务函数添加全量异常捕获,确保任务无论执行成功失败都能正常退出
- 任务中使用的数据库连接、文件句柄、网络连接等资源执行完后主动关闭,避免资源泄漏导致线程无法销毁
- 不要在任务内部启动未托管的子线程/子进程
- 框架与服务层面修复:
- 将Django-Q升级到最新稳定版,旧版本存在已知的线程回收异常bug
- 避免协程库和Django-Q默认线程模式混用,要么使用原生协程模式要么完全关闭协程
- 临时兜底可在systemd服务的Service段添加
RuntimeMaxSec=86400配置,设置服务每24小时自动重启一次,避免CPU占用缓慢涨满影响业务
内容的提问来源于stack exchange,提问作者user7804233
相关产品推荐
相关产品推荐

