延迟与丢包,Linux 运维的终极狩猎指南

发布于:2025-08-16 ⋅ 阅读:(16) ⋅ 点赞:(0)

 0. 写在前面:为什么你需要“神器”而非“常用命令

有时,诡异的卡顿像雾,贴着屏幕不散:延迟忽高忽低、丢包若隐若现,业务像被无形的手攥着喉咙。别急着把问题归咎于“网络黑洞”,也别一上来就全量重启。把系统当成乐器来调音:哪根弦松了,哪处共振了,靠证据说话。下面这套排查路径与操作清单,落地就能用;每一步都给出命令与模拟输出,尽量还原现场。

一、定位思路:把复杂问题拆成四个问句

  • • 这是端点的问题还是中间路径的问题?(主机栈/网卡 vs. 路由/对端)

  • • 是瞬时拥塞还是持续瓶颈?(尖峰 vs. 稳态)

  • • 是 L2/L3 的物理/MTU/丢包,还是 L4/L7 的重传/排队?

  • • 影响面在哪个范围?(同机房、跨区域、公网)

判断清晰,后面的动作就有了顺序。

二、十分钟“快检”小流程(不改配置,只观察)

1)测端到端延迟分解(连接、TLS、首包、总耗时)

$ curl -sS -o /dev/null -w "code=%{http_code} conn=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n" https://api.example.com/ping
code=200 conn=0.012s tls=0.034s ttfb=0.078s total=0.095s

解读:如果 conn 和 tls 很小,ttfb 突然变高,更多是服务端/上游处理慢;相反,如果 conn 偶发变大,像是网络路径在发脾气。

2)观察 TCP 视角的实时 RTT、重传、拥塞窗口

$ ss -ti '( dport = :443 or sport = :443 )' | head -n 8
ESTAB 0 0 10.0.0.5:52364 203.0.113.10:443
     cubic wscale:7,7 rto:204 rtt:78.2/2.1 ato:40 mss:1448 cwnd:10 retrans:1/19

解读:rtt:78.2/2.1 表示均值/抖动;retrans:1/19 意味 19 个段中有 1 次重传——轻微可接受,持续升高要警惕。

3)端到端路径健康(MTR 同时看延迟与丢包)

$ mtr -ezbw -c 100 api.example.com
Start: 2025-08-10T10:30:00
HOST: app-01
  1.|-- 10.0.0.1           0.2%   100  0.3  0.5  0.2  2.1
  2.|-- 10.0.3.254         0.0%   100  0.7  0.9  0.5  3.0
  3.|-- 172.16.1.1         5.0%   100  2.1  5.6  1.9 20.4
  4.|-- 203.0.113.10       5.0%   100  6.9 12.2  5.7 42.7

解读:第 3、4 跳都有 5% 丢包,可能是第 3 跳开始拥塞或限速;若只有中间节点丢包但末端 0%,可能只是中间设备对 ICMP 限速,不必惊慌。

4)本机是否在丢包(驱动/队列/环形缓冲)

$ ip -s link show dev eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
    RX: bytes  packets  errors  dropped  overrun ...
        8.4G   9.2M     0       5321     0
    TX: bytes  packets  errors  dropped  carrier ...
        7.1G   8.1M     0       0        0

RX dropped 持续增长,多半是收包环溢出/软中断不及

$ ethtool -S eth0 | egrep -i 'drop|err|rx_.*no|fifo' | head
rx_no_buffer: 4873
rx_missed_errors: 0
rx_fifo_errors: 0

5)核对 MTU / Path MTU 黑洞

$ tracepath -n api.example.com | head -n 3
 1?: [LOCALHOST]                                         pmtu 1500
 1:  10.0.0.1
 2:  10.0.3.254                                          pmtu 1500
$ ping -c3 -M do -s 1472 api.example.com
PING ... 1472(1500) bytes of data.
3 packets transmitted, 3 received, 0% packet loss, time 2004ms

如果 1472 成功而更大失败,说明 PMTU 正常;如果连 1472 都不通且小包通,怀疑中间设备丢弃“不可分片”ICMP——典型 PMTUD 黑洞


三、系统层面证据:把“感觉慢”变成“数字指纹”

1)丢包与重传的全局计数

$ nstat -az | egrep 'TcpRetransSegs|IpInDiscard|IpInDelivers|UdpInErrors'
TcpRetransSegs                 321
IpInDiscard                    57
UdpInErrors                    0
$ sar -n DEV,EDEV 1 3
11:20:01 AM  IFACE   rxpck/s  txpck/s   rxerr/s  txerr/s  rxdrop/s  txdrop/s
11:20:02 AM  eth0     15234    13012     0.00     0.00      5.00      0.00

rxdrop/s 持续不为 0,就是主机侧接收丢包

2)软中断与 ksoftirqd 压力

$ top -H -b -n1 | sed -n '1,15p'
%Cpu(s): 12.3 us, 7.8 sy, 0.0 ni, 60.0 id, 0.0 wa, 19.7 si, 0.2 st

si(softirq)高企 + ksoftirqd/* 线程靠前,提示中断风暴/大流量抢占 CPU

$ cat /proc/softirqs | sed -n '1,12p'
                    CPU0       CPU1
NET_RX:          1234567     345678
NET_TX:           234567     123456

3)队列、qdisc 与 bufferbloat 线索

$ tc qdisc show dev eth0
qdisc pfifo_fast 0: root refcnt 2 bands 3 priomap ...

pfifo_fast 在突发场景容易排队膨胀→高延迟。后面给出切换 fq_codel 的方法。


四、常见根因与修复动作(带“如何验证”)

以下调整尽量先在非生产验证,再按变更流程施行。涉及内核网络栈的修改,建议先单机灰度、再扩大范围。

A. 接收环/软中断处理不过来 → 调整网卡 ring / RPS / 中断亲和

1)查看并适度增大 ring buffer(硬件/驱动允许时):

$ ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096
Current hardware settings: RX: 512 TX: 512

$ sudo ethtool -G eth0 rx 2048 tx 1024

2)打散软中断到多核(RPS/RFS 示例):

# 为 eth0 的队列设置 RPS 掩码(示例掩码 0x3 -> 使用 CPU0/CPU1)
$ echo 3 | sudo tee /sys/class/net/eth0/queues/rx-0/rps_cpus

3)验证:sar -n EDEV 1 的 rxdrop/s 应下降,ss -ti 的 retrans 趋于稳定。


B. MTU/PMTUD 黑洞 → 统一 MTU 或在边界做 MSS Clamp

1)找出异常路径(大包不通):

$ ping -c3 -M do -s 1472 api.example.com  # 1500 测试
$ ping -c3 -M do -s 8972 api-internal.example.com  # 如果内部是 9000 jumbo

2)临时缓解(网关上钳制 MSS 到路径 MTU):

# iptables 版本
$ sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

# nftables 版本(推荐新系统)
$ sudo nft add rule inet filter forward tcp flags syn tcp option maxseg size set clamp-to-pmtu

3)长期修复:统一子网 MTU(云上常见 1500/9001 混用),或打通 ICMP “需要分片但 DF 置位”的返回。
4)验证:tracepath pmtu 稳定、业务大包传输不再超时。


C. Bufferbloat(排队膨胀)→ 切换到 FQ-CoDel / 启用 BBR

1)切换默认队列为 fq_codel(减少排队延迟):

$ echo 'net.core.default_qdisc=fq_codel' | sudo tee -a /etc/sysctl.conf
$ sudo sysctl -p
$ tc qdisc replace dev eth0 root fq_codel

2)启用更友好的拥塞控制(BBR,内外网要兼容):

$ echo 'net.ipv4.tcp_congestion_control=bbr' | sudo tee -a /etc/sysctl.conf
$ sudo sysctl -p
$ sysctl net.ipv4.tcp_available_congestion_control
net.ipv4.tcp_available_congestion_control = cubic reno bbr

3)验证:长流下 ss -ti 的 rtt 抖动收敛、tc -s qdisc 中 drops 不再持续增长;端到端 curl -w 总时延下降。


D. CPU 上不来(软中断与用户态争抢) → 中断亲和/多队列/NUMA 绑核

1)将 NIC 队列中断绑定到不同 CPU,避免全集中在 CPU0:

$ grep eth0-TxRx /proc/interrupts
 57:  123456  IR-PCI-MSI  eth0-TxRx-0
 58:   98765  IR-PCI-MSI  eth0-TxRx-1

# 把中断 57 绑到 CPU0,58 绑到 CPU1
$ echo 1  | sudo tee /proc/irq/57/smp_affinity_list
$ echo 2  | sudo tee /proc/irq/58/smp_affinity_list

2)开启 RSS/多队列收发(硬件支持时):

$ ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums: RX: 8 TX: 8
Current hardware settings: RX: 2 TX: 2

$ sudo ethtool -L eth0 combined 4

3)验证:/proc/interrupts 分布均衡,si% 降低,rxdrop/s 收敛。


E. 防火墙/ACL/限速导致 ICMP 或端口间歇丢包 → 用 TCP MTR 与计数器证据

1)当 ICMP 被限速时,用 TCP 探测:

$ mtr -ezbw -c 50 -T -P 443 api.example.com

2)检查本机防火墙计数器(哪个规则在吞噬包):

# iptables
$ sudo iptables -L -v -n | head -n 20
Chain INPUT ...
  pkts bytes target prot opt in out source destination

# nftables
$ sudo nft list ruleset | sed -n '1,80p'

3)验证:放宽或修正规则后,curl -wmtr 的丢包恢复正常。


F. 服务器端处理慢被误判为“网络慢” → 从 TCP 层拆分时间

1)观察 RTT 正常但 ttfb 高,说明网络不是主因:

$ ss -ti state established '( dport = :443 )' | head -n 6
ESTAB ... rtt:8.1/1.2 retrans:0 ...

2)对服务端做“冷热点”确认:磁盘 IO、上游依赖、线程池。网络排除后,把精力放回应用。


G. UDP 抖动/丢包(实时音视频/日志投递) → 用 iperf3 的 UDP 模式

# 目标端
$ iperf3 -s
# 源端
$ iperf3 -u -b 200M -l 1200 -c 203.0.113.10 -t 30
[  5]  0.00-30.00 sec  690 MBytes  193 Mbits/sec  1.2%  3.45 ms  4.12 ms  12.1 ms

抖动(jitter)与丢包率直观呈现;调低速率/分片长,观察阈值点。


五、应用一体化验证:别只看网络,要对业务负责

1)HTTP 探活与 95/99 分位延迟

$ for i in {1..50}; do curl -s -o /dev/null -w "%{time_total}\n" https://api.example.com/ping; done | awk '
{p[NR]=$1} END{
  n=asort(p); 
  p95=p[int(0.95*n)]; p99=p[int(0.99*n)];
  printf("p95=%.3fs p99=%.3fs\n", p95, p99)
}'
p95=0.112s p99=0.148s

2)TCP 连接失败率(应用可感知)

$ journalctl -u myapp -n 200 --no-pager | egrep -i 'ECONNRESET|ETIMEDOUT|EHOSTUNREACH' | wc -l
3

把“连接错误数/请求数”纳入监控,比肉眼追日志可靠。


六、常见“坑位图库”(你大概率会遇到)

  • • 云环境混用 MTU:VPC 内 1500,与跨 AZ/专线 9001,跨边界丢包。

  • • 容器与宿主 MTU 不一致:CNI 默认 1450,宿主 1500,外链 GRE/VXLAN 叠加——用 tracepath 查清楚。

  • • 驱动 Bug/固件老旧dmesg | grep -i 'NETDEV WATCHDOG'link down/up 抖动;升级内核/驱动是最稳的解。

  • • 队列默认 pfifo_fast:峰值时 RTT 爆炸;切 fq_codel 往往立竿见影。

  • • ICMP 被彻底屏蔽ping 不通≠服务不通,谨记用 mtr -T 与 curl -w 双证据。

  • • conntrack 被打满:连接瞬时飙升,nf_conntrack_count 接近 max,丢包像退潮一样整片消失;调上限/调超时/分流是治本。

$ cat /proc/sys/net/netfilter/nf_conntrack_count
1048575
$ cat /proc/sys/net/netfilter/nf_conntrack_max
1048576

七、演练脚本(非侵入,只读采样)——一次跑完抓关键证据

仅采集,不更改系统;可在跳板机或业务机执行。请根据安全规范保存输出。

#!/usr/bin/env bash
# 名称:net-quickcheck.sh(只读体检)
set -euo pipefail
TARGET="${1:-api.example.com}"
PORT="${2:-443}"
COUNT="${3:-100}"

echo"=== curl timing (${TARGET}) ==="
curl -sS -o /dev/null -w "code=%{http_code} conn=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n""https://${TARGET}:${PORT}" || true

echo -e "\n=== TCP sockets RTT/retrans (sample) ==="
ss -ti "( dport = :${PORT} or sport = :${PORT} )" | sed -n '1,20p' || true

echo -e "\n=== mtr (${COUNT} cycles) ==="
command -v mtr >/dev/null && mtr -ezbw -c "${COUNT}" -T -P "${PORT}""${TARGET}" || echo"mtr not found"

echo -e "\n=== interface drops (ip -s link) ==="
ip -s link | sed -n '1,200p'

echo -e "\n=== NIC stats (ethtool -S) ==="
command -v ethtool >/dev/null && ethtool -S eth0 2>/dev/null | egrep -i 'drop|err|fifo|nobuf' || echo"ethtool or stats not available"

echo -e "\n=== stack counters (nstat) ==="
command -v nstat >/dev/null && nstat -az | egrep 'TcpRetransSegs|IpInDiscard|UdpInErrors' || echo"nstat not found"

echo -e "\n=== qdisc ==="
tc qdisc show dev eth0 || true

echo -e "\n=== PMTU / tracepath(5 hops) ==="
command -v tracepath >/dev/null && tracepath -n "${TARGET}" | sed -n '1,5p' || echo"tracepath not found"

echo -e "\n=== conntrack usage (if present) ==="
for f in /proc/sys/net/netfilter/nf_conntrack_{count,max}; do [[ -r "$f" ]] && echo"$f: $(cat $f)"; done

模拟运行输出节选

=== curl timing (api.example.com) ===
code=200 conn=0.010s tls=0.031s ttfb=0.082s total=0.096s

=== TCP sockets RTT/retrans (sample) ===
ESTAB ... rtt:81.2/3.1 mss:1448 cwnd:10 retrans:2/47

=== interface drops ===
RX ... dropped 120  overrun 0
TX ... dropped 0    carrier 0

=== qdisc ===
qdisc pfifo_fast 0: root refcnt 2 bands 3 priomap ...

八、变更动作“口袋卡”(需要审批的改动,给出最小化命令)

建议:先一台机器灰度、收集指标、再推广。

  • • 切换队列调度器:

    sudo tc qdisc replace dev eth0 root fq_codel
  • • 启用 BBR:

    echo 'net.ipv4.tcp_congestion_control=bbr' | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
  • • 调整 ring:

    sudo ethtool -G eth0 rx 2048 tx 1024
  • • RPS 打散:

    echo 3 | sudo tee /sys/class/net/eth0/queues/rx-0/rps_cpus
  • • MSS 钳制(PMTU 黑洞缓解):

    sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
    # 或 nft 同等规则

九、复盘与固化:把“偶发事故”变成“可预期的物理量”

  • • 监控层面加入:rtt/ttfbTcpRetransSegs/sip -s link droppedconntrack 使用率mtr 可视化

  • • 发布变更时标注 MTU/队列算法/拥塞控制与版本。

  • • 每季度做一次“网络劣化演练”(tc netem 注入延迟与丢包),验证应用的超时/重试策略是否健壮。

示例(仅在演练环境):

# 模拟 50ms 延迟和 1% 丢包
$ sudo tc qdisc add dev eth0 root netem delay 50ms loss 1%
# 还原
$ sudo tc qdisc del dev eth0 root

尾声

网络像一条看不见的河,水势有枯有涌。延迟与丢包不是神秘学,它们有迹可循,有数可证。把“快检”放在指尖,把“证据”刻进流程,把“修复”做成可回滚的变更。这样,当下次雾起时,你会更早看见河床的纹理,而不是被水声吓倒。

老杨时间

这里我先声明一下,日常生活中大家都叫我波哥,跟辈分没关系,主要是岁数大了.就一个代称而已.
我的00后小同事我喊都是带哥的.张哥,李哥的.
但是这个称呼呀,在线下参加一些活动时.金主爸爸也这么叫就显的不太合适.
比如上次某集团策划总监,公司开大会来一句:“今个咱高兴!有请IT运维技术圈的波哥讲两句“
这个氛围配这个称呼在互联网这行来讲就有点对不齐!
每次遇到这个情况我就想这么接话: “遇到各位是缘分,承蒙厚爱,啥也别说了,都在酒里了.我干了,你们随意!”
所以以后咱们改叫老杨,即市井又低调.还挺亲切,我觉得挺好.

运维X档案系列文章:

从告警到CTO:一个P0故障的11小时生死时速

企业级 Kubernetes 集群安全加固全攻略( 附带一键检查脚本)

点击原文链接访问实时vps信息查询及小工具汇聚项目

老杨的关于AI的号


网站公告

今日签到

点亮在社区的每一天
去签到