最近把一台跑了两年的反代机器重新梳理了一遍。配置本身没有大改,主要是把一些凭感觉设置的值换成了有数据支撑的值。下面几条结论来自压测和线上观察,环境是 Debian 12、Nginx 1.22、上游为本地 Node 服务。

1. proxy_buffering 不是越大越好

默认配置下,Nginx 会尽量把上游响应缓冲到磁盘或内存。对于小文件接口,这没有问题;但对于流式返回的接口,过大的缓冲区会让首字节时间明显变长。

我的做法是按路径区分:普通接口保留默认缓冲,流式接口单独关掉:

location /api/stream/ {
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 3600s;
    proxy_pass http://127.0.0.1:3000;
}

改完之后,流式接口的首字节能稳定在几十毫秒,长连接也不会被过早回收。

2. 上游长连接需要显式配置

很多人只设置了 keepalive,却忘了在 location 里把 HTTP 版本改成 1.1。两个条件缺一不可:

upstream app_backend {
    server 127.0.0.1:3000;
    keepalive 32;
}

location / {
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_pass http://app_backend;
}

注意 Connection "" 这一行。如果照抄网上的配置写成 Connection close,长连接会被立刻关掉,等于白配。

3. TLS 会话复用的收益被低估了

在默认的 ssl_session_cache off 下,每个新连接都要完整握手。开启共享缓存之后,重复访问的握手开销下降非常明显:

ssl_session_cache shared:SSL:20m;
ssl_session_timeout 1d;
ssl_session_tickets off;

我把 ticket 关掉,是因为在多机部署下 ticket key 不同步会带来额外的排查成本。单机场景可以保留。

4. 日志写入也会成为瓶颈

访问日志同步写盘在高并发下会拖慢响应。把缓冲打开,并限制单个日志文件的大小:

access_log /var/log/nginx/access.log combined buffer=64k flush=5s;

配合 logrotate 做按天切分,基本就不会再出现磁盘 I/O 抖动。

最后

调优这件事没有通用答案。先把观测做起来,知道瓶颈在哪里,再动配置。盲目复制一份「高性能配置」,往往只是把问题挪到了另一个地方。