3、TCP/IP协议栈回顾:TCP三次握手与四次挥手、滑动窗口、拥塞控制
做带宽测试和瓶颈分析,TCP协议栈是你绕不开的核心。说白了,网络上的大部分流量都是TCP承载的。你测出来的带宽好不好,很多时候不是线路的问题,而是TCP协议栈在背后“搞事情”。
我个人习惯,在分析任何性能问题之前,先回顾一下TCP的几个关键机制。这就像修车之前得先看发动机原理图,不然你连故障灯亮在哪都看不懂。
3.1 TCP三次握手:连接建立的“敲门砖”
三次握手,大家面试都背过。但你真的理解它对带宽测试的影响吗?
流程很简单:
- 客户端发SYN:我想跟你说话,这是我的初始序列号(ISN)。
- 服务端回SYN+ACK:收到,这是我的ISN,确认你的序列号。
- 客户端发ACK:收到确认,咱们开始聊。
嗯,这里要注意。三次握手的开销,在短连接场景下非常致命。我在项目中遇到过,一个HTTP请求只有几KB,但握手就占了两个RTT(往返时间)。你想想看,如果RTT是100ms,光握手就200ms没了,带宽再高也白搭。
核心影响: 三次握手引入了至少1.5个RTT的延迟。对于带宽测试工具(比如 iperf),如果使用短连接模式,测出来的结果会远低于实际可用带宽,因为大量时间浪费在握手上了。
我的建议: 做带宽测试时,尽量使用长连接(比如 iperf 的默认模式),或者使用 TCP_NODELAY 选项禁用 Nagle 算法,避免握手阶段的数据包被延迟合并。
3.2 四次挥手:优雅地“说再见”
四次挥手比握手复杂一点,因为它涉及半关闭状态。流程是:
- 主动方发FIN:我说完了。
- 被动方回ACK:知道了,但我还有话没说完。
- 被动方发FIN:我也说完了。
- 主动方回ACK:收到,拜拜。
这里有个坑,叫 TIME_WAIT 状态。主动关闭连接的一方,在发送最后一个ACK后,会进入TIME_WAIT,等待2MSL(最大报文生存时间)后才彻底关闭。
我曾经在压测服务器时,发现端口被占满了,新连接连不上。查了半天,就是TIME_WAIT太多。每个连接关闭后,端口要等60秒才能复用。高并发场景下,这简直是灾难。
避坑指南: 我曾经在压测时,因为没调优TIME_WAIT,导致端口耗尽,测试直接中断。解决方案:调整内核参数 net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_tw_recycle(注意:tcp_tw_recycle 在NAT环境下有坑,慎用),或者使用 SO_LINGER 选项强制关闭。
3.3 滑动窗口:流量控制的“水龙头”
滑动窗口,说白了就是接收方告诉发送方:“你一次别发太多,我缓冲区就这么大。” 它解决了发送方和接收方处理速度不匹配的问题。
窗口大小决定了在未收到ACK确认前,最多能发送多少数据。窗口越大,吞吐量越高,但风险也越大——万一丢包了,重传的数据量也大。
我习惯用 ss -ti 命令查看当前连接的窗口大小。比如:
# 查看当前TCP连接的窗口信息
ss -ti | grep -E "cwnd|ssthresh|rtt"
# 输出示例
cwnd:20 ssthresh:14 rtt:10ms
这里 cwnd 是拥塞窗口,ssthresh 是慢启动阈值。窗口大小 = min(接收窗口, 拥塞窗口)。
实战经验: 我在调优一个跨国专线时,发现带宽利用率只有30%。查了接收窗口,发现默认只有64KB。而RTT是200ms,BDP(带宽延迟积)算下来需要1MB的窗口才能跑满。调大 net.core.rmem_max 和 net.ipv4.tcp_rmem 后,带宽直接拉满。
3.4 拥塞控制:网络的“交通警察”
拥塞控制是TCP最核心、也最复杂的部分。它防止发送方把网络“堵死”。主要算法有四个阶段:
| 阶段 | 行为 | 触发条件 |
|---|---|---|
| 慢启动 | cwnd 从1开始,每收到一个ACK翻倍 | 连接刚建立,或超时重传后 |
| 拥塞避免 | cwnd 线性增长(每RTT加1) | cwnd 达到 ssthresh |
| 快速重传 | 收到3个重复ACK,立即重传丢失的包 | 检测到丢包 |
| 快速恢复 | ssthresh 减半,cwnd 设为 ssthresh + 3 | 快速重传后 |
你想想看,如果网络有1%的丢包率,TCP的拥塞控制会频繁触发快速重传和快速恢复,cwnd 不断减半。带宽利用率能高才怪。
不同的拥塞控制算法,对带宽测试结果影响巨大。比如:
- CUBIC:Linux默认算法,适合高带宽长肥网络。
- BBR:Google开发的,基于带宽和RTT建模,不依赖丢包。我在跨国链路上用BBR,带宽利用率从40%提升到了90%。
- Reno:老算法,丢包后窗口减半,性能较差。
切换算法: 你可以通过 sysctl net.ipv4.tcp_congestion_control 查看当前算法,用 sysctl -w net.ipv4.tcp_congestion_control=bbr 切换。注意,需要内核支持。
3.5 知识体系总览
下面这张图,是我梳理的TCP协议栈核心逻辑。它把三次握手、滑动窗口、拥塞控制串在了一起。你看完应该能明白,为什么带宽测试结果会受这么多因素影响。
这张图把三个核心机制串起来了。你从左边看到右边,就是一次TCP数据传输的完整生命周期。握手建立连接,滑动窗口控制流量,拥塞控制应对网络变化。任何一个环节出问题,带宽测试结果都会失真。
总结一句话: 做带宽测试前,先检查TCP参数。调优窗口和拥塞控制算法,往往比换硬件更有效。我见过太多人花大价钱升级带宽,结果问题出在服务器默认的TCP配置上。
想要更多资料,联系可可