Linux 内核有个参数 tcp_retries2(默认值是 15),可以控制 TCP 连接建立的情况下,最大超时重传次数
不过参数 tcp_retries2 值为 15,并不代表 TCP 超时重传了 15 次才会断开该连接,而是 Linux 内核还会根据参数 tcp_retries 值计算出一个 timeout(如果 tcp_retries2=15,则计算出的 timeout 值为 924600 ms), 如果重传总间隔时长超过这个阈值,也会断开连接
在发生超时重传的过程中,每轮 RTO 都是倍数增长的,例如第一轮 RTO 是 200ms,那么第二轮 RTO 就是 400ms,第三轮 RTO 则是 800ms,以此类推,而 RTO 是基于 RTT(一个包的往返时间)计算出来的,如果 RTT 较大,计算出的 RTO 也就越大
举个例子,如果 tcp_retries2=15,则计算出的 timeout 值为 924600 ms
- 如果 RTT 比较小,那么 RTO 初始值就约等于下限 200ms,也就是第一轮 RTO 是 200 毫秒,由于 timeout=924600 ms,刚好重传 15 次后断开 TCP 连接
- 如果 RTT 比较大,假设计算出的 RTO 初始值为 1000 ms,也就是第一轮 RTO 是 1s,压根就不需要重传 15 次,只要重传总间隔时长达到了 timeout 就会断开 TCP 连接
/* Linux Kernel 6.14.7 tcp.h */
#define TCP_RTO_MAX ((unsigned)(120*HZ))
#define TCP_RTO_MIN ((unsigned)(HZ/5))
如果 tcp_retries=15,且 RTT 比较小,那么 RTO 初始值就约等于下限 200ms,这意味着需要经过 924.6 秒才能断开 TCP 连接,每轮 RTO 增长变化如下:
RTO(ms) | 总用时(s) | 重传次数 |
---|---|---|
200 | 0.2 | 1 |
400 | 0.6 | 2 |
800 | 1.4 | 3 |
1600 | 3.0 | 4 |
3200 | 6.2 | 5 |
6400 | 12.6 | 6 |
12800 | 25.4 | 7 |
51200 | 51 | 8 |
102400 | 102.2 | 9 |
120000 | 204.6 | 10 |
120000 | 324.6 | 11 |
120000 | 444.6 | 12 |
120000 | 564.6 | 13 |
120000 | 684.6 | 14 |
120000 | 804.6 | 15 |
120000 | 924.6 | 16 |