Gunicorn+Nginx报'Resource temporarily unavailable'及Worker挂死调试求助
问题分析与解决方案
环境与问题概述
- 部署架构:Beanstalk Docker环境,采用gunicorn + supervisor + nginx部署Django应用
- 实例规格:c6a.large,单实例负载约1700请求/分钟
- 当前问题:
- supervisor显示gunicorn处于运行状态,但所有请求返回Nginx 502错误
- 无流量时gunicorn进程也无法自行恢复,期望supervisor能自动重启无法响应的gunicorn进程
- Nginx错误日志核心提示:
connect() to unix:/run/django_app.sock failed (11: Resource temporarily unavailable)
Nginx配置
server_tokens off; upstream wsgi_server { # fail_timeout=0 means we always retry an upstream even if it failed # to return a good HTTP response (in case the Unicorn master nukes a # single worker for timing out). server unix:/run/django_app.sock fail_timeout=0; } server { location / { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Protocol $http_x_forwarded_proto; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 60s; proxy_read_timeout 60s; proxy_pass http://wsgi_server; } }
一、解决502错误与supervisor自动重启配置
1. 502错误根因定位
日志里的Resource temporarily unavailable,大概率是两种情况:
- gunicorn所有worker进程挂死/阻塞,无法处理新请求
- Unix Socket的监听队列被占满,新请求无法进入
supervisor只监控进程是否存活,不会检测进程是否能正常响应,所以会显示gunicorn运行但实际无服务能力。
2. 调整gunicorn配置
针对高负载和worker阻塞问题,优化参数:
- worker数量:c6a.large是2核4G,设置
workers = 2*CPU核心数+1(即5个),匹配硬件资源 - 自动重启机制:添加
max_requests=1000和max_requests_jitter=200,让worker处理一定请求后自动重启,避免内存泄漏或长期阻塞 - 超时控制:设置
timeout=30(比Nginx的proxy_read_timeout短10秒),让gunicorn主动杀死超时worker并重建
示例启动命令:
gunicorn --workers 5 --worker-connections 2000 --timeout 30 --max-requests 1000 --max-requests-jitter 200 --bind unix:/run/django_app.sock your_project.wsgi:application
3. 配置supervisor的智能监控
默认supervisor只看进程是否存在,需要增强监控逻辑:
- 开启自动重启:在supervisor配置中添加
autorestart=true,进程异常退出时自动重启 - 延迟判定运行状态:设置
startsecs=5,避免进程刚启动就被误判为正常 - 记录日志:配置
stdout_logfile和stderr_logfile,留存gunicorn运行日志便于排查 - 自定义健康检查:写个简单脚本定期请求Django的健康接口(比如
/health),连续失败就调用supervisorctl restart gunicorn,用cron或supervisor的eventlistener定期执行
示例supervisor配置片段:
[program:gunicorn] command=/path/to/gunicorn --workers 5 --worker-connections 2000 --timeout 30 --max-requests 1000 --max-requests-jitter 200 --bind unix:/run/django_app.sock your_project.wsgi:application directory=/path/to/your/project user=www-data autostart=true autorestart=true startsecs=5 stdout_logfile=/var/log/gunicorn_stdout.log stderr_logfile=/var/log/gunicorn_stderr.log
4. 优化Nginx的Socket配置
- 增大Socket监听队列:在upstream中添加
backlog=8192,避免高负载下队列溢出 - 修正Socket权限:确保gunicorn和Nginx运行用户属于同一组,或在gunicorn启动参数中加
--chmod=770,保证Nginx能读写Socket
修改后的upstream配置:
upstream wsgi_server { server unix:/run/django_app.sock fail_timeout=0 backlog=8192; }
二、调试挂死的gunicorn worker
1. 开启gunicorn详细日志
启动时添加--log-level debug,或在配置文件中设置loglevel=debug,记录worker的请求处理细节、异常栈信息。
2. 用gdb分析进程调用栈
- 找到挂死的worker PID:
ps aux | grep gunicorn(子进程是worker,主进程是master) - 附加进程:
gdb /path/to/gunicorn <worker_pid> - 查看调用栈:
thread apply all bt,直接定位worker阻塞的代码位置(比如数据库查询、IO操作、死循环)
3. 使用Python追踪工具
- trace模块:实时追踪进程执行代码:
python -m trace -t -p <worker_pid>,找到阻塞的代码行 - py-spy:安装后执行
py-spy top --pid <worker_pid>,可视化显示进程CPU使用和函数调用占比,快速定位性能瓶颈
4. 检查系统资源
- 内存:
free -h,确认是否内存耗尽导致worker被OOM杀死或阻塞 - 文件句柄:
lsof -p <worker_pid>,检查是否存在未关闭的数据库连接、文件句柄泄漏 - CPU负载:
top -p <worker_pid>,看worker是CPU密集型阻塞还是完全无响应
5. 启用Django请求日志
在settings.py中配置详细请求日志,记录每个请求的处理时间、视图函数、异常信息:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': {'class': 'logging.StreamHandler'}, }, 'loggers': { 'django.request': { 'handlers': ['console'], 'level': 'DEBUG', 'propagate': False, }, }, }
内容的提问来源于stack exchange,提问作者pratik
相关产品推荐
相关产品推荐

