UDP优化重点旨在解决高延迟、高丢包场景下传输低效的问题。
UDP优化重点旨在解决高延迟、高丢包场景下传输低效的问题。
本次UDP优化重点旨在解决高延迟、高丢包场景下传输低效的问题。当前改造的UDP协议 CC算法是基于TCP BIC算法。先了解下BIC算法。
BIC 算法
应用场景
BIC算法主要用于高延迟的高速网路(也称为log fat networks)。在这样的网络中,BIC能更显著得(相比它之前的算法)利用好带宽。
算法思想
在Linux内核的2.6.8~2.6.18版本中作为默认算法。BIC有独特的CC算法。为了寻找最大的cwnd,通过三个流程来搜索:增性二分查找,加性增(AI),以及慢启动。如果网络出现波动,BIC使用乘性减(MD)来校正窗口。
使用二分查找算法,试图查找在长时间内的保持窗口最大。
二分思想
当出现丢包的时候,说明最佳窗口应该比这个值小,那么当前的cwnd可以设为MAX_WIN($W_{max}$),把乘性减窗后的值设置为MIN_WIN($W_{min}$)。这样,BIC在这两者间通过二分查找,每次都是取其中点窗口。可以看到,这比标准更显“激进”,每次变化幅度都会更大(若MAX_WIN与MIN_WIN间差距较小,则幅度不会很显著)。这也可能造成每次传输波动较大。
缺点
抢占性较强,增长函数在小链路带宽时延短的情况下,比起标准TCP抢占性强;在低RTT网络和低速环境下,BIC可能过于“积极”。BIC规定在当前窗口值小于low_window(=14)情况下,采用标准TCP CC算法。
UDP优化
概述
目前所谓的UDP可靠传输,都是对于TCP协议的“拙劣”模仿(嗯,我也一样)。其实这也无可厚非,TCP有几十年的沉淀,大大小小的算法也是提了一箩筐,这个宝库不利用也是浪费。凡是UDP可靠传输的,都是基于TCP的某一个算法或思想,在某一场景下的特定优化,以达到特定的场景的高效传输效果。但凡说,要提出一个普适的UDP可靠传输实现,几乎都是把TCP那一套在应用层又重新实现了一遍。意义估计在于能够尽快使用到TCP提出的新特性(一些核心老设备一般都要落后个好几年or十几年),不用升级内核等。
应用场景
搞UDP可靠传输的私有协议(UDT貌似有RFC草案了),先是要主攻首要的支持场景,然后后续扩展。目前主要要解决的场景是提高在long fat network中大文件的传输效率(所以先介绍了一把BIC,基于BIC的改造)。
优化考虑
复用的TCP特性
- 三次握手(可以在握手的时候“先发制人”,开始发包),四次挥手;
- 序列号机制,UDP以包为单位;
- ACK确认机制;
- BIC算法(会根据UDP以及实现做调整);
- 时间戳(估计rtt)
改进考虑
选择性重传
TCP已经支持这个特性了。在UDP可靠传输里略有不同,我们使用了请求-确认机制,即由发送方来发送请求ACK的报文来触发接收方发送ACK。一是避免接收方一接收数据包就要确认,二是由发送方来控制一次性需要确认的报文数,减少控制报文的传输。在ACK中可以看到当前接收方已经接收到了哪些序列号的报文,发送方基于此来选择重传丢失的报文。
报文合并
接上述,在确认时,我们可以多个包确认一次。传输双方可以基于此种行为约定具体数量N(在握手阶段),只在发送/接收N个包后来请求/确认,减少交互(贪婪的做法去抗丢包)。
快速连接
这个其实意义不大,但是同事有提到,后面也做了。就是在两次握手后,第三次开始发包。实际上,现在TCP也是可以做到的,在第三次发送ACK的同时携带数据。如果想要提前传输的话,可以更激进一点,“先声夺人”,在开始握手就发送数据了—-当然目前没有这么做,因为本质上我们要解决的问题不是在于首包时间。
信息反馈
协议数据格式毕竟可以自定义,所以可以在报文头加上一些控制信息,来获取诸如rtt以及丢包率等信息(TCP也有,只是说线上TCP不是每个都有orz)。
CC算法修改
TCP在丢包时会降窗,反应比较敏感;由于我们使用了选择性重传的方式,我们可以统计每次发送的丢包率。根据这个丢包率数据来调整窗口,会容忍一定的丢包率。如果丢包率过高或是持续(几个rtt内统计)丢包率没有下降,这时开始按一定比例降窗,调整合适的窗口值。
效果
当前的测试结果看,在高丢包率的大带宽环境下相较于TCP(CUBIC/BBR等)能更胜一筹;在小带宽/小运营商环境下,波动较大,相对效果也比较差。
尾声
写完发现,其实我们真的只是重新实现了一把简单TCP的样子(内部实现细节不便说明)。没有什么最好的算法,只有合适的算法。挽尊。