Nginx的requests per second上不去,多半是这几个配置拖了后腿

2026-09-30 17:16 1005 次浏览

一台机器上线之前压了一遍,4核8G,Nginx反向代理后端接口,requests per second只有四百出头。top一看CPU用了不到35%,内存也宽裕,网络带宽更是没跑满。硬件没到极限,软件也没报错,数字就是上不去。这种卡在半路的状态最让人难受,因为不知道该往哪个方向调。

吞吐上不去但资源有富余,问题通常不在Nginx本身,而在它和操作系统之间的那层边界上。连接建立的速度、文件描述符的数量、日志写盘的节奏,这几处任意一个卡住,requests per second就顶不上去。

文件描述符和连接队列,先看这两个硬限制

Nginx处理一个连接就要占一个文件描述符。系统默认的ulimit -n常常是1024,意味着同时最多一千个连接,再多就报too many open files。压测把并发加到五百以上,如果ulimit没放开,后面的连接直接建不起来,requests per second自然卡住。

改法分两处。系统层面在/etc/security/limits.conf里把nofile设到65535,Nginx配置里worker_rlimit_nofile也写同样的值。两个都要改,只改一个不生效。

连接队列是另一个容易漏的点。TCP三次握手完成之后,连接会先进accept队列等Nginx来取。这个队列的长度由net.core.somaxconn控制,老内核默认128。高并发下队列满了,新连接会被丢弃或者触发重传,客户端看到的就是超时。net.ipv4.tcp_max_syn_backlog管的是半连接队列,SYN flood或者连接建立特别密集时同样会满。

  • somaxconn建议设到65535,配合Nginx的listen backlog参数一起改
  • tcp_max_syn_backlog同样设到65535,注意和somaxconn保持同一量级

这两个参数改完要sysctl -p生效,重启Nginx之后重新压测,观察连接建立失败的比例有没有下降。

access_log的写盘方式,对吞吐影响比想象中大

这条是我踩过的坑。默认情况下Nginx每处理一个请求就往access_log写一行,而且是同步写。requests per second到几千的量级,日志写入会变成实打实的瓶颈,磁盘IO被日志占满,处理请求反而慢了。

解法有两个方向。一是把access_log的缓冲打开,用buffer=32k flush=5s这样的参数,让Nginx先在内存里攒一批再落盘。二是把日志格式精简,去掉不需要的字段,每行短了,写盘量自然下来。

缓冲的代价是日志会有延迟,flush间隔内如果进程崩了,这部分日志会丢。对大多数业务站点来说这个代价可以接受,对审计要求高的场景就得权衡。我一般会先开缓冲压一轮,看requests per second提升多少,再决定值不值得承担这点日志延迟。

如果后端本身响应慢,日志再优化也没用。先用request_time确认一下单个请求的处理耗时,如果普遍在100毫秒以上,那瓶颈在后端,不在Nginx。

反向代理场景下,keepalive和超时怎么配

Nginx到上游服务器的连接默认是短连接,每个请求都要重新建一次TCP。上游如果在内网,握手开销还能忍;上游跨机房,每次握手就是几十毫秒的延迟,requests per second直接受影响。

在upstream块里加keepalive参数,配合proxy_http_version 1.1和proxy_set_header Connection "",让Nginx和上游之间保持长连接。keepalive的值设成上游服务器数量的两倍左右比较稳妥,设太大反而占内存。

超时参数要设短。proxy_connect_timeout默认60秒,太长。上游如果挂了,Nginx会一直等,后面排队的请求全被拖住。设成5到10秒,快速失败比慢慢等好。proxy_read_timeout同理,按后端正常响应时间的两三倍来定。

还有个细节是proxy_buffering。打开之后Nginx会把上游的响应先缓存到内存或磁盘再发给客户端,客户端网速慢不会反向拖住上游连接。默认是开的,但有些场景会被手动关掉,关掉之后慢客户端会占着上游连接不放,吞吐掉得很快。

调完这一轮,重新跑压测和第一次的数字对比。如果requests per second翻倍了,说明改对了方向。如果只涨了一点点,回去看是不是后端或者磁盘还有别的瓶颈。

机器本身的规格也要跟得上。Nginx反向代理吃的是CPU单核性能和内存带宽,核心数多但主频低的机器,单请求处理未必快。香港裸机云 IV 是E5-2690配32G内存、20M带宽,月付124美元,适合中小流量的代理和静态分发场景,先把参数调透,再考虑要不要加配置。