Reverse Proxy实战指南:从原理到Nginx配置优化

IT人亚会 工具 阅读 1,138
赞 20 收藏
二维码
手机扫码查看
反馈

优化前:卡得不行

上个月接手一个老项目,前端页面加载动不动就5秒起步,用户反馈“点一下等半天”。我一开始以为是前端打包问题,结果排查一圈发现,真正卡住的是后端 API 响应——但奇怪的是,本地直连后端接口飞快,部署到线上就慢成狗。

Reverse Proxy实战指南:从原理到Nginx配置优化

后来才意识到,问题出在反向代理(Reverse Proxy)配置上。我们用的是 Nginx 作为前端和后端之间的中间层,所有 /api 请求都通过它转发到内网服务。但默认配置几乎没做任何优化,缓冲区小、超时短、连接复用也没开,导致每次请求都要重新握手、等响应、再关闭,慢得离谱。

找到瓶颈了!

我先用 Chrome DevTools 看 Network 面板,发现很多请求的 Waiting (TTFB) 高达 3-4 秒。这明显不是前端代码的问题,而是服务端响应太慢。接着用 curl -w "@format.txt" -o /dev/null -s https://jztheme.com/api/data 测 TTFB,结果本地测 80ms,线上测 3200ms,差距巨大。

然后登录服务器,用 nginx -T 打印当前配置,又用 tcpdump 抓包看 TCP 握手和数据流,发现每次请求都新建连接,而且后端返回大 JSON 时,Nginx 缓冲区满了就频繁写磁盘,I/O 直接拉满。

折腾了半天才发现,原来是我们那个“能跑就行”的 Nginx 配置里,连最基本的 proxy_buffering 都没开,更别说连接池和缓存了。

核心优化方案:三招搞定

试了几种方案,最后靠这三招把性能拉回来了。重点讲前两个,第三个简单带过。

1. 开启代理缓冲 + 调大缓冲区

默认 Nginx 的 proxy_bufferingon,但缓冲区太小(通常 4k 或 8k),一旦后端返回的数据超过这个值,Nginx 就会把多余内容写入临时文件,造成磁盘 I/O。我们的 API 返回经常 100KB+,所以必须调大。

优化前配置:

location /api/ {
    proxy_pass http://backend;
}

优化后:

location /api/ {
    proxy_pass http://backend;
    proxy_buffering on;
    proxy_buffer_size 16k;
    proxy_buffers 8 32k;
    proxy_busy_buffers_size 64k;
    proxy_max_temp_file_size 0;  # 禁用磁盘临时文件
}

这里注意我踩过好几次坑:proxy_max_temp_file_size 0 很关键,不然大响应还是会写磁盘。另外 proxy_busy_buffers_size 要大于 proxy_buffer_size,否则会报错。

2. 启用 keepalive 连接复用

后端服务是 Node.js 写的,每次新连接都要走 TLS 握手(虽然内网没开 HTTPS,但也有 TCP 握手开销)。通过在 upstream 里配置 keepalive,可以让 Nginx 复用后端连接,避免频繁建连。

优化前:

upstream backend {
    server 127.0.0.1:3000;
}

优化后:

upstream backend {
    server 127.0.0.1:3000;
    keepalive 32;  # 保持 32 个空闲连接
}

server {
    location /api/ {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

这里必须加 proxy_http_version 1.1 和清空 Connection 头,否则 keepalive 不生效。亲测有效,QPS 直接翻倍。

3. 简单缓存高频只读接口

有些 GET 接口比如 /api/config 几乎不变,但每天被请求几万次。加个 10 秒缓存,能省下大量后端计算。

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=API_CACHE:10m inactive=10m max_size=1g;

location = /api/config {
    proxy_cache API_CACHE;
    proxy_cache_valid 200 10s;
    proxy_cache_use_stale error timeout updating http_500;
    proxy_pass http://backend;
}

这个方案不是最优的(比如缓存穿透没处理),但最简单,上线后 CPU 使用率直接降了 15%。

优化后:流畅多了

改完配置 reload Nginx 后,立马测效果。前端页面首屏加载从平均 5.2 秒降到 800 毫秒左右,TTFB 从 3200ms 降到 120ms。用户反馈“突然变快了”,其实后端代码一行没动,全靠代理层优化。

还有个意外收获:服务器负载从 70% 降到 30%,晚上再也不用担心突发流量把服务搞崩了。

当然,也不是完美无缺。比如 POST 请求没法缓存,大文件上传还是有点慢(不过那不是本文重点)。但对绝大多数常规 API,这套配置已经够用了。

性能数据对比

为了说服团队,我做了个简单压测(用 ab -n 1000 -c 50):

  • 优化前:平均响应时间 3200ms,失败率 8%
  • 优化后:平均响应时间 110ms,失败率 0.2%

TPS 从 15 提升到 450,提升 30 倍。虽然实际用户场景没这么极端,但足以说明问题。

另外,用 nginx -T 确认配置生效后,我还加了监控,用 Prometheus 抓 nginx_upstream_response_time 指标,确保后续不会退化。

结尾:有坑一起填

以上是我最近一次 Reverse Proxy 性能优化的实战经验。说白了,就是别用默认配置上线,缓冲、连接复用、缓存这三板斧,能解决 90% 的性能问题。

当然,如果你的后端本身慢,光优化代理也没用。但至少别让代理拖后腿。

以上是我踩坑后的总结,希望对你有帮助。有更优的实现方式欢迎评论区交流,比如你们怎么处理 WebSocket 代理的性能?或者有没有用 Envoy 替代 Nginx 的?我正想试试呢。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论