尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Nginx反向代理偶发超时排查:从网络抓包到eBPF内核追踪全链路实战

Nginx反向代理偶发超时排查:从网络抓包到eBPF内核追踪全链路实战 这次我们来看一个线上服务排障的经典场景Nginx 作为反向代理自身日志一切正常没有 5xx 错误但上游应用接口却偶发超时导致客户端请求失败。这种问题排查起来往往令人头疼因为它不像代码 Bug 那样有明确的堆栈而是隐藏在复杂的网络交互、系统负载和内核行为之中。问题的核心在于Nginx 的access.log和error.log只能反映它自身处理请求的状态。当 Nginx 将请求转发给后端应用如 Tomcat、Node.js、Go 服务后从建立连接到接收响应的整个链路上任何一个环节的延迟都可能导致最终超时。而 Nginx 默认只会记录请求的开始和结束状态码对于中间漫长的等待过程它是“沉默”的。本文将带你系统性地拆解这个难题。我们会从最基础的网络抓包开始逐步深入到系统内核态的性能分析使用tcpdump、eBPF等工具定位从客户端到 Nginx再到上游服务的完整链路中究竟是哪个环节“偷走”了时间。无论你是运维工程师、后端开发还是全栈开发者掌握这套排查思路都能让你在面对线上偶发超时这类“幽灵问题”时不再束手无策。1. 核心能力速览排障工具箱与思路在深入细节前我们先快速了解解决此类问题需要哪些“武器”以及整体的排查路径。这能帮助你在遇到问题时快速判断该从何处入手。能力项说明与工具问题特征Nginx 返回 502/504 或客户端超时但 Nginx 自身日志无异常错误。超时偶发难以稳定复现。排查核心思路遵循“从外到内从应用到系统”的原则先确认客户端到 Nginx 的网络再确认 Nginx 到上游的网络最后分析上游应用及操作系统内核。关键工具网络层:tcpdump,Wireshark,netstat,ss应用层: Nginx 日志定制、上游应用日志、应用性能监控(APM)系统层:strace,perf,eBPF(如bcc-tools中的tcplife,tcpretrans)硬件/环境门槛需在出问题的服务器上执行命令通常需要root或sudo权限。eBPF工具需要内核版本 4.1推荐 4.9。适合场景生产环境或测试环境中的偶发性网络超时、接口响应慢问题排查。尤其适用于微服务、API 网关后方服务链路的性能诊断。2. 问题场景与排查边界在开始动手前明确问题的具体表现和排查的边界至关重要。这能避免你陷入无关的细节直奔主题。典型场景还原用户或监控系统报告调用某个 API 接口偶尔会失败错误信息是“连接超时”或“响应超时”。查看 Nginx 的access.log发现对应请求的状态码可能是200成功、502Bad Gateway或504Gateway Timeout。但关键是error.log里没有对应的error级别日志。上游应用如 Java 服务的日志可能记录了该请求但处理耗时看起来正常也可能根本没收到这个请求。排查边界定义目标不是修改 Nginx 或应用的代码而是定位延迟产生的具体环节。范围涵盖完整的请求生命周期客户端 - Nginx - 上游服务 - Nginx - 客户端。重点网络连接建立时间、数据传输时间、上游服务处理时间、以及系统层面的资源争用如 CPU 调度、内存回收。排除代码逻辑 Bug、数据库慢查询等应用层问题除非它们通过系统调用表现出来。这些问题通常有更明确的日志。3. 环境准备与前置条件工欲善其事必先利其器。在问题发生前就应该在服务器上准备好这些工具以便在问题出现时能快速投入战斗。3.1 工具安装清单根据你的 Linux 发行版安装以下工具包# 对于 CentOS/RHEL/Alibaba Cloud Linux sudo yum install -y tcpdump sysstat perf kernel-devel-$(uname -r) kernel-headers-$(uname -r) # 安装 bcc-tools (eBPF) sudo yum install -y bcc-tools # 对于 Ubuntu/Debian sudo apt-get update sudo apt-get install -y tcpdump sysstat linux-tools-common linux-tools-$(uname -r) # 安装 bcc-tools (eBPF) sudo apt-get install -y bcc-tools安装后bcc-tools的工具通常位于/usr/share/bcc/tools/目录下。3.2 权限与配置检查权限tcpdump,perf,eBPF工具通常需要root权限。确保你有sudo权限或在问题发生时能快速获得。Nginx 配置确保 Nginx 的日志格式包含了请求时间信息这对于后期分析至关重要。检查你的nginx.conf或vhost配置http { log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for upstream_addr$upstream_addr request_time$request_time upstream_response_time$upstream_response_time upstream_connect_time$upstream_connect_time upstream_header_time$upstream_header_time; access_log /var/log/nginx/access.log main; }$request_time客户端请求的总处理时间。$upstream_response_time从 Nginx 向上游建立连接到接收完响应头的时间。$upstream_connect_time与上游服务器建立连接的时间。$upstream_header_time从连接到接收完上游响应头的时间。 配置后需要重载 Nginxsudo nginx -s reload。4. 第一阶段排查网络链路抓包与分析当超时再次发生时第一步是抓取网络数据包这是最直接的证据。我们分两个方向进行客户端到 Nginx以及 Nginx 到上游服务。4.1 抓取 Nginx 与上游服务之间的流量假设你的 Nginx 服务器 IP 是192.168.1.10上游服务 IP 是192.168.1.20端口是8080。在 Nginx 服务器上启动抓包# 抓取所有与上游服务器 192.168.1.20:8080 的 TCP 流量并写入文件 sudo tcpdump -i any host 192.168.1.20 and port 8080 -w nginx_to_upstream.pcap -s 0-i any: 监听所有网卡。host 192.168.1.20 and port 8080: 过滤特定主机和端口。-w nginx_to_upstream.pcap: 将原始数据包保存到文件便于用 Wireshark 进行图形化分析。-s 0: 抓取完整的数据包。触发超时请求让客户端再次发起那个会超时的请求。停止抓包请求完成后无论成功或超时按CtrlC停止tcpdump。分析抓包文件将nginx_to_upstream.pcap下载到本地使用 Wireshark 打开。重点关注TCP 三次握手延迟查看SYN,SYN-ACK,ACK包之间的时间差。如果SYN发出后很久才收到SYN-ACK可能是网络问题或上游服务负载过高TCP backlog 队列满。数据传输与确认观察请求体发送后到收到第一个响应包之间的时间。如果这个间隔很长而上游服务日志显示处理很快则可能是网络丢包、重传或者上游服务所在主机 CPU 调度延迟。TCP 重传与零窗口Wireshark 会用黑色背景或特定标识标记重传包。如果发现大量重传说明网络不稳定。如果看到TCP ZeroWindow报文说明接收方可能是 Nginx 或上游的缓冲区满了应用没有及时读取数据。4.2 使用tcpdump命令行进行快速分析如果不方便使用 Wireshark可以直接用tcpdump命令行过滤关键信息# 1. 查看与上游服务器连接建立过程中的异常如SYN重传 sudo tcpdump -i any host 192.168.1.20 and port 8080 and tcp[tcpflags] (tcp-syn|tcp-ack) ! 0 # 2. 查看是否有大量的TCP重传包 sudo tcpdump -i any host 192.168.1.20 and port 8080 and tcp[13] 4 ! 0 # RST标志 # 更准确的重传判断需要结合序列号分析上述命令仅作参考。更推荐用Wireshark。 # 3. 实时查看Nginx与上游的HTTP请求/响应概要假设是HTTP协议 sudo tcpdump -i any -A -s 0 host 192.168.1.20 and port 8080 and tcp port 8080 | grep -E (GET|POST|HTTP\/1\.[01])5. 第二阶段排查系统与内核态深度分析如果网络抓包显示连接建立和数据传输本身没有明显延迟例如三次握手在1ms内完成但请求整体还是超时了那么问题可能更深层涉及到操作系统内核的网络栈处理、CPU调度或资源锁竞争。这时eBPF工具就派上用场了。5.1 使用tcplife追踪 TCP 会话生命周期tcplife是bcc-tools中的一个工具它可以实时显示 TCP 连接的生命周期包括本地和远程地址、端口、连接持续时间毫秒以及发送/接收的字节数。这能帮你快速发现哪些连接存在异常的长耗时。# 以 root 权限运行 sudo /usr/share/bcc/tools/tcplife # 或者如果已在 PATH 中 sudo tcplife # 输出示例 PID COMM LADDR LPORT RADDR RPORT TX_KB RX_KB MS 12345 nginx 192.168.1.10 443 110.120.130.140 54321 5 20 1500 67890 java 192.168.1.20 8080 192.168.1.10 56789 2 1 2500 -- 这个连接持续了2.5秒关键观察点MS 列连接持续时间。关注与上游服务192.168.1.20:8080建立的连接中持续时间异常长例如远超平均响应时间的记录。PID/COMM 列看到长时间连接对应的进程是 Nginx 还是上游应用。如果是上游应用如java那么问题可能出在应用处理逻辑或它依赖的资源如数据库、下游服务。如果是nginx进程本身则需要结合其他工具看 Nginx 在等待什么。5.2 使用tcpretrans追踪 TCP 重传TCP 重传是导致延迟的常见原因但有时在应用层或常规tcpdump中不易察觉。tcpretrans可以追踪内核中的 TCP 重传事件。sudo /usr/share/bcc/tools/tcpretrans运行后它会打印出发生重传的 TCP 报文信息包括时间戳、源目地址、端口等。如果发现到上游服务器的连接频繁重传即使每次重传间隔不长累积起来也会导致超时。5.3 使用strace跟踪 Nginx 工作进程的系统调用如果怀疑是 Nginx 进程本身在某个系统调用上被阻塞例如连接上游时connect()调用卡住或读取响应时read()调用卡住可以使用strace进行跟踪。找到处理请求的 Nginx 工作进程 PIDsudo ps aux | grep nginx | grep worker # 或者通过访问日志的端口反查 (假设Nginx监听80端口) sudo ss -tlnp | grep :80跟踪该进程的系统调用特别是网络相关的# -p PID: 跟踪指定进程 # -ttt: 打印时间戳微秒精度 # -T: 显示每个系统调用的耗时 # -f: 跟踪子进程如果Nginx有子进程 # -e tracenetwork: 只跟踪网络相关的系统调用如socket, connect, sendto, recvfrom sudo strace -ttt -T -f -p nginx_worker_pid -e tracenetwork触发超时请求。观察strace输出。你会看到类似下面的行1712345678.123456 connect(15, {sa_familyAF_INET, sin_porthtons(8080), sin_addrinet_addr(“192.168.1.20”)}, 16) 0 0.000123 1712345678.456789 sendto(15, “GET /api/test HTTP/1.1\r\nHost…”, 256, 0, NULL, 0) 256 0.000045 1712345678.789012 recvfrom(15, unfinished … # 卡在这里了如果recvfrom或read调用后面没有立刻显示返回值和耗时而是长时间挂起直到超时才结束并且耗时3.000123假设超时时间是3秒这就明确指出了阻塞点Nginx 在等待上游的响应数据。6. 第三阶段排查上游应用与资源分析当网络和 Nginx 层面的证据都指向上游服务响应慢时排查重点就需要转移到上游服务器本身。6.1 分析上游应用日志检查上游应用如 Java 应用的logback/log4j日志Go 应用的stdout在超时时间点附近是否有慢查询日志数据库、Redis。调用外部服务的超时记录。垃圾回收GC暂停的日志对于 JVM 应用。线程池耗尽的警告。6.2 检查系统资源在上游服务器上使用以下命令检查超时时刻的系统状态CPUtop -H或htop查看是否有进程或线程 CPU 使用率 100%。内存free -m查看是否因内存不足触发频繁的 Swap。磁盘 I/Oiostat -x 1查看%util和await是否过高。网络连接ss -s或netstat -s查看是否有TCP timeout、retrans计数增长。6.3 使用perf进行 CPU 性能剖析如果怀疑是上游应用自身代码或锁竞争导致 CPU 调度延迟可以在上游服务器上用perf采样。# 对特定进程进行 30 秒的 CPU 调用栈采样 sudo perf record -F 99 -p upstream_app_pid -g -- sleep 30 sudo perf report --stdio查看perf report的输出关注哪些函数占用 CPU 时间最多是否存在自旋锁或同步原语导致的忙等待。7. 模拟复现与压测验证对于偶发问题主动模拟和压测是验证猜想和定位瓶颈的有效手段。7.1 使用wrk或ab进行压测模拟客户端请求观察超时率。# 使用 wrk 进行持续30秒10个线程100个连接的压测 wrk -t10 -c100 -d30s --timeout 2s http://your-nginx-server/api/your-endpoint关注输出中的Latency延迟分布和Requests/sec。如果延迟的99%或99.9%分位数非常高说明存在尾部延迟问题这与“偶发超时”的特征相符。7.2 在压测同时进行监控一边压测一边在 Nginx 和上游服务器上运行前面提到的监控命令tcplifetcpdump(可限定只抓取压测客户端的IP)top/htop应用监控指标如 JVM GC 时间、线程池活跃数通过关联压测时间点和监控数据往往能捕捉到问题瞬间的系统状态。8. 常见问题与排查方法速查表将上述排查过程总结为一张问题排查表方便你在实际工作中快速对照。问题现象可能原因排查工具/方法解决方案/下一步Nginxupstream_connect_time过长1. 上游服务负载高TCP backlog 满2. 网络路由或防火墙问题3. DNS 解析慢tcpdump看 SYN-ACK 延迟ss -lnt查看上游服务监听队列检查/etc/hosts或 DNS 配置优化上游服务性能增大net.core.somaxconn和应用的backlog检查网络使用 IP 直连或优化 DNS。Nginxupstream_response_time长但上游日志显示处理很快1. 网络传输慢或丢包重传2. 上游服务器内核协议栈处理慢如 softirq 高3. 上游应用发送响应数据慢如缓冲区满tcpdump/Wireshark 看 TCP 序列号和 ACKtcpretrans看重传strace跟踪 Nginx 的recvfrom检查上游服务器sar -n ETCP 1优化网络质量检查上游服务器 CPU 软中断 (top看si占比)调整上游应用 socket 缓冲区或刷新输出流。请求完全未到达上游应用1. Nginxproxy_pass配置错误2. 上游服务崩溃或未监听端口3. 连接被中间防火墙拦截检查 Nginx 配置在上游服务器netstat -tlnp | grep port双向tcpdump抓包修正 Nginx 配置重启上游服务检查防火墙规则 (iptables,firewalld)。超时只在特定时间或流量下发生1. 定时任务导致资源竞争如备份、日志切割2. 流量洪峰导致连接池耗尽或线程池满3. 底层云服务如云硬盘性能波动检查 crontab监控应用连接池/线程池指标检查系统监控CPU、IO、网络带宽错峰执行定时任务扩容应用实例或优化池化配置联系云服务商或使用更高性能的底层资源。strace显示connect()或recvfrom()长时间阻塞系统调用在内核中等待资源通常是内核网络栈或协议层的问题。结合perf分析内核调用栈检查系统参数如net.ipv4.tcp_syn_retries,net.ipv4.tcp_fin_timeout调整内核网络参数升级内核版本考虑是否有 SYN Flood 攻击启用syn cookies。9. 最佳实践与长效预防排查一次问题很辛苦更好的方法是建立预防机制让问题在出现苗头时就被发现。完善监控与告警Nginx 指标监控$upstream_response_time的 p95, p99 分位数设置阈值告警。使用ngx_http_stub_status_module或nginx-module-vts暴露更多指标。系统指标监控服务器的 CPU、内存、网络带宽、TCP 重传率、连接数。应用指标上游应用暴露 Prometheus 指标如请求延迟、错误率、线程池状态、GC 时间。优化配置Nginx 超时设置合理配置proxy_connect_timeout,proxy_send_timeout,proxy_read_timeout根据业务特性设置不宜过短或过长。内核参数调优根据业务负载调整/etc/sysctl.conf中的网络参数例如net.core.somaxconn 65535 net.ipv4.tcp_max_syn_backlog 65535 net.ipv4.tcp_syncookies 1 net.ipv4.tcp_tw_reuse 1 net.ipv4.tcp_fin_timeout 30上游服务配置确保应用服务器的 TCP backlog、线程池、连接池大小与预期负载匹配。建立排查预案将本文提到的工具安装、常用命令写成脚本或文档放在团队知识库。在测试环境定期进行故障演练模拟网络延迟、丢包、上游服务高负载等场景验证监控告警和排查流程的有效性。线上偶发的 Nginx 超时问题本质是一个“全链路”问题。它要求我们具备从应用日志、网络协议到操作系统内核的跨层级排查能力。从最直观的tcpdump抓包开始逐步深入到eBPF追踪内核事件这套由表及里的方法链是解决此类复杂问题的有效路径。最应该优先验证的永远是网络链路和基础资源。一次简单的tcpdump抓包可能直接暴露出重传或连接建立的延迟。最容易踩的坑是只盯着 Nginx 日志和应用日志而忽略了操作系统内核这个“黑盒”。eBPF工具如tcplife和tcpretrans正是打开这个黑盒的钥匙。下次再遇到 Nginx 沉默而客户端报错的超时不妨按照这个顺序来先看 Nginx 定制日志的时间字段再抓包看网络交互接着用eBPF工具看连接生命周期和重传最后用strace或perf定位阻塞点。把这套组合拳练熟大部分的偶发网络超时问题都将无处遁形。建议将本文提及的命令和思路收藏为线上排障的实战手册。
返回列表