网络是分布式系统的"血液循环系统"。它不像CPU和内存那样在单机内闭环——网络问题往往涉及多个节点、多个路由、多种协议。诊断网络性能,需要的是"端到端"的系统性思维。
第6章 网络性能分析:追踪每一毫秒的去向
6.1 故事:跨机房迁移后的"神秘延迟"
2024年5月,某电商平台将核心服务从A机房迁移到B机房。迁移完成后,压测显示:同机房调用延迟5ms,跨机房调用延迟120ms。
"物理距离增加了30公里,延迟多了115ms?光速30公里只需要0.1ms,这说不通。"网络工程师小陈皱眉。
他开始逐层排查。
第一步:ping测试
ping -c 100 api-server-b
# rtt min/avg/max/mdev = 1.234/1.456/2.890/0.345 ms网络层延迟只有1.5ms,不是网络距离问题。
第二步:TCP握手时间
tcpdump -i eth0 host api-server-b and port 8080 -w capture.pcap
# 用wireshark分析:
# SYN → SYN+ACK = 1.5ms(正常)
# 但 SYN+ACK → ACK = 45ms(异常!)客户端收到SYN+ACK后,花了45ms才发ACK。为什么?
第三步:深挖客户端
ss -ti '( dport = :8080 )'
# tcp ESTAB 0 0 10.0.1.2:54321 10.0.2.3:8080
# ts sack cubic wscale:7,7 rto:201 rtt:1.456/0.345 mss:1448 cwnd:10 ...注意到 cwnd:10——拥塞窗口只有10个MSS(约14KB)。而服务端一次响应就80KB,需要6个RTT才能传完。
第四步:定位根因
B机房的LB(负载均衡器)配置了一个"安全"的TCP初始拥塞窗口限制:10。A机房的是系统默认值(Linux 4.x之后是10,但之前是2-4)。等等,两边都是10?
继续查,发现B机房的防火墙对TCP窗口缩放(window scaling)选项进行了修改,导致实际可用的窗口比协商的更小。
根因:防火墙修改TCP选项 → 实际窗口小于协商窗口 → 大量小数据包传输 → 延迟飙升。
修复:调整防火墙策略,保留TCP窗口缩放选项。跨机房延迟降到6ms。
6.2 TCP/IP协议栈
数据包旅程
flowchart TD
A["应用程序"] -->|"send()"| B["Socket层"]
B --> C["TCP层"]
C --> D["IP层"]
D --> E["网卡驱动"]
E --> F["Ring Buffer"]
F --> G["网卡硬件"]
G --> H["网络"]
C -->|"连接管理"| I["三次握手"]
C -->|"可靠性"| J["ACK/重传"]
C -->|"流量控制"| K["滑动窗口"]
C -->|"拥塞控制"| L["CUBIC/BBR"]
style C fill:#e8f5e9
style H fill:#ffebeeTCP三次握手与性能
sequenceDiagram
participant C as 客户端
participant S as 服务端
C->>S: SYN
Note over C,S: 1 RTT
S-->>C: SYN+ACK
Note over C,S: 1 RTT
C->>S: ACK + DATA
Note over C,S: 数据传输开始
Note right of C: TCP Fast Open (TFO)
允许在SYN包中携带数据
减少1 RTTRTT(Round Trip Time)是网络性能的核心。 优化TCP性能,本质上就是减少RTT或提高每RTT的传输量。
6.3 网络性能指标
flowchart TD
A["网络性能"] --> B["延迟 Latency"]
A --> C["带宽 Bandwidth"]
A --> D["吞吐量 Throughput"]
A --> E["丢包率 Loss"]
A --> F["抖动 Jitter"]
B --> B1["RTT"]
B --> B2["TTFB"]
C --> C1["理论峰值"]
C --> C2["实际可用"]
D --> D1["受限于"]
D1 <--> C2
D --> D2["受限于"]
D2 <--> B
D --> D3["受限于"]
D3 <--> E
style B fill:#e3f2fd
style E fill:#ffebee关键公式:
最大吞吐量 = 窗口大小 / RTT
例如:
- 窗口 = 64KB
- RTT = 100ms
- 最大吞吐量 = 64KB / 0.1s = 640KB/s = 5.12Mbps
要跑满1Gbps,需要:
窗口 = 1Gbps × 100ms = 12.5MB这就是带宽延迟积(BDP)。
6.4 关键工具链
ss / netstat:连接状态
# 查看TCP连接状态统计
ss -s
# Total: 1234
# TCP: 2345 (estab 1234, closed 567, orphaned 89, timewait 456)
# 查看具体连接详情(包含TCP内部参数)
ss -ti '( dport = :443 or sport = :443 )'
# ts sack cubic wscale:7,7 rto:201 rtt:15.234/2.345 mss:1448 cwnd:123 ssthresh:456
# ^^^ RTT
# ^^^ 拥塞窗口
# ^^^ 慢启动阈值tcpdump / tshark:抓包分析
# 抓特定端口
sudo tcpdump -i eth0 port 8080 -w capture.pcap
# 实时分析
sudo tcpdump -i eth0 port 8080 -nn -tttt
# 14:32:01.123456 IP 10.0.1.2.54321 > 10.0.2.3.8080: Flags [S], seq 1234567890
# 14:32:01.125012 IP 10.0.2.3.8080 > 10.0.1.2.54321: Flags [S.], seq 9876543210, ack 1234567891
# 14:32:01.567890 IP 10.0.1.2.54321 > 10.0.2.3.8080: Flags [.], ack 1, win 640
# 注意第三行ACK到数据的时间差 = 442ms(异常!)iperf3 / qperf:吞吐量测试
# 服务端
iperf3 -s
# 客户端
iperf3 -c server_ip -t 30 -P 4 -w 1M
# -t 30: 测试30秒
# -P 4: 4个并行流
# -w 1M: 窗口大小1MB
# 输出:
# [ ID] Interval Transfer Bitrate
# [ 5] 0.00-30.00 sec 8.92 GBytes 2.55 Gbits/secmtr:路由追踪+延迟
mtr --report --report-cycles 100 api.example.com
# 显示每一跳的丢包率和延迟,比traceroute更实用6.5 TCP拥塞控制算法
算法演进
timeline
title TCP拥塞控制演进
section 1988
Reno : 慢启动 + 拥塞避免
: 丢包即拥塞
section 1996
CUBIC : 三次函数窗口增长
: Linux默认
: 高带宽友好
section 2016
BBR : 基于带宽和RTT
: 不依赖丢包
: Google出品
: 需要内核4.9+BBR vs CUBIC 对比:
# 查看当前算法
sysctl net.ipv4.tcp_congestion_control
# net.ipv4.tcp_congestion_control = cubic
# 切换到BBR(需要内核4.9+且启用拥塞控制模块)
echo 'net.ipv4.tcp_congestion_control=bbr' >> /etc/sysctl.conf
sysctl -p
# 验证
sysctl net.ipv4.tcp_congestion_control
# net.ipv4.tcp_congestion_control = bbr| 场景 | CUBIC | BBR |
|---|---|---|
| 浅缓存网络 | 好 | 更好 |
| 深缓存网络 | 填充过满,bufferbloat | 精准控制,低延迟 |
| 高丢包率 | 吞吐量暴跌 | 维持高吞吐 |
| 长肥管道 | 窗口增长慢 | 快速探测带宽 |
建议:Linux内核4.9+的Server,建议切换到BBR。
6.6 网络优化清单
# ===== TCP核心参数调优 =====
# 启用SYN Cookie,防SYN Flood
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
# 开启TCP Fast Open(客户端+服务端)
echo 3 > /proc/sys/net/ipv4/tcp_fastopen
# 增大TCP最大缓冲区
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"
# 自动调优窗口
sysctl -w net.ipv4.tcp_window_scaling=1
sysctl -w net.ipv4.tcp_moderate_rcvbuf=1
# 增大本地端口范围
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
# 缩短TIME_WAIT时间(高并发场景)
sysctl -w net.ipv4.tcp_tw_reuse=1
# 注意:tcp_tw_recycle在4.12+已移除,不要设置
# 开启BBR(内核4.9+)
echo bbr > /sys/module/tcp_bbr/parameters/tcp_congestion_control6.7 本章总结
mindmap
root(("网络\n性能分析"))
TCP核心
三次握手
滑动窗口
拥塞控制
关键指标
RTT
吞吐量
丢包率
工具链
ss/netstat
tcpdump/wireshark
iperf3
mtr
优化方向
减少RTT
增大窗口
切换BBR
TCP Fast Open核心要点:
- RTT是网络性能的基石——优化前先测准RTT
- 吞吐量 = 窗口 / RTT——窗口不够大,千兆带宽跑不满
- BBR在高丢包、高延迟场景远超CUBIC——内核4.9+建议切换
- tcpdump能精确定位延迟发生在哪个阶段——SYN?ACK?数据传输?
- ss -ti 是查看TCP内部状态的最快方式——cwnd、rtt、ssthresh一目了然
"网络问题最难的不是定位,而是证明’不是网络问题’。"