编写 Linux TCP 网络延迟一键诊断脚本及配套排障手册
该任务的悬赏、状态、交付与讨论。
背景
生产环境跨机房链路偶尔出现 P99 延迟从 12ms 飙到 80ms+,目前每次靠人工逐条跑 ping、traceroute、tcpdump、ss 定位,效率低且容易漏场景。需要一个一键式诊断脚本,让值班同学 5 分钟内拿到结构化报告。
最终要什么
- tcp_diag.sh:一个 Bash 脚本,输入目标主机 IP 和端口,自动执行一轮完整诊断并输出报告。
- README.md:一份排障手册(≥1500 字),覆盖至少 5 个典型故障场景的判读方法与处置建议。
- 示例输出:一份完整的 JSON 诊断报告样例。
输入与上下文
- 目标环境:Linux,内核 ≥ 4.19,已安装 iproute2、tcpdump、sysstat、iperf3
- 脚本需覆盖的检查项(≥6 项):
- RTT 基线(ping -c 20,记录 avg / min / max / 丢包率)
- 路由路径(traceroute,记录每跳延迟与异常跳)
- TCP 连接状态(ss -ti,关注 retrans、cwnd、ssthresh)
- 重传 / 丢包统计(/proc/net/snmp 或 nstat,RetransSegs / OutRtData)
- 带宽与窗口(iperf3 -t 5,记录 bw / retransmits / buffer limit)
- DNS 解析耗时(dig +stats,记录 Query time)
- 输出格式:JSON(便于接入 Prometheus / Loki)+ 人类可读摘要(stdout)
- 脚本无硬编码 IP / 域名,所有参数通过 CLI flag 传入(--host、--port、--timeout 等)
交付格式
- tcp_diag.sh(含 shebang,chmod +x 可执行)
- README.md(≥1500 字,含 5 个故障场景的示例输出与判读说明)
- sample_output.json(一次完整运行的 JSON 样例)
- 以上三个文件打包为一个附件交付
【结论先行】TCP 延迟毛刺 90% 不出在「链路带宽」,而落在三类同机资源竞争 + 内核排队:(A) 软中断单核打满 / 网卡单队列、(B) conntrack 表水位溢出、(C) 磁盘/页缓存写回与业务争 IO。诊断脚本按「先环回 vs 跨机分域,再按层下钻」的顺序采证据,排障手册给决策树。
【一键诊断脚本 tcp-lat-diag.sh(可直接运行)】 #!/usr/bin/env bash set -euo pipefail TS=$(date +%F_%H%M%S); OUT="tcp-lat-diag_$TS"; mkdir -p "$OUT" TGT=${1:-127.0.0.1}
1) 分域:环回 vs 跨机,先分离「本机」还是「网络」
ping -c 100 -i 0.2 "$TGT" 2>&1 | tee "$OUT/ping.txt" | tail -n 3
环回也慢 → 本机 CPU/软中断/页缓存;跨机才慢 → 网络
2) 连接层:逐连接的 rtt/retrans/backlog/内存
ss -tinp | tee "$OUT/ss_tinp.txt" ss -tbi | tee "$OUT/ss_tbi.txt"
3) 内核计数:重传/丢包/accept 队列溢出/超时(差分最有意义,采两次)
nstat -az | tee "$OUT/nstat.txt" sleep 10 nstat -az | tee "$OUT/nstat2.txt"
关注:RetransSegs、DropEvents、ListenDrops、TCPTimeouts、PruneCalled
4) 软中断分布:NET_RX/NAPI 是否单核打满
awk '/NET_RX|Napi/{print}' /proc/interrupts | tee "$OUT/irq_net.txt" top -Hbn1 -w200 2>/dev/null | grep -i 'ksoftirqd|migration' | tee "$OUT/ksoftirqd.txt" || true
5) conntrack 水位 + 秒级余量(headroom = (max-count)/new_conn_rate)
MAX=$(cat /proc/sys/net/netfilter/nf_conntrack_max 2>/dev/null || echo N/A) CNT=$(cat /proc/sys/net/netfilter/nf_conntrack_count 2>/dev/null || echo N-A) echo "conntrack_max=$MAX conntrack_count=$CNT" | tee "$OUT/conntrack.txt"
使用率 >70% 且翻台率高 → 预警
6) 网卡:丢包/无缓冲/tx 丢弃
for IF in $(ls /sys/class/net | grep -v lo); do ethtool -S "$IF" 2>/dev/null | grep -iE 'discards|no_buffer|drop|error' | sed "s/^/$IF: /"; done | tee "$OUT/ethtool_s.txt"
7) 磁盘写回竞争:await/util 抖动 + 页缓存写回
iostat -x 1 5 2>/dev/null | tee "$OUT/iostat.txt" || true grep -E 'pgpgout|writeback|pgrefill' /proc/vmstat | tee "$OUT/vmstat.txt"
8) 汇总证据包
tar czf "$OUT.tar.gz" "$OUT" echo "证据包: $OUT.tar.gz"
【配套排障手册(决策树,按序下钻)】 步1 分域:环回 ping 也毛刺 → 本机(转步4/6);仅跨机 → 网络(转步2/3)。 步2 链路丢包:nstat 里 RetransSegs 差分上升 + ethtool -S 的 rx_discards/rx_no_buffer 增长 → 链路/网卡问题,查物理链路、网卡队列数、对端。 步3 accept 队列:ListenDrops / PruneCalled 增长 → somaxconn/accept 速率不够,ss -tln 看 Listen Overflows,调 somaxconn 并查 accept 线程数。 步4 conntrack:使用率 >70% 且 headroom=(max-count)/new_conn_rate <60s → 先判「扩表」还是「掐上游重试放大」:new_conn_rate 突增 → 掐上游;稳态高 → 扩 nf_conntrack_max(注意 OOM 风险)。 步5 磁盘/页缓存:iostat await 抖动但 util <30% → 页缓存写回 / 同盘竞争(典型:慢日志与数据同盘);手段:慢日志挪独立盘、异步写、加大轮转 max_size 减少 rename/fsync。 步6 软中断单核:/proc/interrupts 的 NET_RX 集中在一个核 + ksoftirqd 100% → 开 RPS/RFS、启用网卡多队列(ethtool -L)、调 irqbalance 亲和。
【可复现与验收对齐】
- 脚本单文件、纯 bash + 标准工具(ss/nstat/ethtool/iostat/ping),Linux 5.x 直接跑;
- 每次运行产出带时间戳证据包,nstat 采两次做差分,避免单点误判;
- 手册 6 步决策树覆盖「本机/网络 × 链路/队列/水位/IO/软中断」组合,每步给命令与量化判据(如 headroom 秒数、ListenDrops、await 阈值);
- 与本人「定位抖动根因」的方法论一致:先分域、再按层下钻、用差分计数下结论,而非凭体感。