网络栈全景

Linux 内核的网络数据处理路径:

网卡驱动 → SoftIRQ → Netfilter → Socket Buffer → 应用层
   │                              │
   │                              └── sk_buff 管理
   └── Ring Buffer / NAPI

性能瓶颈可能出现在任何一层。调优的本质就是找到并消除这些瓶颈。

第一层:网卡与 Ring Buffer

查看网卡信息

# 查看网卡型号和驱动
ethtool -i eth0

# 查看 Ring Buffer 大小
ethtool -g eth0

# 查看网卡统计(看是否有丢包)
ethtool -S eth0 | grep -i drop

调整 Ring Buffer

# 增大 Ring Buffer(单位: descriptor 数量)
ethtool -G eth0 rx 4096 tx 4096

# 启用自适应中断
ethtool -C eth0 adaptive-rx on adaptive-tx on

# 查看当前设置
ethtool -c eth0

多队列网卡

# 查看队列数
ethtool -l eth0

# 设置队列数(等于 CPU 核心数)
ethtool -L eth0 combined 4

# 将队列绑定到 CPU
# 中断号通过 /proc/interrupts 查找
echo 2 > /proc/irq/IRQ_NUM/smp_affinity  # 绑定到 CPU1

第二层:SoftIRQ 与 NAPI

SoftIRQ 处理网络收包。如果单个 CPU 核心处理不过来,就会成为瓶颈。

监控 SoftIRQ

# 查看 SoftIRQ 分布
cat /proc/softirqs | grep NET_RX

# 查看是否有 CPU 瓶颈
mpstat -P ALL 1

调整 NAPI

# 增加 NAPI 权重(让每个 SoftIRQ 处理更多包)
sysctl -w net.core.netdev_budget=600
sysctl -w net.core.netdev_budget_usecs=8000

第三层:Socket 缓冲区

核心参数

# /etc/sysctl.d/99-network-tuning.conf

# --- 接收缓冲区 ---
# 最小值、默认值、最大值(字节)
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.udp_rmem_min = 8192

# --- 发送缓冲区 ---
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.udp_wmem_min = 8192

# --- 全局缓冲区 ---
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 1048576
net.core.wmem_default = 1048576
net.core.optmem_max = 2048

理解自动调优

Linux 内核会根据拥塞窗口自动调整 TCP 缓冲区大小。设置的 min/max 定义了自动调优的范围:

实际缓冲区 = clamp(自动调优值, min, max)

对于高带宽长距离连接(BDP 大),需要更大的缓冲区:

BDP = Bandwidth × RTT
示例: 1Gbps × 100ms = 12.5MB

验证缓冲区使用

# 查看当前连接的缓冲区使用
ss -tm
# ss 输出中的 skmem:(r0,rbX,t0,tbX) 表示接收/发送缓冲区

第四层:TCP 连接管理

连接队列

# SYN 半连接队列
net.ipv4.tcp_max_syn_backlog = 65536

# 已完成连接等待 accept 的队列
net.core.somaxconn = 65536

# 本地端口范围
net.ipv4.ip_local_port_range = 1024 65535

连接回收

# TIME_WAIT 复用
net.ipv4.tcp_tw_reuse = 1

# FIN-WAIT-2 超时(秒)
net.ipv4.tcp_fin_timeout = 15

# Keepalive 参数
net.ipv4.tcp_keepalive_time = 600    # 空闲多久开始探测
net.ipv4.tcp_keepalive_intvl = 15    # 探测间隔
net.ipv4.tcp_keepalive_probes = 5    # 探测次数

SYN Flood 防护

# 启用 SYN Cookie(SYN 队列满时启用)
net.ipv4.tcp_syncookies = 1

# SYN+ACK 重试次数
net.ipv4.tcp_synack_retries = 2

# SYN 重试次数
net.ipv4.tcp_syn_retries = 3

第五层:拥塞控制

BBR 算法

BBR(Bottleneck Bandwidth and Round-trip propagation time)是 Google 开发的拥塞控制算法,基于带宽和延迟建模,而非丢包:

# 设置 BBR 为默认算法
sysctl -w net.core.default_qdisc=fq
sysctl -w net.ipv4.tcp_congestion_control=bbr

# 永久生效
cat >> /etc/sysctl.d/99-network-tuning.conf << EOF
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
sysctl -p /etc/sysctl.d/99-network-tuning.conf

验证 BBR 是否生效

# 查看当前拥塞控制算法
sysctl net.ipv4.tcp_congestion_control

# 查看 BBR 统计
sysctl net.ipv4.tcp_bbr

# 查看内核支持的算法
sysctl net.ipv4.tcp_available_congestion_control

BBR v2

BBR v2 改善了与基于丢包的算法(如 Cubic)的共存性:

# 如果内核支持 BBR v2
modprobe tcp_bbr2
sysctl -w net.ipv4.tcp_congestion_control=bbr2

第六层:其他优化

TCP Fast Open

允许在 SYN 报文中携带数据,减少一次 RTT:

# 服务端启用 TFO
net.ipv4.tcp_fastopen = 3

# 服务端 TFO 队列长度
net.ipv4.tcp_fastopen_key = random

MTU 发现

# 启用路径 MTU 发现
net.ipv4.ip_no_pmtu_disc = 0

# 查看路径 MTU
ip route get 8.8.8.8

ECN(显式拥塞通知)

# 启用 ECN
net.ipv4.tcp_ecn = 1

监控工具集

# 实时监控连接状态
watch -n1 'ss -ant | awk "{print \$1}" | sort | uniq -c | sort -rn'

# 网络流量监控
iftop -i eth0

# 连接追踪表
conntrack -L -o extended | head -20

# 内核网络统计
nstat -az | grep -i tcp

# 完整的网络栈监控脚本
sar -n DEV 1

调优检查清单

参数默认值推荐值说明
tcp_rmem4096 1310724096 87380 16777216TCP 接收缓冲区
tcp_wmem4096 163844096 65536 16777216TCP 发送缓冲区
somaxconn12865536监听队列
tcp_max_syn_backlog25665536SYN 队列
tcp_tw_reuse01TIME_WAIT 复用
tcp_fin_timeout6015FIN 超时
default_qdiscpfifo_fastfq队列调度
congestion_controlcubicbbr拥塞控制

总结

网络调优不是堆参数,而是理解每一层的工作机制,根据实际场景做出针对性调整。先监控找到瓶颈,再调优验证效果。