技术分享

写了十三年Nginx才敢说:反向代理正在悄悄吃掉你的性能预算

无锡枫泽云创 阅读约 7 分钟

摘要:反向代理并非免费管道,缓冲区落盘、连接池失效、超时层级混乱和头部规则膨胀都在悄悄消耗性能预算。文章主张代理层保持薄,把复杂路由与鉴权上移,并用分项耗时指标让成本显形。

写了十三年Nginx才敢说:反向代理正在悄悄吃掉你的性能预算
写了十三年Nginx才敢说:反向代理正在悄悄吃掉你的性能预算

反向代理几乎是现代 Web 架构的默认配置。一台 Nginx 挡在应用前面,做 TLS 卸载、做静态资源分发、做灰度路由、做限流熔断,看起来天经地义。写了十三年 Nginx 配置之后,我越来越确信一件事:很多人把反向代理当成了免费的午餐,而它其实一直在悄悄从你的性能预算里扣费,只是账单不在 Nginx 那一栏。

先说一个常被忽略的事实。反向代理不是一层透明的管道,它是一个完整的 HTTP 参与者。客户端与 Nginx 建立一条连接,Nginx 再与上游建立另一条连接,中间涉及请求解析、头部重建、缓冲区分配、连接复用判断、超时管理。每一个环节都有成本,问题在于这些成本被分散到了不同的指标里:应用侧的 CPU 看起来正常,Nginx 的 QPS 看起来漂亮,但端到端 P99 就是压不下去。

最典型的浪费来自缓冲区配置。默认的 proxy_buffering 开启后,Nginx 会先把上游响应读进内存缓冲区,再逐步发给客户端。这个设计本意是让上游尽快释放连接,对短响应确实有效。但当响应体达到几 MB 级别,或者上游是流式输出,缓冲区会频繁触发写磁盘临时文件,一次请求可能产生多次磁盘 I/O。你在应用里优化了序列化、压缩了 JSON,结果省下来的那点字节数,全被代理层落盘吃回去了。要么把 proxy_max_temp_file_size 设为零明确禁用落盘,要么针对大响应路径单独关闭 buffering,让数据直通。这不是调优技巧,是止血。

第二个隐形开销是连接管理。上游 keepalive 没配好,Nginx 对每个请求都新建 TCP 连接,三次握手加上可能的 TLS 协商,在高并发下就是成片的 TIME_WAIT 和延迟毛刺。很多人只记得在 upstream 块里加 keepalive 指令,却忘了配套设置 proxy_http_version 1.1 和清空 Connection 头。配置写了,连接池没生效,等于白写。反过来,keepalive 数量开得过大,空闲连接长期占着上游的文件描述符和内存,又会在流量低谷时制造另一种浪费。连接池大小应该跟上游 worker 的并发处理能力对齐,而不是拍脑袋填个整数。

第三个问题更隐蔽:反向代理会放大超时配置的错误。客户端到 Nginx 有一组超时,Nginx 到上游有另一组,两组超时如果缺乏层次,会出现上游还在处理、代理已经断开、客户端收到 504 的情况,而上游继续把活干完,资源白白消耗。更糟的是重试逻辑,proxy_next_upstream 默认在某些错误下会换一台上游重试,对于非幂等请求,这等于把一次写操作变成两次。超时和重试必须一起设计,先明确哪些错误可重试、哪些请求可重试,再谈参数。

还有一个被严重低估的成本是头部处理。现代应用喜欢在请求头里塞东西:追踪 ID、租户标识、灰度标签、认证令牌。Nginx 需要解析、匹配、可能还要改写这些头部。单看一次请求微不足道,但在十万级 QPS 下,正则匹配的 location 和复杂的 map 规则会稳定吃掉一两个核。用精确匹配和前缀匹配能解决的问题,不要交给正则;能在应用层做的路由决策,不要全堆到代理层。代理层应该保持薄,越薄越可预测。

从架构视角看,反向代理的成本本质上是“多一跳”的成本。多一跳意味着多一次排队、多一次序列化边界、多一个故障域。这不是说反向代理不该用,而是说它应该被当作有预算的组件来管理。每增加一条 rewrite 规则、每开一个 lua 脚本、每加一层鉴权,都要问一句:这个能力放在这里,省下的复杂度是否大于它引入的延迟和运维负担。很多团队把 API 网关、鉴权、限流、灰度全部压在 Nginx 上,配置膨胀到几千行,最后没人敢改,性能问题也定位不到根因。

我的观点是:反向代理应该回归它的本职——连接管理、TLS 卸载、基础的负载均衡和静态资源服务。业务路由、复杂鉴权、请求聚合这些事,交给应用框架或者独立的网关层去做,那里的可观测性和测试手段更成熟。代理层的配置应当短到可以一眼看完,长到能覆盖必要的边界防护即可。

具体到落地,有几件事值得立刻检查。一是打开 upstream 的响应时间日志,把代理耗时和上游耗时分开统计,很多性能问题一分开就现形。二是审视 buffering 策略,对流式接口和大响应明确关闭缓冲。三是核对 keepalive 三件套是否配齐,用连接数指标验证而不是靠猜。四是梳理超时与重试的层级关系,确保不会出现上游空转。五是给代理配置做减法,删掉那些没人说得清来历的规则。

性能预算从来不是无限的,它只是被记在了不同的账本上。反向代理不会主动告诉你它花了多少,但延迟曲线会。写了十三年配置,我最大的体会是:把代理层当成本中心来管,而不是当免费基础设施来用,端到端的数字才会诚实。

专业的软件开发服务

立即联系我们,获取免费的方案评估和报价

立即咨询
联系我们:18706176160