告别网络排障恐惧症-告别UI版wireshark:用 curl + tcpdump + tshark + ss 构建完整工具链
你是否曾被 tcpdump 满屏的十六进制吓退?是否在 Wireshark 复杂的 UI 中迷失方向?
本文将用一条清晰的工具链告诉你:90% 的问题用 curl 就能搞定,剩下的 10% 也有优雅的命令行方案。
前言:运维网络排障的完整武器库
做运维的同学都经历过这样的场景:
- 用户说"网站打不开"或"系统卡",你登上服务器,一脸茫然。
- 想抓包看看,
tcpdump一开,满屏数据飞过,根本不知道该看哪一行。 - 把 pcap 文件拉到本地用 Wireshark 打开,在一堆协议字段中点来点去,最后发现只是 DNS 解析慢了一点点......
本文的目标是:给你一套完整的、从应用层到传输层的命令行排障方法论。
先上一张"排障决策树",帮你快速决定用哪个工具:
用户报告网络故障
↓
┌─────────────────────────────────────────────────────────┐
│ 第一步:用 curl -w 测量耗时分布(应用层) │
│ → 定位问题在哪一层:DNS?TCP?TLS?还是服务器处理? │
└────────────────────────┬────────────────────────────────┘
↓
┌──────────┴──────────┐
↓ ↓
问题在应用层/HTTP/HTTPS 问题在传输层/非HTTP协议/底层网络
↓ ↓
┌─────────────────┐ ┌─────────────────────────────┐
│ curl -v / -I 等 │ │ 第二步:用 ss 看连接状态 │
│ 深入诊断 │ │ (套接字层快速巡检) │
└─────────────────┘ └──────────────┬──────────────┘
↓
┌──────────┴──────────┐
↓ ↓
快速定位就够了 需要深入分析报文
↓ ↓
┌──────────────────┐ ┌──────────────────┐
│ tcpdump 轻量抓包 │ │ tshark 深度解析 │
│ (快速验证) │ │ (脚本化分析) │
└──────────────────┘ └──────────────────┘
记住这条铁律:
- curl → 应用层第一道防线(HTTP/HTTPS/TLS 问题)
- ss → 套接字层快速巡检(连接状态、端口、进程)
- tcpdump → 传输层轻量抓包(快速验证、远程 SSH 场景)
- tshark → 深度协议分析(脚本化提取、统计、无 GUI 环境)
下面,我们逐个拆解这四个工具。
第一部分:curl ------ 应用层排障的瑞士军刀
curl 提供了一个 -w (write-out) 选项,可以输出请求过程中各个阶段的精确耗时。先看一个完整的命令模板:
bash
# 创建格式化文件(一次性操作)
cat > curl-format.txt << 'EOF'
time_namelookup: %{time_namelookup}\n
time_connect: %{time_connect}\n
time_appconnect: %{time_appconnect}\n
time_pretransfer: %{time_pretransfer}\n
time_redirect: %{time_redirect}\n
time_starttransfer: %{time_starttransfer}\n
----------\n
time_total: %{time_total}\n
EOF
# 使用该格式测试目标 URL
curl -w "@curl-format.txt" -o /dev/null -s "https://www.example.com"
输出示例:
time_namelookup: 0.031
time_connect: 0.041
time_appconnect: 0.131
time_pretransfer: 0.131
time_redirect: 0.000
time_starttransfer: 0.188
----------
time_total: 0.199
各指标含义速查表
| 变量 | 含义 | 包含的阶段 | 正常范围 | 异常时指向的问题 |
|---|---|---|---|---|
time_namelookup |
DNS 解析时间 | 域名 → IP | < 100ms | DNS 服务器慢 / 解析失败 |
time_connect |
TCP 三次握手完成时间 | SYN, SYN-ACK, ACK | < 200ms | 网络延迟大 / 防火墙拦截 / 端口不通 |
time_appconnect |
SSL/TLS 握手完成时间 | 加密协商、证书交换 | < 300ms | 服务端 SSL 性能差 / 证书链过长 / 风控延迟 |
time_pretransfer |
准备传输数据的时间 | 等于 time_appconnect(无重定向时) |
--- | 存在重定向时会增加 |
time_starttransfer |
收到服务器第一个字节的时间 | 包含服务器处理时间 | --- | 应用代码慢 / 数据库查询慢 |
time_total |
总耗时 | 以上全部 + 数据传输 | --- | 用户体验总时长 |
三个黄金锚点,快速定位问题层
time_connect → 网络层问题(防火墙、路由、端口)
time_appconnect → TLS/SSL 层问题(证书、加密协商、安全策略)
time_starttransfer → 应用层问题(代码逻辑、SQL、第三方 API)
实战案例:云迁移后 HIS 系统间歇性卡顿
故障现象:医院 HIS 系统迁移至阿里云后,高峰时段调用医保接口响应超时(>5秒),但 ping 医保域名延迟正常。
curl 做法:
bash
curl -w "@curl-format.txt" -o /dev/null -s "https://yibao-api.xxx.cn/pay"
输出:
time_namelookup: 0.052
time_connect: 0.078 ← 网络延迟正常
time_appconnect: 4.523 ← 异常!TLS 握手花了 4.5 秒
time_total: 5.189
结论 :time_connect 正常说明 TCP 连接没问题,但 time_appconnect 高达 4.5 秒,问题锁定在 TLS 握手阶段。结合云迁移后公网 IP 变更的背景,大概率是对端风控策略对新 IP 降级处理。与医保侧沟通后,将新 IP 加入白名单,问题秒解。
curl 更多诊断选项
| 选项 | 用途 | 示例 |
|---|---|---|
-v |
查看详细交互过程(DNS、TCP、TLS、HTTP 头) | curl -v https://example.com |
-I |
仅获取响应头 | curl -I https://example.com |
--trace-ascii |
保存完整 ASCII 交互流 | curl --trace-ascii trace.log https://example.com |
--resolve |
强制域名解析到指定 IP | curl --resolve example.com:443:1.2.3.4 https://example.com |
--connect-timeout |
设置 TCP 连接超时 | curl --connect-timeout 5 https://example.com |
第二部分:tcpdump + tshark ------ 底层抓包双雄
当 curl 告诉你"问题在 TCP 层"或者"这不是 HTTP 协议"时,就该请出这两位了。
2.1 tcpdump:轻量、通用、脚本友好
tcpdump 是 Linux/Unix 环境下最经典的命令行抓包工具,几乎预装在所有发行版上,适合远程 SSH 快速排障。
常用命令速查:
bash
# 基础抓包
sudo tcpdump -i eth0 # 监听指定网卡
sudo tcpdump -i any -c 100 # 抓取 100 个包后停止
sudo tcpdump -i eth0 -w capture.pcap # 保存到文件
tcpdump -r capture.pcap # 读取保存的文件
# 按主机和端口过滤
sudo tcpdump -i eth0 host 192.168.1.1 # 指定 IP
sudo tcpdump -i eth0 src 192.168.1.1 # 仅源 IP
sudo tcpdump -i eth0 tcp port 80 # 指定端口
sudo tcpdump -i eth0 'tcp port 80 or tcp port 443' # 组合条件
# 按协议和标志位过滤
sudo tcpdump -i eth0 icmp # ICMP 协议
sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0' # 只抓 SYN 包
# 输出格式控制
sudo tcpdump -i eth0 -A -c 5 # ASCII 格式显示内容
sudo tcpdump -i eth0 -X -c 5 # 十六进制 + ASCII
sudo tcpdump -i eth0 -tttt # 显示精确时间戳
sudo tcpdump -i eth0 -s 0 # 捕获完整报文(不截断)
# 环形缓冲(生产环境长时间抓包)
sudo tcpdump -i any -s 0 -C 100 -W 5 -w /tmp/cap%03d.pcap
# 说明:每个文件 100MB,保留 5 个,自动循环覆盖
2.2 tshark:终端里的 Wireshark
tshark 是 Wireshark 的命令行版本,它继承了 Wireshark 强大的协议解析能力和显示过滤器语法,特别适合在无 GUI 的服务器上进行深度分析,或集成到自动化脚本中。
tshark 相比 tcpdump 的核心优势:
| 特性 | tcpdump | tshark |
|---|---|---|
| 协议解析能力 | 基础解析 | 支持数千种协议的深度解析 |
| 过滤语法 | BPF 捕获过滤器 | BPF 捕获过滤器 + Wireshark 显示过滤器 |
| 输出格式 | 固定格式 | 支持 text/json/fields/ek 等多种格式 |
| 统计功能 | 无 | 内置丰富的统计功能(-z 选项) |
| 字段提取 | 不支持 | 支持精确提取任意协议字段(-T fields -e) |
常用命令速查:
bash
# 基础抓包
tshark -D # 列出可用网卡
tshark -i eth0 # 监听指定网卡
tshark -i eth0 -c 100 # 抓取 100 个包后停止
tshark -i eth0 -a duration:60 # 抓取 60 秒后停止
tshark -i eth0 -w capture.pcapng # 保存到文件
tshark -r capture.pcapng # 读取文件
# 捕获过滤器(BPF 语法,与 tcpdump 相同)
tshark -i eth0 -f "tcp port 80" # 只抓 80 端口
tshark -i eth0 -f "host 192.168.1.1 and port 443" # 组合条件
# 显示过滤器(Wireshark 语法,这是 tshark 的杀手锏)
tshark -r capture.pcapng -Y "http.request.method == GET" # 只看 GET 请求
tshark -r capture.pcapng -Y "tcp.flags.syn == 1 && tcp.flags.ack == 0" # 只看 SYN 包
tshark -r capture.pcapng -Y "tls.alert_message" # 只看 TLS 告警
# 提取指定字段(脚本化分析的核心功能)
tshark -r capture.pcapng -T fields -e frame.number -e ip.src -e ip.dst -e tcp.port
# 输出:包序号、源 IP、目的 IP、TCP 端口
tshark -r capture.pcapng -T fields -e frame.number -e tls.alert_message -E separator=,
# 输出 TLS 告警信息,逗号分隔
# 统计功能(-z)
tshark -r capture.pcapng -q -z conv,tcp # TCP 会话统计
tshark -r capture.pcapng -q -z io,phs # 协议层次统计
2.3 两大抓包工具的选型指南
| 场景 | 推荐工具 | 理由 |
|---|---|---|
| 远程 SSH 快速验证连通性 | tcpdump | 轻量、无需额外安装、输出简洁 |
| 服务器上需要长时间抓包留痕 | tcpdump 或 dumpcap | 环形缓冲、资源占用低 |
| 需要分析具体协议内容(如 TLS 握手细节) | tshark | 协议解析深度远超 tcpdump |
| 需要在脚本中批量提取统计信息 | tshark | -T fields 配合 -e 输出结构化数据 |
| 需要在无 GUI 服务器上深度分析 | tshark | 完整继承 Wireshark 分析能力 |
| 非 HTTP 协议故障排查 | tshark | 支持数千种协议解析 |
典型工作流:
tcpdump 采集 → tshark 脚本化提取 → Wireshark 交互分析(如需要)
2.4 实战案例:数据库连接池泄露排查
故障现象 :应用连接 MySQL 偶发 Too many connections,但应用侧连接池配置正常。
排查思路:
-
curl 完全用不上------这是 MySQL 协议,不是 HTTP。
-
先用 ss 快速查看当前连接数:
bashss -t state established '( dport = :3306 or sport = :3306 )' | wc -l # 发现连接数远超预期,确认存在泄露 -
用 tcpdump 在 MySQL 服务器上抓包留证:
bashsudo tcpdump -i any port 3306 -s 0 -w mysql.pcap -
用 tshark 批量分析哪些 IP 占用了大量连接:
bashtshark -r mysql.pcap -T fields -e ip.src -e ip.dst | sort | uniq -c | sort -rn # 发现某台已下线服务器的 IP 仍然持有大量 ESTABLISHED 连接 -
根因定位:TCP 半开连接未关闭,MySQL 的
wait_timeout设置过长。调整参数并清理僵死连接后解决。
此类场景 curl 完全用不上,但 tcpdump + tshark + ss 的组合拳完美覆盖。
第三部分:ss ------ 套接字统计的"快枪手"
ss (Socket Statistics) 是 netstat 的现代替代品。它直接从内核空间获取信息,比 netstat 快得多,尤其在高并发场景下优势明显。
核心优势:
- 速度更快:直接读取内核内存,不走
/proc文件系统 - 信息更详细:能显示比
netstat更丰富的 TCP 状态信息 - 过滤更强:支持按状态、端口、IP 等维度精确过滤
常用命令速查:
bash
# 基础查看
ss -tln # 查看所有 TCP 监听端口(最常用)
ss -tuln # 查看所有 TCP/UDP 监听端口
ss -tan # 查看所有 TCP 连接(包括监听和非监听)
ss -tulnp # 显示占用端口的进程信息
# 按状态过滤(ss 的杀手锏功能)
ss -t state established # 只看已建立的 TCP 连接
ss -t state time-wait # 只看 TIME_WAIT 状态
ss -t state syn-sent # 只看正在尝试建立连接的
ss -t '( state not established )' # 查看非 ESTABLISHED 状态的连接
# 按 IP 和端口过滤
ss -t dst 192.168.1.10 # 目的 IP 为 192.168.1.10
ss -t sport eq :22 # 源端口为 22
ss -t dport eq :3306 # 目的端口为 3306
ss -t '( dport = :80 or sport = :80 )' # 源或目的端口为 80
# 统计信息
ss -s # 显示汇总统计(各状态连接数)
输出解读示例:
$ ss -tan state established
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 0 10.0.1.10:22 192.168.1.5:54321
ESTAB 0 0 10.0.1.10:3306 10.0.2.20:45678
- Recv-Q / Send-Q:接收和发送队列的积压数据量。非零值可能表示应用处理不过来或网络拥塞。
- Local Address:Port:本地地址和端口。
- Peer Address:Port:远端地址和端口。
常见排障场景:
| 问题现象 | ss 排查命令 | 判断依据 |
|---|---|---|
| 服务端口监听不上 | `ss -tlnp | grep <port>` |
| 连接数过多/泄露 | ss -s 或 `ss -tan |
wc -l` |
| 大量 TIME_WAIT | ss -t state time-wait |
短连接过多,需调优内核参数或启用连接复用 |
| 连接卡在 SYN_SENT | ss -t state syn-sent |
目标不可达或防火墙丢弃 SYN 包 |
| 连接卡在 CLOSE_WAIT | ss -t state close-wait |
应用未正确调用 close(),代码 bug |
第四部分:工具边界与扩展阅读
4.1 curl / tcpdump / tshark / ss 覆盖不到的领域
尽管这四个工具已经覆盖了 95% 的日常排障场景,但以下情况仍需其他工具介入:
| 场景 | 为什么上述工具不行 | 推荐工具 |
|---|---|---|
| 路径网络质量分析(延迟、丢包、路由追踪) | curl 只能测端到端,无法看中间每一跳 | mtr(My TraceRoute) |
| MTU 问题(大包无法通过、分片异常) | 应用层工具感知不到 MTU | ping -M do -s <size> + tcpdump 抓 ICMP |
| DNS 递归解析链分析 | curl 只看最终解析时间 | dig +trace |
| 带宽占用分析(哪个进程在疯狂发包) | 抓包只能看流量内容,看不出进程级流量 | nethogs、iftop |
| 进程级网络行为追踪(某进程发起了什么请求) | 抓包按端口过滤,但端口会变 | strace -e trace=network -p <pid> 或 eBPF |
| HTTP/HTTPS 代理调试(篡改请求、断点重放) | curl 只能发请求,不能拦截修改 | Fiddler、Charles |
| 安全入侵检测(实时告警、规则匹配) | 抓包工具只管采集,不管告警 | Snort |
| TCP 流重组与内容提取(恢复传输的文件) | tcpdump 只抓包,不重组 | tcpflow |
4.2 扩展阅读:当底层抓包成为刚需时
mtr ------ 网络路径诊断的第一选择
mtr 结合了 ping 和 traceroute 的功能,可以持续探测到目标主机之间每一跳的丢包率和延迟。这在排查网络质量问题(如间歇性丢包、某跳延迟突然增大)时,比抓包更直接有效。
bash
mtr -r -c 100 8.8.8.8 # 发送 100 个包后输出报告
mtr 8.8.8.8 # 实时交互模式
输出解读:
- Loss%:该跳的丢包率。注意,中间跳有丢包但后续跳丢包率低是正常的(控制平面限速),关键是最后一跳的丢包率。
- Avg / Best / Wrst:延迟的平均值、最小值、最大值。如果某跳延迟突然飙升,说明该节点可能存在拥塞。
dig ------ DNS 解析的显微镜
curl 的 time_namelookup 只能告诉你 DNS 慢了,但 dig +trace 可以完整展示从根域名服务器到权威服务器的整个解析链路,帮你定位是哪个环节出了问题。
bash
dig +trace example.com # 追踪完整解析链路
dig example.com ANY # 查询所有记录类型
dig -x 8.8.8.8 # 反向解析 IP 到域名
nethogs / iftop ------ 带宽"谁在用"的实时监控
当服务器带宽被打满,你需要快速知道是哪个进程或哪个 IP 在占用流量时:
nethogs:按进程显示实时带宽占用。iftop:按源/目的 IP 和端口显示实时流量。
bash
sudo nethogs eth0 # 按进程显示
sudo iftop -i eth0 # 按连接显示
strace / eBPF ------ 进程级网络行为的终极武器
当你需要知道某个进程到底发出了什么系统调用、连接到了哪些 IP、读写了多少数据时:
bash
# 追踪进程的网络相关系统调用
strace -e trace=network -p <pid>
# 更现代的方式:使用 bpftrace 或 eBPF 工具
tcplife # 跟踪 TCP 会话的生命周期
tcptop # 实时显示 TCP 连接的吞吐量
4.3 生产环境抓包的黄金法则
- 抓在最接近问题的一端:客户端侧问题就在客户端抓,服务端问题就在服务端抓。
- 限定过滤条件 :永远不要无过滤抓包,
-f或host/port限定范围,避免海量无关数据。 - 使用
-s 0捕获完整报文:默认 snaplen 可能截断数据,关键信息丢失。 - 启用环形缓冲 :长时间抓包时用
-C -W或 dumpcap 的-b filesize,避免磁盘写满。 - 多点抓包对比:在客户端、中间设备、服务端分别抓包,对比时序是定位丢包位置的黄金手段。
总结:一张图记住所有
┌─────────────────────────────────────────────────────────────────────┐
│ 运维网络排障工具链 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 应用层 ──→ curl (90% 的问题在这里解决) │
│ ├── -w:精准测量各阶段耗时 │
│ ├── -v:查看详细交互 │
│ └── --trace:保存完整会话 │
│ │
│ 套接字层 ──→ ss (连接状态巡检,1 秒定位) │
│ ├── -tlnp:查看监听端口和进程 │
│ ├── state:按 TCP 状态过滤 │
│ └── -s:汇总统计 │
│ │
│ 传输层/网络层 ──→ tcpdump + tshark (深层排障的双刃剑) │
│ ├── tcpdump:轻量采集、环形缓冲、脚本友好 │
│ └── tshark:深度解析、字段提取、统计丰富 │
│ │
│ 扩展武器库 ──→ mtr (路径质量) / dig (DNS) / nethogs (带宽) │
│ / strace (进程行为) / tcpflow (流重组) │
│ │
└─────────────────────────────────────────────────────────────────────┘
一句话总结:先用 curl 定位问题层次,再用 ss 快速确认连接状态,最后视需要祭出 tcpdump 采集 + tshark 分析。掌握了这套组合拳,你就能在命令行里优雅地搞定绝大多数网络排障任务,再也不用对着 Wireshark 的 UI 发愁。
附录 B:老手一眼就能看出的 TCP 异常信号
这一节是给有经验的运维准备的"直觉速查表"。老手往往看一眼
ss输出中的某个状态、某个数字,就能在几秒内判断问题方向。这些判断力来源于对 TCP 状态机、内核参数和网络协议的深刻理解。
一、TCP 连接状态异常速查
老手排查网络问题,第一件事往往不是抓包,而是先看 ss 的状态分布。某些状态的异常堆积,几乎能直接锁定问题类型。
| 状态 | 正常场景 | 一眼异常的阈值 | 对应的问题 |
|---|---|---|---|
SYN_RECV |
服务器收到 SYN,等待 ACK 完成握手,通常极少量且瞬间消失 | 持续堆积数百条以上 | SYN Flood DDoS 攻击;或半连接队列(默认仅 128)太小导致正常连接也被丢弃 |
SYN_SENT |
客户端发出 SYN,等待服务端 SYN+ACK,通常瞬时状态 | 大量堆积且持续 | 目标端口不通/防火墙丢弃 SYN 包/目标服务挂掉 |
ESTABLISHED |
正常业务连接 | 数量远超业务预期且无应用层数据 | 连接泄漏(应用未关闭连接);CC 攻击(建立连接后不发数据,耗尽连接池) |
TIME_WAIT |
主动关闭方等待 2MSL(约 60 秒) | 数千至上万条 | 短连接过多(HTTP/1.0 频繁建连断连);需启用 tcp_tw_reuse 或改长连接 |
CLOSE_WAIT |
被动关闭方收到 FIN,等待应用调用 close() |
持续堆积且不消失 | 应用代码 Bug :应用未正确调用 close() 关闭 socket |
FIN_WAIT1 / FIN_WAIT2 |
主动关闭方等待对方 FIN 或 ACK | 大量停留在这些状态 | 对端不响应 FIN;网络丢包;防火墙丢弃 FIN 包 |
老手常用命令:
bash
# 快速看状态分布
ss -s
# 按状态精确统计
ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn
# 专门看 SYN_RECV(半连接堆积)
ss -tan state syn-recv | wc -l
# 专门看 CLOSE_WAIT(代码 bug 信号)
ss -tan state close-wait
二、SYN_RECV 大量堆积 = DDoS(老手直觉的第一反应)
老手看到 ss -tan 里有大量 SYN_RECV,第一反应就是:SYN Flood 攻击。
原理: TCP 三次握手中,服务器收到 SYN 后会分配资源(半连接队列、内存缓冲区)并返回 SYN+ACK,然后进入 SYN_RECV 状态等待客户端的 ACK。攻击者利用这种"资源消耗不对称",发送大量伪造源 IP 的 SYN 请求,故意不完成三次握手,耗尽服务器的半连接队列,导致正常请求被丢弃。
老手直觉判断标准:
- Linux 默认半连接队列容量仅 128 (
net.ipv4.tcp_max_syn_backlog) - 如果
SYN_RECV数量持续 > 100 且居高不下 → 极可能是攻击 - 某金融科技公司案例:业务低峰期突增 3 万条 TCP 连接,其中 78% 处于半开状态,最终确认为 SYN Flood
快速验证:
bash
# 看半连接数
ss -tan state syn-recv | wc -l
# 看队列是否溢出(关键证据)
netstat -s | grep -i "SYNs to LISTEN"
# 如果有 "SYNs to LISTEN sockets dropped",说明半连接队列已满,正常请求被丢弃
防御措施:
- 启用 SYN Cookie:
sysctl -w net.ipv4.tcp_syncookies=1(队列满时用加密 Cookie 代替队列存储) - 调大半连接队列:
sysctl -w net.ipv4.tcp_max_syn_backlog=10240
三、CLOSE_WAIT 堆积 = 代码 Bug(老手最常见的发现)
CLOSE_WAIT 是 TCP 状态机中的一个"死穴"------它永远在等应用调用 close()。
老手判断逻辑:
CLOSE_WAIT是被动关闭方(收到对方 FIN)的状态- 如果
CLOSE_WAIT持续堆积且不消失 → 应用代码没有调用close()关闭连接 - 这是应用层 bug,不是网络问题,调内核参数没用,必须改代码
快速定位:
bash
# 看 CLOSE_WAIT 数量
ss -tan state close-wait | wc -l
# 看是哪个进程的 CLOSE_WAIT
ss -tanp state close-wait | grep -i close
四、Recv-Q / Send-Q 队列积压
ss 输出中的 Recv-Q 和 Send-Q 是老手必看的两个数字,一眼就能判断数据流向的瓶颈在哪一端。
| 队列 | 含义 | 正常值 | 异常时的问题 |
|---|---|---|---|
| Recv-Q | 接收缓冲区中待应用读取的数据量 | 0 或极小 | 非零且持续增长:应用处理速度跟不上网络接收速度,应用层有性能瓶颈 |
| Send-Q | 发送缓冲区中待发送的数据量 | 0 或极小 | 非零且持续增长 :网络拥塞、对端接收窗口满(rwnd=0)、或对端应用不读数据 |
老手特别注意: ss -lnt 监听状态的 Recv-Q 含义不同!
对于 LISTEN 状态 的套接字(ss -lnt):
- Recv-Q :当前已完成三次握手、等待应用
accept()的连接数 - Send-Q :该监听套接字的最大全连接队列长度(
min(backlog, somaxconn))
如果 ss -lnt 中某端口的 Recv-Q 接近或等于 Send-Q ,说明全连接队列已满,新连接会被丢弃。这通常是因为应用 accept() 太慢或 backlog 配置太小。
快速诊断命令:
bash
# 检查监听队列是否堆积
ss -lnt | awk 'NR>1 {if ($2>0) print $0}'
# 看内核是否记录队列溢出
netstat -s | grep -i "listen queue"
# "times the listen queue of a socket overflowed" → 全连接队列溢出过
五、常见指标阈值速查
老手对数字非常敏感,以下阈值是经验积累下来的"红线":
| 指标 | 正常/健康范围 | 警告阈值 | 严重阈值 | 含义与排查方向 |
|---|---|---|---|---|
| TCP 重传率 | < 0.1% | > 1% | > 5% | 网络丢包严重/拥塞;检查交换机端口错误计数、网卡丢包、带宽打满 |
| RTT 延迟(内网) | < 1ms | > 5ms | > 10ms | 网络拥塞/路由绕路/交换机排队;用 mtr 看各跳延迟 |
| RTT 延迟(同城公网) | < 5ms | > 20ms | > 50ms | 公网质量波动/路由切换;联系运营商或用 CDN |
| TIME_WAIT 数量 | < 5000 | > 10000 | > 30000 | 短连接过多;考虑启用连接复用或改长连接 |
| 本地端口范围 | 默认约 28K 可用 | > 60% 占用 | > 80% 占用 | TIME_WAIT 耗尽端口;sysctl net.ipv4.ip_local_port_range 扩大范围 |
重传率的快速估算:
bash
# 从内核统计粗略计算(两次采样间隔)
netstat -s | grep "segments retransmited"
TIME_WAIT 的参考值:
- 单个 IP 的可用端口范围约 28,000~65,000 个(取决于
ip_local_port_range) - 如果 TIME_WAIT 数量接近可用端口数的 50%,就应考虑优化
- 可通过扩大端口范围、启用
tcp_tw_reuse、或改用长连接解决
六、案例:一个老手的 30 秒直觉判断
以下是一个典型的真实排障流程,展示老手如何凭直觉快速锁定问题:
背景: 凌晨 3 点接到告警:"用户反馈网站打不开,503 错误"。
老手的 30 秒操作:
bash
# 第 1 秒:看连接状态分布
$ ss -s
Total: 15842
TCP: 15840 (estab 12000, closed 3400, synrecv 520, timewait 3200)
# 第 2 秒:一眼看到 synrecv=520(正常应 < 10)
$ ss -tan state syn-recv | head -5
State Recv-Q Send-Q Local Address:Port Peer Address:Port
SYN-RECV 0 0 10.0.1.10:80 45.xxx.xxx.xxx:12345
SYN-RECV 0 0 10.0.1.10:80 212.xxx.xxx.xxx:54321
...
# 第 10 秒:确认队列溢出
$ netstat -s | grep -i "SYNs to LISTEN"
2347 SYNs to LISTEN sockets dropped
# 第 20 秒:看源 IP 分布,全是随机 IP,无规律
$ ss -tan state syn-recv | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | head
1 103.45.xxx.xxx
1 185.23.xxx.xxx
1 45.132.xxx.xxx
...
结论: SYN Flood 攻击。synrecv=520 远超正常阈值,源 IP 随机分散,且有大量 SYNs dropped 记录。立即启用 SYN Cookie + 调大半连接队列,同时联系云厂商清洗流量。
七、总结:老手的"一眼直觉"口诀
| 看到的 | 第一反应 | 下一步 |
|---|---|---|
SYN_RECV 堆积 |
SYN Flood DDoS | 启用 SYN Cookie,看源 IP 分布 |
CLOSE_WAIT 堆积 |
代码没调 close() |
找开发改代码 |
TIME_WAIT > 1 万 |
短连接太多 | 调内核参数或改长连接 |
Recv-Q(监听)接近 Send-Q |
accept() 太慢 / backlog 太小 |
调大 backlog 或优化应用 |
Recv-Q(已连接)非零 |
应用读数据太慢 | 优化应用处理逻辑 |
Send-Q(已连接)非零 |
网络拥塞 / 对端不读 | 查网络质量、对端应用 |
SYN_SENT 堆积 |
目标不可达 | telnet 测端口,查防火墙 |
| 重传率 > 5% | 网络丢包严重 | 检查网卡/交换机错误计数 |
掌握这些直觉判断,你就拥有了老手排查网络问题的"肌肉记忆"。配合本文正文中的 curl / tcpdump / tshark / ss 完整工具链,绝大多数运维网络故障都能在几分钟内定位根因。