TCP 在不断演进过程中有很多弄巧成拙的事,这些事无一例外都是 “我猜是X,但我不能确定” 导致。
拥塞控制中丢包判断不必多说, Nagle 算法和 Delayed ACK 也曾经说过。跟同事聊起 RTO 的事,这又是一例。
Linux TCP 实现中 MIN_RTO 为什么 200ms 如此大,对于 IDC 内部通信显然非常不合理,100us 级的 RTT 显然不需要 1000 倍时间来断定超时。
解决这个问题不难,提取一个配置参数,让 MIN_RTO 可配就行。这也是最自然的想法,我相信很多私有实现都这么做。但问题是为什么大名鼎鼎的 LInux 没有导出这个配置呢?
原来为了迎合 Delayed ACK,又是标准规定,Delayed ACK 有个延迟上界,比方说 200ms (具体数字不重要),RTO 必须考虑这个 Delay,否则就可能伪超时。
于是 MIN_RTO 配置成 Delayed ACK Delay 量级,比如 200ms 。
看起来顺利成章。但事情变复杂了:
…
然后 Google 出了个方案:draft-wang-tcpm-low-latency-opt-00
其实这一切根本没必要,兜了个圈。
为减少 ACK 数量,引出 Delayed ACK,为迎合 Delayed ACK 延时上界,MIN_RTO 明显偏大,为更高效探测尾丢,引出 TLP,为适应 IDC RTT 但又遵守 Delayed ACK 上界,Google 引出 TCP Low Latency Option。
根源就是 Delayed ACK,那就解决它好了。
看下面文章:
TCP Delayed ACK 辩证考
怎么解决 MIN_RTO 问题呢?
MIN_RTO 不再需要,不必再迎合 Delayed ACK,RTO 完全根据 RTT 计算。TLP 也不再需要,只需在 PSH 包设置 “必须立刻 ACK” 标志。有了上述保证,完全不必担心伪超时:
特别的,如果是单向传输,明知对端不肯能捎带 ACK 的情况下,为何不直接告诉对端,而非要去自适应呢。事实上 Linux TCP 为连接维护了一个 pingpong 变量,就是自适应 TCP 超时的。现实情况还要更复杂。
你可每一个包都设置 “立刻 ACK” 标志,或者缓解一点,每 2 个,3 个 … 设置一次 “立刻 ACK”。甚至可以只在前几个包以及最后一个 PSH 包上设置 “立刻 ACK”。取决于拥塞控制算法。
是不是很清爽?
只要保证 RTT 量级内有一个 “立刻 ACK“ 数据包发出就能在 RTT 量级时间内策划 RTO,不必再设定 MIN_RTO,自己决定自己,而不靠猜测对方的行为。更不要猜链路的行为。
TCP 性能不佳,包括 QUIC 性能也有上限,其根本就是链路行为基本靠猜,这是端到端原则导致,只要你认同端到端自决,这问题就没法解决,链路行为信息你拿不到,只能靠预测,启发,说到底都是猜。
我这个 “建议” 很好,但对端不一定支持,所以说要协商?
协商也总比之前导出那么大一堆 “机制” 要好。所以说,能标准化就标准化,不能标准化就协商,但别猜。
谁在乎 7 亿中国男人走得累不累?奥康在乎。
浙江温州皮鞋湿,下雨进水不会胖。