我们的 Nginx 反向代理从 94,706 QPS 跌到 6,301,慢了 15 倍,却没有一条错误日志。OpenResty XRay 火焰图揪出两个根因:upstream 配置块漏掉了 keepalive 指令,导致每个请求都新建一条 TCP 连接;外加一个被遗忘的 -O0 调试编译选项,又悄悄吃掉 10% 性能。两处修复后,性能完全恢复。

本文按火焰图逐张复盘完整的诊断过程。

Nginx 反向代理慢 15 倍,日志却零报错

在任何成熟的工程团队中,性能验收通常是一个确定性的、流程化的环节。尤其对于网关这类基础组件,其架构(Client → OpenResty Gateway → Upstream)已经是一个被反复验证的成熟模式。理论上,一个仅做轻量级转发的网关,其性能开销应是可预测且极低的。

然而,在对新版网关进行基准压测时,我们遭遇了惊人的性能衰退:

  • 上游服务基线 (直连压测): 94,706 QPS
  • 新版网关 (反向代理): 6,301 QPS

性能凭空蒸发了 93%。一个简单的反向代理,竟然造成了近 15 倍的性能差距。系统表面上风平浪静:没有错误日志,配置也符合常规认知,问题显然已经下沉到我们日常观测的视野之外。

火焰图暴露连接风暴:upstream keepalive 缺失

我们使用 OpenResty XRay 对网关进行 CPU 性能分析,运行 lj-c-on-cpu 工具生成火焰图:

CPU 火焰图被两大块异常宽阔的平台所占据:connect()close() 系统调用。

在高性能网络服务中,这两者本应是几乎不可见的“背景噪音”。它们的异常凸显,指向一个致命的问题:上游连接没有被复用。每一个进来的请求,都在触发一次全新的 TCP 握手和挥手。在高并发场景下,这无异于一场“连接风暴”,内核将大量时间消耗在创建和销毁连接上,而非真正的数据处理。

通过 OpenResty XRay 提供的完整调用栈,我们迅速锁定了问题根源:

  • Connect 路径: ngx_http_proxy_handlerngx_http_upstream_connectconnect()
  • Close 路径: ngx_http_upstream_finalize_requestngx_close_connectionclose()

诊断清晰明了:我们的 upstream 配置块中,遗漏了 keepalive 指令。这是一个看似微小、却足以在生产环境中引发雪崩的配置疏忽。

我们立即启用了上游 keepalive。效果立竿见影:性能提升:从 6,301 QPS 到 21,923 QPS,提升 3.48 倍!

启用 upstream keepalive 前后的 QPS 柱状对比图:从 6,301 提升至 21,923

connect()close() 的尖峰已然消失。第一个性能黑洞被填补,但故事还未结束。

剩下的 10% 差距:基线对比指向编译器

尽管性能大幅回升,但资深的工程师直觉告诉我们,事情没那么简单。我们将当前版本的性能(21,923 QPS)与上一个稳定版本(24,115 QPS)进行对比,发现仍然存在约 10% 的性能差距

这 10% 的差距从何而来?它虽然不像 15 倍的鸿沟那样触目惊心,但对于追求极致性能的基础设施而言,任何不明不白的衰退都是不可接受的。

  • 当前版本的火焰图“更深”:调用栈的层级明显多于稳定版本。
  • 特定函数调用增多:例如,ngx_http_gunzip_body_filter 这样的函数在调用链中频繁出现,而在稳定版本中则几乎不可见。

查看 ngx_http_gunzip_body_filter 的代码:

static ngx_int_t
ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    int                     rc;
    ngx_uint_t              flush;
    ngx_chain_t            *cl;
    ngx_http_gunzip_ctx_t  *ctx;

    ctx = ngx_http_get_module_ctx(r, ngx_http_gunzip_filter_module);

    if (ctx == NULL || ctx->done) {
        return ngx_http_next_body_filter(r, in);
    }
}

理论上,Nginx/OpenResty 的 filter 链大量使用了尾调用(tail-call),在优化编译下,这些调用应该被编译器“拉平”,几乎没有额外开销。而当前版本的火焰图形态,恰恰暗示着编译器优化可能失效了

-O0 调试编译如何吃掉我们 10% 的性能

顺着这条线索,我们核查了两个版本的构建脚本,发现:

当前开发版本使用了 -O0 编译选项。

原因是在开发过程中,为了方便调试某个问题,临时将编译优化关闭了。但在功能开发完成后,忘记恢复为优化编译选项

-O0 意味着:

  1. 函数内联失效 - 小函数调用无法被内联
  2. 尾调用优化失效 - 调用栈变深
  3. 冗余代码未消除 - 更多无用指令
  4. 寄存器使用效率低 - 更多内存访问

这些看似微小的编译器行为差异,累积起来,不多不少,恰好“偷”走了我们 10% 的性能。

我们将编译选项恢复为标准的 -O2,重新构建并部署。

结果显示性能完全恢复,与稳定版本持平。至此,两个性能问题被彻底解决。

15 倍 QPS 差异的工程性复盘

这次从 94K QPS 到 6K QPS 的性能排查,暴露了现代复杂系统中两个深刻的挑战:

  1. “隐形上下文”的漂移:性能不仅由代码逻辑决定,更取决于构建与运行时环境的“隐形上下文”——例如编译选项、内核参数和运行时配置。这些上下文的变化往往在 Code Review 中难以察觉,却能导致灾难性的后果。本次的 keepalive 缺失和 -O0 编译选项就是最好的例证。

  2. 突破观测盲区:为何你需要动态追踪?当问题下沉至内核与编译器层面,传统的 Logs & Metrics 往往保持静默。 本案例证明,面对系统级瓶颈,我们需要的是 OpenResty XRay 这样具备穿透力的工具:

  • 全链路采样:穿透应用层直达内核,快速识别宏观瓶颈(如连接风暴)
  • 异常模式识别:通过火焰图快速识别非预期的 connect/close 路径。
  • 基线对比:定位微观层面的细微差异(如编译器行为)

性能问题往往不是非黑即白的 Bug,而是灰度的效率流失。 在复杂的系统架构中,仅凭经验猜测是低效的。我们需要通过 OpenResty XRay 构建起从应用逻辑到内核调用的完整可观测性,让我们有能力去度量、分析和优化那些隐藏在系统深处的“灰色地带”,从而确保系统的长期稳定与卓越性能。

如果您面对的症状不是吞吐量下降、而是尾部延迟偏高,可以参阅我们的姊妹篇:用 OpenResty XRay 诊断 P99 延迟

常见问题

为什么我的 Nginx 反向代理比直连后端慢这么多?

在本案例中,上游服务直连压测可达 94,706 QPS,经过反向代理却只剩 6,301 QPS。根因是上游连接没有被复用:upstream 配置块缺少 keepalive 指令时,每个请求都会触发完整的 TCP 握手和挥手。启用 upstream keepalive 后,吞吐量立即提升 3.48 倍,达到 21,923 QPS。

如何定位 Nginx 反向代理的 CPU 消耗在哪里?

我们使用 OpenResty XRay 的 lj-c-on-cpu 工具对运行中的网关生成 CPU 火焰图。两块异常宽阔的平台——connect()close() 系统调用——一眼暴露了连接风暴;完整调用栈(ngx_http_proxy_handlerngx_http_upstream_connectconnect())则精确定位到代码路径,全程无需侵入应用。

-O0 编译选项真的会影响 Nginx 性能吗?

会。本案例中 -O0 调试编译实测吃掉了约 10% 的吞吐量(21,923 对比 24,115 QPS)。-O0 会关闭函数内联和尾调用优化,导致调用栈变深、冗余指令增多——在火焰图上表现为频繁出现的 ngx_http_gunzip_body_filter 帧。恢复 -O2 重新编译后,性能完全恢复。

关于 OpenResty XRay

OpenResty XRay 是一款动态追踪产品,它可以自动分析运行中的应用,以解决性能问题、行为问题和安全漏洞,并提供可行的建议。在底层实现上,OpenResty XRay 由我们的 Y 语言驱动,可以在不同环境下支持多种不同的运行时,如 Stap+、eBPF+、GDB 和 ODB。

关于作者

章亦春是开源 OpenResty® 项目创始人兼 OpenResty Inc. 公司 CEO 和创始人。

章亦春(Github ID: agentzh),生于中国江苏,现定居美国湾区。他是中国早期开源技术和文化的倡导者和领军人物,曾供职于多家国际知名的高科技企业,如 Cloudflare、雅虎、阿里巴巴, 是 “边缘计算“、”动态追踪 “和 “机器编程 “的先驱,拥有超过 22 年的编程及 16 年的开源经验。作为拥有超过 4000 万全球域名用户的开源项目的领导者。他基于其 OpenResty® 开源项目打造的高科技企业 OpenResty Inc. 位于美国硅谷中心。其主打的两个产品 OpenResty XRay(利用动态追踪技术的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最适合微服务和分布式流量的全能型网关软件),广受全球众多上市及大型企业青睐。在 OpenResty 以外,章亦春为多个开源项目贡献了累计超过百万行代码,其中包括,Linux 内核、Nginx、LuaJITGDBSystemTapLLVM、Perl 等,并编写过 60 多个开源软件库。

关注我们

如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:

我们的微信公众号

翻译

我们提供了英文版原文和中译版(本文)。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!