Nginx 作为 API 网关:性能故障排查深度实践
场景
在 OpsGlobal,我们经常看到客户将 Nginx 作为微服务前面的 API 网关运行。典型设置包括 Nginx 终止 TLS、将请求路由到上游服务,以及处理速率限制或缓存。最近,我们的一位客户报告说他们的 API 延迟从 50 毫秒飙升至 2 秒以上,并且在业务高峰时段出现间歇性 504 网关超时。
症状
- 响应延迟增加(p95 延迟增加了三倍)
- 当上游在默认超时时间内未能响应时,Nginx 返回 504 错误
- Nginx worker 连接数达到
worker_connections限制 - 上游服务 CPU 使用率高但未饱和
- 没有明显的代码变更或部署事件
诊断
我们首先检查基础知识:
-
检查 Nginx 错误日志
tail -f /var/log/nginx/error.log查找upstream timed out或no live upstreams。 -
检查访问日志中的慢请求 我们在日志格式中启用了
$request_time和$upstream_response_time。配置和查看日志的命令。 -
验证 Nginx 配置:
nginx -t和nginx -T来转储完整配置。 -
测试到上游的连接和计时: 使用
curl -w测量 DNS、连接、TLS、TTFB 和总时间。 -
检查连接池统计:
ss -s查看套接字统计信息,以及netstat -an | grep ESTABLISHED | wc -l。 -
使用
wrk或ab进行负载测试,在受控负载下重现问题。
我们发现 Nginx 配置中 proxy_connect_timeout 和 proxy_read_timeout 设置为默认值(60 秒),但真正的问题是没有正确配置上游 keepalive 连接。upstream 块中没有 keepalive 指令,导致每个请求都进行新的 TCP 连接和 TLS 握手。在高并发下,这增加了大量开销。
使用的命令
以下是我们在诊断和修复过程中使用的关键命令:
检查错误日志
tail -f /var/log/nginx/error.log
检查带有计时信息的访问日志
访问日志格式定义:
log_format timed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
然后查看日志:
tail -f /var/log/nginx/access.log | awk '$10 > 2 {print}'
(假设第 10 个字段是 request_time)
验证配置
nginx -t
nginx -T
Curl 计时
curl -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" https://api.example.com/health
套接字统计
ss -s
ss -tn state established '( dport = :443 or sport = :443 )' | wc -l
使用 wrk 进行负载测试
wrk -t8 -c200 -d30s https://api.example.com/health
实施修复与风险控制
我们做了以下更改:
- 启用上游 keepalive:
upstream backend {
server api1:8080 weight=3;
server api2:8080 weight=2;
keepalive 32;
}
- 调整 Nginx HTTP 设置:
http {
upstream backend {
server api1:8080;
keepalive 32;
}
server {
listen 443 ssl;
location /api/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 5s;
proxy_read_timeout 10s;
proxy_send_timeout 10s;
proxy_buffering off; # 仅当需要时
}
}
}
proxy_http_version 1.1是上游 keepalive 所必需的。- 空的
Connection头。 - 减少超时时间以防止长时间挂起。
- 调整 worker 进程/连接数:
- 设置
worker_processes auto;以匹配 CPU 核心数。 - 将worker_connections增加到 4096 或更高。 - 调整客户端连接的keepalive_timeout。
在应用之前,我们:
- 备份了原始配置:cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
- 在与生产环境镜像的 staging 环境中进行了测试。
- 在 reload 之前使用 nginx -t 进行了验证。
我们使用了 nginx -s reload 进行优雅重载,它会创建新的 worker 并排空旧连接。
回滚策略
如果更改导致问题:
- 恢复备份:
cp /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf - 测试:
nginx -t - 重载:
nginx -s reload
如果问题很严重,我们可以使用符号链接快速切换到旧配置(如果保留了多个版本)。
验证与结果
重载后,我们监控了错误日志、访问日志和外部指标(例如 Datadog)。
tail -f /var/log/nginx/error.log显示不再有超时错误。wrk基准测试显示吞吐量和延迟提高了 40%。ss -s套接字统计显示新建 TCP 连接减少,因为 keepalive 被重用。- 客户的 p95 延迟下降回约 80 毫秒。
何时提交 OpsGlobal 工单
这种级别的故障排查通常可以由公司内部的 DevOps 团队完成。然而,如果你遇到以下情况,就是时候请 OpsGlobal 介入了:
- 你不熟悉 Nginx 内部机制,或者不习惯编辑生产配置。
- 基本调优后问题仍然存在,可能需要调整内核参数(例如
tcp_tw_reuse、somaxconn)或系统级调优。 - 你需要水平扩展网关,需要负载均衡器设计或服务网格集成方面的专业知识。
- 症状指向上游服务异常,需要帮助追踪或检测微服务。
OpsGlobal 提供 24/7 支持。我们可以接管事件响应、执行深入的性能审计,并实施具有适当回滚计划的生产变更。
适用场景
适合正在处理 Performance、Nginx, API网关, 性能调优, SRE 相关问题的团队,用于快速建立排查路径和交付标准。
问题背景
了解如何诊断和解决基于 Nginx 的 API 网关的性能瓶颈,包含实用命令、风险控制和回滚策略。
排查步骤
先确认影响范围和最近变更,再收集日志、配置、指标和链路数据,最后按风险从低到高执行修复。
命令示例
示例命令请替换为你的真实资源名,并使用环境变量保存账号、密码、token 等敏感信息。
风险说明
生产环境操作前需要确认备份、权限边界、变更窗口和回滚路径,避免扩大故障影响。
回滚方案
保留原配置和发布版本;如修复后指标异常,立即回退配置、镜像或数据库变更并复核日志。
交付清单
问题定位记录、关键命令、修复步骤、验证结果、后续优化建议。
遇到类似技术问题?
如果你的服务器、K8s、Docker、CI/CD、数据库或监控系统出现类似问题,可以提交日志和配置文件,我们帮你远程诊断。