来源 /腾讯课堂Coding学院(ID:ke_coding)
导语
TCP数据包重传类算法是要让TCP连接从数据包丢失当中快速恢复起来。
1、用数据说话
基于数据定制出来的策略,才能精准解决问题。google在TCP的包丢失检测算法当中花费了大力气,在内核上也提交了很多补丁。所有策略的制定都是基于对TCP数据流的分析与统计。TCP重传类的算法的核心思想是在同样的丢包场景下,可以减少其在Loss Recovery的时间,精准重传,减少伪重传。
下面是引自谷歌的一个统计数据:
Google Web servers上面,将近70%的重传是RTO超时重传,只有30%是Fast Recovery重传。
同时还有数据表明,96%的RTO超时重传是在没有收到任何dupack的情况下发生的。
没有到任何dupack就意味着FR和ER机制都是无法生效的。
触发超时机制的常见场景:
另外google还收集了RTO/RTT的分布,来了解RTO值到底比RTT值大多少。下面是统计数据:
Googler认为”Such large RTOs make a huge contribution to the long tail on the
latency statistics of short flows.”
那么将RTO的计算值设置得较小一点如何?可能会造成两个问题:
所有优化策略都是基于特定场景进行订制,才能实现精准定制,有效优化。
这里存在的一个疑问是:我们腾讯的web servers上面的数据是怎么样的?
RTO 重传占比多少?
Fast Recovery 重传占比多少?
RTO/RTT分布如何?
Spurious retransmission(伪重传) 数量是多少?
丢包特征是如何?(是尾部丢、中间丢、一个一个丢还是一窗口一窗口的丢分布)
2、用数据解决问题
重传类的算法不外乎两种,一种是快速恢复的重传算法,另外一种是RTO超时重传。根据上面的统计,RTO要远远大于RTT时间,因此尽量在快速恢复阶段解决丢包重传可以大大提升性能。其二是大部分的RTO超时是由于没有dup ack导致(即尾部丢包),导致RTO超时。
根据上面的统计问题提出解决方案,googler提出了一系列的快速重传算法,如TLP、ER、RACK等算法,来提高TCP的性能,并去除了FACK算法,该算法过于激进导致重传脉冲,造成更多的丢包。定制的策略符合丢包特征,精准重传,减少伪重传(减少流量增加有效手段)。目前Linux上游分支采用的方案是:采用RACK+TLP这两种算法来实施对丢包的全覆盖。
TLP: 主要解决没有dup ack的丢包场景(即一个窗口一个窗口的丢包)。
RACK:主要解决dup ack数量不够的场景(连接中间的噪声丢包)。
这里存在一个疑问:这个算法是否符合我们腾讯的服务器的网络丢包特性?
3、性能评估方案
基于上面的数据,google提出了对此类算法的一个简单评估方案: 采用现网流量进行对比测试:在西欧的服务器上面部署了三组服务器运行了五天(one weekend plus 3 weekdays)的数据。具体描述如下:
Group 1: RACK off, TLP off
Group 2: RACK on, TLP off
Group 3: RACK on, TLP on
使用Cubic拥塞控制算法,init cwnd=10,以及fq/pacing qdisc。enabled SACK、F-RTO, disabled FACK。以上三个节点处理相同数量的连接。对比的目标是在loss Recovery花费的时间。
Recovery time = recovery and retransmit starts, till the remote has acknowledge beyond the highest sequency at the time the recovery starts.
Recovery = fast recoveries and timeout recoveries.
实验结果:
Group2 恢复时延比Group1 减少仅仅2%
Group3 恢复时延比Group1 减少25%,减少40%的 RTO超时。
如何理解这个测试方案以及测试结果:
在一定的传输时间内,在loss Recovery花费的时间越小,就说明有更多的时间传输新的数据,因此可以说明有更好的传输效果。
谷歌的测试结论是:
现行的实验需要取决于网络场景,谷歌的测试场景在西欧,其网络链路质量是比较好的,而loss Recovery 不是性能瓶颈,后续会在网络较差的场景进行测试,特别是受到强烈的traffic policing的环境进行验证。
TLP和RACK一起使用效果最佳。
反思:实质上google的算法之所以有这么大性能提升,主要是其抓住了主要矛盾(尾部丢包的场景比较多),用数据说话,用数据解决问题,最后直中要害,一击命中(这就是传说中的大招)。
4、性能评估方案实现
下面是我在内核侧实现的一个统计方案:分别统计loss状态花费的时间和Recovery状态花费的时间:(Linux 4.10 内核,移植最新的TCP RACK算法、去除FACK、ER代码)(
这里是单个连接的场景:
tcp的状态切换函数使用的是:tcp_set_ca_state,下面将所有的相关函数调用:
tcp_sock结构体中添加两个识别Loss和Recovery停留的时间,代码如下
tcp.h
tcp初始化时,对TCP的连接进行变量进行初始化:
在状态切换过程中开始统计:
在Loss状态和Recovery状态结束之后,停止统计。
5、副作用评估方案实现
实际上重传算法难免带来伪重传(通常是乱序问题导致判断失误而带来伪重传),带来的副作用,其一是:伪重传太多,导致流量激涨,其二是伪重传太多占用窗口的有效传输效率,导致下载性能下降。
下面的代码是统计伪重传的个数:在清理重传队列里面对重传的数据进行判断(只有带时间戳的连接才能精确判断一个重传是否是伪重传)。
这个是一个方案,比较直观,直接是伪重传数量。另外一个方案则是计算TCP的重传率,对比两台机器的重传率即可得到那边的重传更多,消耗的流量更大。再者,也可以统计两台机器的流量,流量更多,在下载数目一样的情况下,则说明伪重传更多。
快速重传和精准重传两者是一个矛盾体,是时间和空间的矛盾,永远无法调和,只能在其中折中。
6、总结
解决问题的首要思路还是要了解问题的瓶颈在哪里。如果这些TCP重传类的算法放在网络链路质量很好的环境下,进行测试和验证,其提升肯定是非常有限的。还有就是没有适用于任何场景的万能算法。
欢迎有兴趣的小伙伴微信关注“腾讯课堂”(微信号:tencent-class)收获更多福利~
网友评论