Gunicorn worker 配置直接决定 Django 并发模型,IO 密集场景推荐 gevent 协程模式,CPU 密集场景推荐 sync 多进程模式。错误配置会导致 CPU 满载但吞吐量低,或内存溢出进程震荡。
先说结论:生产环境必须禁用 Django 自带服务器,根据业务 IO 或 CPU 密集程度选择 worker 类,数量需结合 CPU 核数与内存限制调整。
- 适合:IO 密集型 Web 服务或 CPU 密集型计算任务
- 重点看:worker_class 选择与 workers 数量公式匹配
- 别忽略:多进程模式下全局变量不共享及线程安全问题
命令速用版
默认 sync 模式启动 4 个 worker:
gunicorn `--workers` 4 myapp:wsgi -b 127.0.0.1:8000
IO 密集场景启用 gevent 模式:
gunicorn `--worker-class` gevent `--workers` 4 myapp:wsgi -b 127.0.0.1:8000
为什么会这样
不同 worker 类对应不同的并发处理模型,sync 模式每个进程同时只能处理一个请求,gevent 模式通过协程可在单个进程内并发处理多个请求。Django 默认同步阻塞,不靠多进程或协程无法利用多核 CPU 或应对高并发 IO 等待。
分步处理
1. 确定 worker 数量:通用建议设为 2× CPU 核数 + 1,但 IO 密集场景下 gevent 模式 4 核机器设 8~12 个 worker 更合理,过多会导致内存争抢和频繁 GC。
2. 选择 worker 类:CPU 均衡型应用用默认 sync,大量 HTTP 外调或数据库长连接等 IO 密集场景用 gevent,需先 pip install gevent。
3. 配置预加载:开启`--preload` 避免每个 worker 单独导入 Django 触发重复初始化或 DB 连接泄漏。
4. 代码层适配:使用 gevent 必须在代码最开头加 from gevent import monkey; monkey.patch_all(),漏掉会导致 HTTPS 请求卡死。
怎么验证是否生效
启动时加`--log-level` info 确认实际加载的 worker 数,有时配置写了 4 个但因端口占用只起了 1 个。使用 apache ab 等工具测试并发,观察 Failed requests 是否为零,CPU 峰值是否合理。
常见坑
1. 全局变量失效:多 Worker 进程拥有独立内存空间,全局字典修改无法在不同 Worker 间共享,应改用缓存系统。
2. 线程不安全:避免用`--threads` 混合多线程,Django 的 ORM 和中间件大多非线程安全,线程数大于 1 容易出数据库锁定错误。
3. 兼容性问题:gevent 不兼容所有同步库,某些 MySQL 驱动需换 PyMySQL,eventlet 社区维护弱且 Python 3.11+ 兼容性差。
常见问题
默认 worker 数量是多少?
默认只启 1 个 worker 进程,哪怕机器有 8 核也只压着一个 CPU 跑,必须显式设-w 参数。
gevent 一定能提升性能吗?
不一定,代码里有大量 CPU 密集操作时 gevent 无济于事,反而因协程调度增加开销,这时用多进程更稳。
为什么 CPU 占用率会 100%?
主因是 worker 数量或类型与 I/O 密集型负载不匹配,超设致内存不足、频繁 GC 及 OOM 震荡。
参考来源
- Python Web 服务器怎么选_Gunicorn/uWSGI/Waitress 性能对比
- django gunicorn 各 worker class 简单性能测试-CSDN 博客
- 为什么 Python Web 部署后 CPU 占用率过高_通过 Gunicorn 配置多进程模型
- Django gunicorn 怎么跑_多 worker 进程与 gevent 协程提高并发
- 关于 django 中几个重要的 gunicorn worker 的配置
- Django Gunicorn 多 Worker 模式下全局字典值异常的原理与解决方案