大促或压测时 Nginx 突然开始成片 502/504,错误日志满屏 Too many open files,根因几乎都是文件描述符(FD)上限太小——Docker 默认只有 1024,并发一上来就被锁死。把上限调大到 65535,再配合重试机制,基本能稳住。
一、现象:高并发下 502/504 突增
平时好好的,一旦并发冲到两三千就开始大面积 502,Nginx 的 error.log 里反复出现:
2026/08/15 21:03:11 [alert] 12#12: *1024 open() "/var/www/..." failed (24: Too many open files)
每个 TCP 连接、每个被代理的后端 socket 都要占一个 FD。1024 的上限在大并发下几秒就被吃光,新连接直接被拒,表现就是雪崩式 502。
二、先看当前的 FD 上限
进到 Nginx 进程里确认限制有没有生效:
docker exec -it my-nginx sh -c "cat /proc/\$(pidof nginx | awk '{print \$1}')/limits | grep 'open files'"
# 期望看到:Max open files 65535 65535 files
如果还是 1024 1024,说明容器默认 ulimit 没改,后面怎么配 Nginx 都没用。
并发 2000 即崩
错误率 15%
峰值 QPS 3500
错误率 0.02%
三、Docker 环境:–ulimit 调大
最直接的办法是启动时把容器 FD 上限拉高:
docker run -d --name my-nginx \
--ulimit nofile=65535:65535 \
-p 80:80 nginx:alpine
用 Compose 的话在 service 下加:
services:
nginx:
image: nginx:alpine
ulimits:
nofile:
soft: 65535
hard: 65535
四、裸机 / Nginx 配置:rlimit 与连接数
容器外,还要在 nginx.conf 的 events 块里同步调高 worker 自身的上限:
worker_rlimit_nofile 65535;
events {
worker_connections 10240;
}
注意 worker_connections 不能超过系统 ulimit,否则 Nginx 起不来。云服务器裸机还要看 /etc/security/limits.conf 里 nginx 用户的 nofile 限制。
五、开启 proxy_next_upstream 自动重试
即使后端偶发故障,也让 Nginx 自动换一个上游重试,用户基本无感:
proxy_next_upstream error timeout http_502 http_504;
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
六、上线前用压测验证是否真稳了
改完配置别凭感觉,直接压一遍看 FD 还够不够。用 wrk 打 3000 并发持续一分钟:
wrk -t4 -c3000 -d60s http://你的域名/
压测同时另开一个窗口盯 Nginx 的 FD 占用,确认峰值下离上限还有余量:
watch -n1 "ls /proc/\$(cat /run/nginx.pid)/fd | wc -l"
如果压到目标并发 FD 占用稳定在几万、错误率接近 0,说明调优到位;要是 FD 数字顶到上限就掉错误,说明 --ulimit 或 worker_rlimit_nofile 还没真生效,回去重查容器重建和配置 reload 有没有漏。
生产环境建议把 Nginx 的 stub_status 打开,长期盯活跃连接数和请求速率,能在 FD 快被吃满之前提前告警,而不是等雪崩了才反应。配置里加一段 location /nginx_status { stub_status on; allow 127.0.0.1; deny all; },再用 curl 127.0.0.1/nginx_status 就能看到实时连接分布。
踩坑实录
一次大促前压测,并发到 2000 就大面积 502,Nginx 日志满屏 “Too many open files”。我第一反应是加 proxy_next_upstream error timeout http_502;,以为重试能扛住。结果重启后撑不过两分钟又崩。进容器 cat /proc/self/limits | grep "open files" 一看,Max open files 还是 1024。原来容器默认 ulimit 根本没动,retry 只是把请求推给已经没有 FD 的后端,纯属治标。加上 --ulimit nofile=65535:65535 后,峰值 QPS 从 800 拉到 3500,错误率从 15% 降到 0.02%。教训:FD 上限是地基,重试只是上层建筑,地基不牢先补地基。
常见问题
Q:改了 ulimit 还是报 Too many open files?
A:八成是 Nginx 的 worker_rlimit_nofile 没跟着改,或 Compose 改了 run 参数却没 docker compose up -d 重建容器。两个值要一起调,且容器内验证过才算数。
Q:worker_connections 设多大合适?
A:一般设 worker_processes × worker_connections 略大于预期并发。单 worker 10240、开 4 个 worker 就是四万多连接上限,足以覆盖绝大多数中小站点。
Q:只调 Nginx 不调系统够吗?
A:Docker 场景下只调 Nginx 配置没用,容器的 ulimit 是父级限制,必须先 --ulimit 放开,Nginx 才能用得上。
高并发下的 Nginx 调优是个系统工程,FD 上限只是第一道关。如果你在压测或上线时还遇到别的瓶颈,欢迎到 fenij.com 留言,一起把这套调优清单补齐。