Django+Celery使用Eventlet/Gevent池的ORM问题及猴子补丁验证
我当前运行一个将工作负载卸载至Celery后台Worker的Django项目。对于CPU密集型任务,采用fork池运行效果良好,启动命令如下:
celery -A myApp worker -l INFO -E -n worker --concurrency=<CPU-core-count>
随着API爬取为主的长时任务增多,我计划创建单独队列,使用Eventlet(或Gevent)池实现更好的扩展。
Eventlet Worker测试
我通过以下命令启动Eventlet Worker,测试阶段运行正常:
celery -A myApp worker -l INFO -E -n worker --concurrency=100 -p eventlet
我测试了两组Eventlet版本组合:
组合1:Celery 5.1.0 + Eventlet 0.33
该组合下,Worker执行API请求+数据库查询时,出现社区常见错误:DatabaseWrapper objects created in a thread can only be used in that same thread
组合2:Celery 5.2.7 + Eventlet 0.33
根据社区建议升级Celery至最新版本后,Worker运行正常,未出现上述线程相关错误。
Gevent Worker测试
为做对比,我也测试了Gevent,启动命令如下:
celery -A myApp worker -l INFO -E -n worker --concurrency=100 -p gevent
搭配Celery 5.1.0/5.2.7与Gevent 21.8.0时,因Django ORM对异步查询支持不佳,偶尔会出现SynchronousOnlyOperation错误,且无固定复现规律,仅在任务量超出Celery并发数且执行ORM查询时随机触发。
当前选型与待明确问题
目前我暂不准备升级至Django 4.1,也不愿通过async_to_sync包装ORM查询增加任务复杂度,因此倾向于使用测试表现正常的Eventlet(Celery 5.2.7 + Eventlet 0.33)组合,但部署到生产前需明确以下问题:
- Eventlet与Django ORM的协作机制(ORM在异步环境表现不佳的底层原因)
- 高并发下Eventlet是否会像Gevent一样触发
SynchronousOnlyOperation异常(暂未找到相关社区反馈) - 升级Celery后Eventlet的线程错误消失的原因,及如何确保极端场景下不会复现
- 如何验证Eventlet是否在后台对数据库连接器等Django关键库进行猴子补丁
测试总结
Gevent+Celery配置(执行Django ORM查询与API请求)
启动命令:
celery -A myApp worker -l INFO -E -n worker --concurrency=100 -p gevent
依赖版本:
- Celery 5.1.0 / Celery 5.2.7
- gevent 21.8.0
问题:偶发SynchronousOnlyOperation异常,由异步环境执行查询导致。
Eventlet+Celery配置(执行Django ORM查询与API请求)
组合1:Celery 5.1.0 + Eventlet 0.33
启动命令:
celery -A myApp worker -l INFO -E -n worker --concurrency=100 -p eventlet
问题:查询失败,触发错误:DatabaseWrapper objects created in a thread can only be used in that same thread
组合2:Celery 5.2.7 + Eventlet 0.33
启动命令:
celery -A myApp worker -l INFO -E -n worker --concurrency=100 -p eventlet
状态:测试阶段未发现问题,但无法确保所有场景下稳定运行
内容的提问来源于stack exchange,提问作者Ruben Rehn

