11_带宽低如何排查
约 1499 字大约 5 分钟
2026-02-24
一、排查目标
当服务器带宽跑不满或明显低于预期时,本指南用于:
- 快速判断是否真的存在流量需求
- 判断是否为主机资源瓶颈
- 判断是否为网络链路问题
- 明确是否需要联系运营商或上游
二、核心原则
带宽低 = 需求不足 或 处理能力不足 或 链路受限
排查顺序必须从内到外。
三、快速检查清单(概览)
- 是否真的有业务流量?
- 主机是否达到资源瓶颈?
- 网卡是否限速或异常?
- TCP 是否存在丢包/重传?
- 上游链路是否存在丢包或拥堵?
四、详细排查流程
Step 1:确认是否真的有流量需求
很多“带宽低”问题,本质是没有流量。
1.1 服务是否在运行
docker ps
docker stats确认:
- 容器是否 UP
- CPU 是否有实际消耗
- 是否存在 OOM
1.2 当前连接情况
关于连接数的正确理解
- TCP 是面向连接协议 → 有连接状态
- UDP 是无连接协议 → 协议层面没有“连接数”
- Linux 内核允许 UDP 使用
connect(),但这只是内核行为,不是协议连接
查看当前 TCP 状态
ss -s
ss -ant | wc -l⚠️ 修正说明:
ss -anut | wc -l 统计的是 socket 数量,不完全等于“真实连接数”。
更准确的是:
ss -ant state established | wc -l判断逻辑
- TCP 连接数接近 0 → 基本无流量
- 连接数正常但带宽低 → 可能单连接速率低
- 检查业务高峰时间是否匹配当前时间
1.3 实时流量
sar -n DEV 1 10关注:
- rxkB/s
- txkB/s
如果几乎为 0,优先确认是否真的切量。
Step 2:主机资源是否成为瓶颈
如果确认有流量,但带宽跑不高,检查主机系统资源。
2.1 CPU / 内存 / IO
vmstat 1
top重点关注:
- us / sy 是否接近 100%
- wa 是否高(IO wait)
- load 是否远高于 CPU 核数
常见误区修正
❌ CPU 高一定丢包 → 不一定,只有在内核处理不过来时才可能丢包
❌ CPU 低就一定没问题 → 可能单线程程序卡死在一个核
2.2 单线程瓶颈
常见问题:
- nginx worker 数过少
- Java 线程池限制
- Node.js 单线程模型
- 单连接窗口限制
现象:
- 总 CPU 很低
- 某一个核 100%
2.3 网卡速率检查
ethtool eth0确认:
- Speed 是否 25000Mb/s / 10000Mb/s
- 是否降速到 1000Mb/s
- 是否 Full Duplex
2.4 网卡统计
ethtool -S eth0查看:
- rx_errors
- tx_errors
- dropped
- fifo_errors
如果 error 增长,说明硬件或驱动问题。
2.5 中断是否均衡(科普)
cat /proc/interrupts观察:
- 是否某一个 CPU 中断数远高于其他核心
- 是否只集中在 CPU0
如果严重不均衡:
- 检查是否开启 RSS(多队列)
- 检查 RPS 是否配置
RSS(硬件多队列)
ls /sys/class/net/eth0/queues/存在多个 rx-* → 支持多队列
RPS(软件分流)
适用于单队列网卡,但会消耗 CPU
Step 3:网络链路排查
如果主机没问题,开始检查网络质量。
3.1 丢包与延迟
ping 对端IP
mtr 对端IP判断逻辑:
- 同机房丢包 → 本地网络问题
- 出口丢包 → 可能运营商问题
3.2 TCP 重传
sar -n TCP,ETCP 1 5关键字段:
- retrans/s
- oseg/s
- iseg/s
重传率计算方式:
genui{"math_block_widget_always_prefetched":{"content":"retransmission_rate = retrans_segments / total_sent_segments"}}
经验判断:
- < 0.1% → 正常
- 0.1%~1% → 需要观察
1% → 明显异常
5% → 严重丢包
不能简单说“重传率高就一定是运营商问题”,也可能是:
- 本机网卡丢包
- 中断不均衡
- 内核参数过小(如 tcp_rmem)
- 防火墙丢弃
3.3 socket 统计
ss -s关注:
- retrans
- orphan
- timewait
3.4 使用 iperf 做对测
必须:
- 两端机器对测
- 同运营商
- 同机房
如果 iperf 跑满:
→ 说明链路没问题,问题在应用
如果 iperf 也跑不满:
→ 基本是网络或出口瓶颈
Step 4:出口或上游是否超售
可能情况:
- 总出口 100G
- 实际卖出 200G
- 高峰期拥堵
表现:
- 晚上高峰带宽下降
- 白天正常
五、标准 SOP
- 确认是否已切流量
- 查看 TCP 连接数
- 查看实时流量
- 查看 CPU / IO / load
- 查看网卡速率与 error
- 查看 TCP 重传
- 对测 iperf
- 再决定是否找运营商
CDN服务器的完整数据流
接入有一台CDN机器,跑的是UDP服务,这台机器从收到请求到发出数据的完整路径:
用户请求 (UDP)
│
▼
┌─────────────────┐
│ 网卡 │ 10Gbps
│ RX 接收队列 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 内核协议栈 │ 解析 UDP 包
│ Socket 接收 │ → 投递到 btvdp 进程
└────────┬────────┘
│
▼
┌─────────────────┐
│ btvdp 进程 │ 解析请求:用户要哪个视频片段?
│ (应用层逻辑) │
└────────┬────────┘
│
┌────────┴────────┐
│ 查找数据在哪里? │
└────────┬────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌────────────┐ ┌──────────┐ ┌──────────┐
│ L1: 进程内 │ │ L2: Page │ │ L3: 磁盘 │
│ 用户态缓存 │ │ Cache │ │ (SSD) │
│ (~20GB/ │ │ (内核管理│ │ │
│ 进程) │ │ ~12GB) │ │ │
└─────┬──────┘ └────┬─────┘ └────┬─────┘
│ │ │
命中直接返回 命中:内存 未命中:
零拷贝发送 拷贝,快 触发磁盘读
│ │ │
│ │ ▼
│ │ ┌──────────────────┐
│ │ │ 磁盘I/O子系统 │
│ │ │ │
│ │ │ 应用 read()/mmap()│
│ │ │ ↓ │
│ │ │ VFS → 文件系统 │
│ │ │ ↓ │
│ │ │ Block Layer │
│ │ │ (I/O调度,合并) │
│ │ │ ↓ │
│ │ │ SCSI/SATA驱动 │
│ │ │ ↓ │
│ │ │ 物理SSD读取 │
│ │ │ (~0.5ms/请求) │
│ │ └────────┬─────────┘
│ │ │
│ │ 数据读入内存
│ │ │
└─────────────┼──────────────┘
│
▼
┌─────────────────┐
│ 数据在内存中了 │
│ │
│ UDP 响应包 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Socket 发送缓冲区│ ← 如果满了,UdpSndbufErrors++
└────────┬────────┘ (丢包就发生在这里!)
│
▼
┌─────────────────┐
│ 内核协议栈 │
│ 添加UDP/IP头 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 网卡 TX 发送队列 │
│ DMA 发送 │
└────────┬────────┘
│
▼
发给用户 📡
关键问题在 L3 磁盘读取 这一步。如果用户请求到达内容没有命中内存的话,就需要去磁盘里面调度,这就造成了额外的开销,想CDN服务器,比如说抖音这种,大量的用户发起随机的UDP包,对磁盘的读取速度就造成了非常大的压力。 单位时间内没有能从磁盘调度出来的数据,就在Socket发送缓冲区被丢弃了
