本文目录导读:

在TCP(传输控制协议)中,乱序(Reordering)是指数据包在从发送端到接收端的网络传输过程中,到达顺序与发送顺序不一致的现象。
tcp_loss_detection_reordering 这个参数(通常是 /proc/sys/net/ipv4/tcp_reordering 或类似的内核TCP参数)控制的是TCP协议对乱序的容忍度,它告诉TCP拥塞控制算法:“当数据包到达顺序错乱时,在多大程度上我相信这是网络乱的(可以容忍),而不是网络丢了包(需要立即重传)?”
这个参数的值越低,TCP越“紧张”,遇到一个小乱序就认为是丢包;这个参数的值越高,TCP越“迟钝”,允许更大的乱序而不启动快速重传。
为了让你理解它如何“产生”乱序,以及这个参数如何“判断”乱序,下面从两个角度来解释:
乱序是怎么产生的?
在正常的TCP通信中,数据包通常按顺序到达,但以下情况会导致乱序:
- 并行链路(最常见的现代原因):数据流被分发到多条物理链路(比如MPTCP或多路负载均衡),由于链路延迟不同,后发的包可能先到。
- 路由变化:当网络拓扑改变(比如路由器切换),数据包可能走了一条更快或更慢的路径,导致较早发出的包在较晚发出的包之后到达。
- 网络设备缓存与多队列:路由器或交换机内的多核处理、多队列调度,可能导致同一流的数据包被临时放入不同队列,从而释放时顺序错乱。
- 无线环境下的ARQ重传:在Wi-Fi或蜂窝网络中,当某个数据帧在无线链路上传输失败,基站会进行自动重传请求(ARQ),此时后续已成功发出的包先到达,而前面的包重传后到达。
tcp_loss_detection_reordering 如何工作?
TCP使用序列号(Seq#)来标记顺序,发送端发送1、2、3、4、5号包,接收端收到的是:1、3、4、2、5。
- 第1个包到达:正常,预期期待包2。
- 第3个包到达:这是乱序包,TCP会记录:有一个SACK块或重复ACK,内核会检查
tcp_reordering阈值。 tcp_reordering设为 3:TCP认为“允许最多乱序3个包”,所以第3个包早于第2个包到达,只算1个包的乱序(因为第2个包还没来),没超过3,TCP不会进入快速重传,继续等待。tcp_reordering设为 1:第3个包一到(乱序深度=1),TCP立即判定为包丢失(因为乱序容忍度为零),它会触发快速重传,立刻重发第2个包。
关键机制:
- 接收端每收到一个乱序包,就会发送一个 “重复ACK”(DupACK)。
- 发送端收到3个重复ACK(默认情况)后,会触发快速重传。
tcp_reordering参数 动态调整了这个“3”,它的值决定了在触发丢包判定前,最多允许多少个包的乱序。
本质上,这个参数是在 乱序 vs 丢包 之间做权衡:
- 值过高(比如10):对乱序非常宽容,但会导致丢包恢复变慢(当真的丢包发生时,要等更多重复ACK或超时才重传)。
- 值过低(比如1):对乱序零容忍,一有乱序就重传,浪费带宽,且可能造成虚假重传(网络没丢,只是乱了,重传的数据和后来的原始数据都到达,反而加重拥塞)。
内核如何自动调整这个值?(动态乱序检测)
现代Linux内核(2.6.18+)通常不靠人工设置固定的 tcp_reordering,而是通过DSACK(重复SACK) 或 FACK(向前确认) 自动学习网络的乱序程度。
算法大致如下:
- 当TCP检测到一次虚假重传(重传的数据包后来被确认时,发现原始数据包也到了,即DSACK)。
- 内核知道:哦!刚才我以为是丢包,其实是乱序,说明我对乱序的容忍度太低了。
- 内核自动增加
tcp_reordering的值(例如乘以1.5倍,但不超过100)。 - 如果后续网络乱序减少,内核也会通过降采样机制慢慢降低该值,以保持对丢包的敏感度。
你问的“怎样乱序”?
可以认为: tcp_loss_detection_reordering 本身不产生乱序,它只是定义了TCP如何感知乱序,但它的值决定了:
- 怎样才算“乱序”:任何不按序列号+1到达的包。
- 乱序到什么程度才算“丢包”:当乱序的“深度”(gap)超过
tcp_reordering时。
实际效果: 在一个低乱序容忍度(<3)的系统中,即使网络只有很轻微的并行路径延迟抖动(比如隔一个包到),也会被判定为丢包,从而触发不必要的重传,而在高乱序容忍度(>5)的系统中,真正的丢包可能被延迟识别,导致更长的延迟和重传超时(RTO)。
一句话结论: 乱序是网络路径的物理特性导致的;tcp_loss_detection_reordering 是内核用来过滤乱序、识别真实丢包的容忍度阈值,它通过控制快速重传触发的时机,来平衡带宽效率和延迟性能。
标签: TCP乱序