Linux Nginx 代理超时排查时怎么抓包分析 TCP 挥手过程
前言Nginx 反向代理超时的直接后果是 504错误日志里常见这几种描述upstream timed out (110: Connection timed out) while connecting to upstream upstream timed out (110: Connection timed out) while reading response header from upstream upstream timed out (110: Connection timed out) while sending request to upstream upstream prematurely closed connection while reading response header from upstream no live upstreams while connecting to upstream光看日志你只知道超时了但不知道是后端没回、网络中间设备把它掐了、还是 Nginx 自己等不下去先撤了。抓包的价值就在这里TCP 的挥手FIN/RST方向和发生时刻是判断谁先放弃最硬的证据。本文基于 RHEL 9 / Ubuntu 22.04 nginx 1.24讲清三件事三类超时分别对应哪个阶段的包tcpdump里 FIN、RST、半关闭half-close怎么读以及一次真实的 504 抓包记录怎么逐行解释。文中示例均可在 Nginx 所在主机上直接执行。一、先分清超时发生在哪个阶段Nginx 的proxy模块有三个独立超时对应请求生命周期的三段抓包时看到的形态完全不同指令默认值覆盖阶段超时后日志里的动词proxy_connect_timeout60s与后端三次握手while connecting to upstreamproxy_send_timeout60s把请求体发给后端while sending request to upstreamproxy_read_timeout60s等待后端响应while reading response header from upstream三者默认都是 60 秒所以如果你没改过配置看到的行为就是请求发出后正好 60 秒出现 504。这个整整 60 秒本身就是线索第一节能省掉你不少瞎猜。另外还有两个只影响重试的指令proxy_next_upstream_timeout默认 0不限制和proxy_next_upstream_tries默认 0不限制次数。它们不产生自己的错误日志但会决定一次超时之后你还看不看得到后续记录。确认配置值时可以直接打印合并后的完整配置nginx -T 2/dev/null | grep -nE proxy_(connect|send|read)_timeout注意nginx -T需要 nginx 1.9.2 及以上版本更老的版本只能用nginx -t校验语法配置值从/etc/nginx/下的文件里翻。二、抓包前的准备抓包要在 Nginx 这台机器上做因为它同时看得到两个方向客户端到 Nginx、Nginx 到后端。抓的时候只保留后端相关的包避免把正常业务流量一起灌进来。# 1. 确认网卡名RHEL 9 常见 ens192Ubuntu 常见 ens33 ip -br a # 2. 装 tcpdump # RHEL/Rocky/AlmaLinux: sudo dnf install -y tcpdump # Debian/Ubuntu: sudo apt update sudo apt install -y tcpdump # 3. 抓包只抓与后端 10.0.0.11:8080 的往来落盘保存 sudo tcpdump -i any -nn -s0 -w /tmp/upstream.pcap host 10.0.0.11 and tcp port 8080几个参数的含义值得记住-i any抓所有网卡Linux 下会使用 cooked 抓包链路层信息与物理网卡不同但不影响 TCP 层分析-nn不做端口和地址的反向解析输出更快更干净-s0抓完整包避免只抓前 96 字节导致看不到 HTTP 内容-w写入 pcap 文件供后面反复分析。如果只想在终端上实时看把-w换成-nn -tttt -v其中-tttt输出带日期的绝对时间戳方便和 Nginx 的 error log 对时间。三、读懂 FIN、RST 与半关闭tcpdump用方括号里的字母表示 TCP 标志位对照表如下输出形式含义说明Flags [S]SYN发起连接Flags [S.]SYNACK接受连接Flags [.]ACK纯确认无数据Flags [P.]PSHACK携带数据Flags [F.]FINACK本方要关闭发送方向Flags [R]/Flags [R.]RST强制复位通常是异常正常关闭是四次挥手F.→.→F.→.如果只看包序列就是两方各发一个带 FIN 的包各自被对方确认一次。谁先发F.谁就是主动关闭方active closer谁就会在自己这一侧留下 TIME_WAIT。RST 则完全不同它直接终止连接不进入 TIME_WAIT数据可能已经丢了。抓包里看到 RST优先怀疑这几种情况后端进程崩溃或被 OOM killer 杀掉内核替它发 RST。连接在对端已经关闭之后还往上写数据对端回 RST。后端 listen 的 backlog 满了内核丢弃或拒绝新连接。中间有防火墙、四层负载均衡按空闲时间回收了连接客户端不知道继续用这条僵尸连接。还有一种是半关闭一方发了 FIN另一方还在继续发送数据F.之后紧跟P.包。这在流式响应SSE、大文件下载里很常见属于正常现象但如果 Nginx 侧先发了 FIN 而响应还在传输就要回头检查proxy_read_timeout是不是设得太紧。特别提醒Nginx 主动向上游发 FIN 不一定是故障。上游 keepalive 连接池里的空闲连接被回收超过keepalive_timeout或超过keepalive_requests时Nginx 就会发 FIN这是在正常清理连接。看到 FIN 要先看它前一条包是什么。实战一次 504 的抓包记录假设proxy_read_timeout 60s;后端接口/api/slow偶尔超时。按下面的顺序操作# 终端 A抓包 sudo tcpdump -i any -nn -s0 -w /tmp/upstream.pcap host 10.0.0.11 and tcp port 8080 # 终端 B复现 curl -o /dev/null -s -w code%{http_code} total%{time_total}\n http://127.0.0.1/api/slow # 抓够了以后 Ctrl-C 停掉终端 A然后离线分析 sudo tcpdump -nn -tttt -r /tmp/upstream.pcap | head -40只看带 FIN 或 RST 的包可以一步筛出来这个过滤表达式是 pcap-filter 语法tcp[tcpflags]取的是 TCP 标志位字节sudo tcpdump -nn -tttt -r /tmp/upstream.pcap tcp[tcpflags] (tcp-fin|tcp-rst) ! 0一次典型的后端处理慢记录如下时间戳做了简化两侧是源和目的14:22:31.104512 IP 10.0.0.10.51234 10.0.0.11.8080: Flags [S], seq 1001, win 29200, options [mss 1460,sackOK,TS val 33 ecr 0,nop,wscale 7], length 0 14:22:31.104633 IP 10.0.0.11.8080 10.0.0.10.51234: Flags [S.], seq 5001, ack 1002, win 28960, options [mss 1460,sackOK,TS val 88 ecr 33,nop,wscale 7], length 0 14:22:31.104701 IP 10.0.0.10.51234 10.0.0.11.8080: Flags [.], ack 1, win 229, length 0 14:22:31.104900 IP 10.0.0.10.51234 10.0.0.11.8080: Flags [P.], seq 1:120, ack 1, win 229, length 119: HTTP: GET /api/slow HTTP/1.1 14:22:31.105200 IP 10.0.0.11.8080 10.0.0.10.51234: Flags [.], ack 120, win 501, length 0 14:23:31.104900 IP 10.0.0.10.51234 10.0.0.11.8080: Flags [F.], seq 120, ack 1, win 229, length 0 14:23:31.105100 IP 10.0.0.11.8080 10.0.0.10.51234: Flags [.], ack 121, win 501, length 0 14:23:31.105400 IP 10.0.0.11.8080 10.0.0.10.51234: Flags [F.], seq 1, ack 121, win 501, length 0 14:23:31.105500 IP 10.0.0.10.51234 10.0.0.11.8080: Flags [.], ack 2, win 229, length 0逐行解读握手正常[S]、[S.]、[.]三行在 1 毫秒内完成proxy_connect_timeout没问题。TCP 时间戳选项TS val/ecr存在说明两端都开了tcp_timestamps。请求GET /api/slow已经发出并被后端确认说明proxy_send_timeout也没问题。从 14:22:31 到 14:23:31 整整 60 秒没有任何数据包。这个 60 秒正好等于proxy_read_timeout的默认值。14:23:31 这一毫秒里Nginx 侧10.0.0.10.51234先发[F.]然后后端确认并且回自己的[F.]最后 Nginx 确认四次挥手完整。全程没有 RST没有重传如果有重传会出现形如Flags [P.], seq 1:120的重复行或tcpdump输出的 retransmission 字样需要抓包时加-v才显示。结论很清楚不是网络问题是后端自己 60 秒没吐出一个字节Nginx 等到超时后主动关闭连接并返回 504。修复方向在后端慢查询、下游依赖超时、线程池排队而不是调proxy_read_timeout——把超时从 60 秒调到 120 秒只是把 504 延后用户等待时间更长。作为对照如果是中间设备掐连接你会看到 Nginx 在等待期间收到一个Flags [R]而且这个 RST 往往出现在一个不规整的时间点比如 30 秒、300 秒这种设备侧的空闲回收周期紧随其后 Nginx 才会记日志。这时候要看链路上有没有四层负载均衡、云厂商的安全组或者 NAT 网关它们的空闲超时必须大于 Nginx 的proxy_read_timeout。交叉验证用ss和日志变量缩小范围抓包之外两个更轻量的手段可以快速缩小范围。第一个是看 socket 状态和定时器ss需要 iproute2-o显示定时器-i显示 RTT、拥塞窗口、重传信息# 看与后端的连接、重传计数和 socket 定时器 ss -tion state established ( dport :8080 ) # 看一眼重传相关的全局统计 nstat -az | grep -iE TcpRetrans|TcpExtTCPLostRetransmit如果ss -ti里的retrans计数持续增长而抓包也确实看到同一个 seq 反复出现那就是链路丢包不是后端慢如果retrans一直是 0、RTT 稳定就是后端应用没回。第二个手段是给 access log 加上游时间变量把是不是超时直接变成可统计的指标log_format upstream_timing $remote_addr $request $status urt$upstream_response_time uct$upstream_connect_time uht$upstream_header_time rt$request_time;$upstream_connect_time大问题在握手阶段proxy_connect_timeout。$upstream_header_time大而$upstream_response_time更大说明后端迟迟不返回响应头。$request_time远大于$upstream_response_time问题在客户端到 Nginx 这一段与后端无关。这三个变量会随重试记录多次值之间用逗号分隔$upstream_addr同理会按顺序记下所有被尝试过的后端地址从这里能一眼看出重试打到了哪几台机器。常见坑点❌ 在业务服务器上抓包看到的是客户端方向的流量看不到 Nginx 与后端之间的挥手。 ✅ 抓包点选在 Nginx 主机上过滤条件锁定后端 IP 和端口。❌ 抓包不带-s0只抓到每个包前 96 字节HTTP 请求行和响应头被截断。 ✅ 用-s0抓完整包只要头部分析也可以用-A直接打印 ASCII 内容。❌ 只抓一个方向例如只抓src host 10.0.0.10挥手过程少了一半无法判断谁先发 FIN。 ✅ 过滤条件用host X and tcp port Y两个方向都要。❌ 看到 Nginx 发 FIN 就断定是故障忽略它前面是不是空闲了 60 秒。 ✅ 先看 FIN 之前的时间间隔和数据包内容空闲后清理是 keepalive 池的正常行为。❌ 把 RST 一律当成后端崩溃直接去重启后端。 ✅ RST 也可能是中间设备回收连接、或对端已关闭后继续写入导致要结合时间点和设备侧空闲超时判断。❌ 超时时间不敢动直接把proxy_read_timeout从 60s 加到 600s 当作修复。 ✅ 先抓包定性后端慢就治后端如果是链路上游设备掐连接则让上游设备的空闲超时大于 Nginx 侧超时。❌ 抓包文件不设上限长时间抓在生产机上把磁盘写满。 ✅ 加-c 数量限制包数或用-w配合-C按大小轮转抓完立刻删除 pcap 文件。总结抓包看到的形态指向的问题下一步长时间静默后 Nginx 先发 FIN时长等于某个超时值Nginx 侧超时触发确认对应阶段超时值修上游或调超时等待中出现 RST时间点不规律中间设备/防火墙回收连接调整链路设备空闲超时大于 Nginx 超时同一个 seq 反复出现ss -ti的 retrans 增长网络丢包查链路质量、MTU、网卡错误计数后端发 FIN 后紧跟响应数据半关闭流式响应正常无需处理确认业务是否符合预期三次握手阶段就超时只有 SYN 重传后端不可达或 backlog 满查后端监听状态、somaxconn抓包分析 TCP 挥手的关键不是把每个包都读懂而是回答一个问题谁先放弃为什么是那个时刻。把日志里的超时值、抓包里 FIN 出现的时间点、以及两端配置的空闲超时三者对齐归属就能立刻确定也不用再靠重启试试来碰运气。

相关新闻

智能汽车后台云架构解析:阿里云与千问的算力逻辑

智能汽车后台云架构解析:阿里云与千问的算力逻辑

1. 从一句调侃说起:智能汽车后台的云厂商格局“中国智能汽车的后台,越来越像阿里云的主场。”这句话最早是我在一个车圈技术群里看到的,当时大家正在讨论某家新势力车企的车机OTA推送延迟问题,有人甩出一张后台服务调用链的截图&a…

2026/10/5 10:44:52 阅读更多 →
AODV移动自组网仿真全攻略:协议机制、参数配置与避坑实战

AODV移动自组网仿真全攻略:协议机制、参数配置与避坑实战

简介:面向移动自组网研究与仿真场景的 AODV 路由协议实现资源,压缩包内仅含 3 个 .h 头文件、体积约 8KB,适合需要快速理解协议核心机制并开展仿真实验的研究者、工程师与网络爱好者。包内头文件分别承担协议基础定义与常量、RREQ/RREP/RERR …

2026/10/4 10:33:12 阅读更多 →
Win11Debloat 新手指南:10分钟完成 Windows 11 去臃肿与隐私清理

Win11Debloat 新手指南:10分钟完成 Windows 11 去臃肿与隐私清理

Win11Debloat 新手指南:10分钟完成 Windows 11 去臃肿与隐私清理 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declut…

2026/10/5 11:22:30 阅读更多 →

最新新闻

AI智能体与Office文档自动化:从ReAct任务规划到工具调用的完整实践

AI智能体与Office文档自动化:从ReAct任务规划到工具调用的完整实践

1. 从毕设选题到真实落地:这个Office智能体套件到底在做什么每年到毕设季,计算机科学与技术专业的同学都会陷入同一个循环:打开选题列表,看到“基于XX的XX系统设计与实现”就头疼,选了个题目又担心工作量不够、技术含量…

2026/10/5 14:41:16 阅读更多 →
Lighttools 8.4.0虚拟相机与3D显示:光学仿真可视化全流程指南

Lighttools 8.4.0虚拟相机与3D显示:光学仿真可视化全流程指南

1. 内容整体设计与思路拆解1.1 Lighttools 8.4.0到底解决什么问题光学设计圈子里有个老传统:设计完一个照明系统,拿到照度图、光强分布曲线,就觉得自己搞定了。但实际上,客户问的第一句话往往是“这东西装上去,人眼看起…

2026/10/5 14:41:16 阅读更多 →
企业智能体平台落地实战:工作流、RAG与权限治理的深水区

企业智能体平台落地实战:工作流、RAG与权限治理的深水区

1. 企业智能体平台落地困境的底层逻辑过去一年多,我参与过三个不同规模的企业智能体平台从选型到上线的完整过程,也帮朋友的公司做过几次技术方案评审。一个非常普遍的现象是:演示阶段效果惊艳,POC 阶段勉强过关,一到真…

2026/10/5 14:41:16 阅读更多 →
DeepSeek Harness桌面端实战:API Key配置、插件与工作流避坑指南

DeepSeek Harness桌面端实战:API Key配置、插件与工作流避坑指南

1. 桌面端来了,为什么这件事比想象中重要 DeepSeek Harness 这个工具,早几个月前还只能在命令行里敲来敲去,配置全靠手写 JSON 和 YAML,每次换台机器就得重新折腾一遍环境变量。现在官方桌面端终于落地,对于长期在本地…

2026/10/5 14:41:16 阅读更多 →
DeepSeek Harness桌面端深度解析:从安装配置到内网部署与插件实战

DeepSeek Harness桌面端深度解析:从安装配置到内网部署与插件实战

1. 桌面端来了,为什么这件事比想象中重要DeepSeek Harness 出官方桌面端这件事,我第一反应不是"终于等到了",而是"早该如此"。过去大半年,我身边用 DSH 的人基本分成两派:一派死磕命令行&#xff…

2026/10/5 14:41:16 阅读更多 →
隔离内网AI Agent落地方案:从模型选型到并发压测全指南

隔离内网AI Agent落地方案:从模型选型到并发压测全指南

把 AI Agent 推进隔离内网的时候,我最直观的感受是:网上那些 Agent 演示项目,到了内网几乎没有一个能直接跑起来。这不是代码写得不行,而是它们默认的世界里什么都有——模型权重从 HuggingFace 拉、Python 依赖从 PyPI 装、搜索工…

2026/10/5 14:40:16 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →