UDT拥塞控制算法

来源:互联网 发布:淘宝店铺修改退货地址 编辑:程序博客网 时间:2024/06/06 19:08

导语

我们知道,TCP是通过AIMD算法来控制发送速度的.UDT使用类似的算法来调整数据包的发送周期

SND:

UDT发送周期,即每个数据包之间的间隔时间,初始值为0.
UDT每隔10毫秒都会调整它的发送速度,当收到ACK消息时,会提升发送速度,而当收到NAK(UDT数据包ACK的一种格式,表示不会对某个数据包进行ACK)时则减少发送速度.
另一种情况则是发生了超时,此时按情况调整,可以不减少。

  • 注意包发送周期与包间时间是不一样的.发送周期=(发送花费的时间+包间时间)

CWND:

UDT的滑动窗口,表示正在传输中的数据包,其初始大小为2,会根据ACK返回的信息更新其窗口大小值,需要注意的是要避免大小为0的情况出现(永远发送不出数据包,也不会收到ACK),CWND可以跟接收方的缓存大小保持一致。

SYN:

UDT调整发送速率的固定周期,一般为10ms。
UDT拥塞控制包含两个阶段,慢启动阶段和常规发送阶段,每个连接建立之初处于慢启动阶段,当发生丢包或者滑动窗口CWND已满时,进入常规发送阶段.并且UDT中所有的数据包应当具有相同的大小。

对包(packet pair):

发送方会连续发送两个相同大小的数据包,接收方接收到时,会根据包间隔来计算出链路带宽。
在发送端,UDT每发送16个数据包就会发送一次对包,即第16,17号数据包成为一个对包,由于在只有16号数据包,没有17号数据包时(或17号包很晚才发),接收方计算间隔时间会出现非常大的值,此时链路带宽会出现比较大的波动,所以UDT采用中值过滤法来避免这种情况。

对包窗口:

一个大小为N的循环链表,接收方维护了最近N个对包的对包间隔窗口,N可以是任意数值,越大需要的内存和CPU消耗越高,在UDT中N=64,每次都会使用最新的间隔时间来替换掉最老的间隔时间,接收方使用中值过滤法来去除噪音,UDT计算出对包窗口中的中值,所有大于中值8倍,或者小于中值1/8的数据都会被忽略掉,然后再计算余下有效的间隔时间的平均值,带宽就通过平均值来计算出来

B = 包大小 / 平均间隔时间  

对包窗口内的间隔时间,全部初始化设置为1秒(安全,考虑低带宽的情况),接收方对链路大小进行评估后,将评估值b通过ACK返回给发送方。
发送方接收到新的评估值b后,使用如下公式更新已有带宽值B(能处理10到1/10倍的错误数据):

B = B * 0.875 + b * 0.125

RTT:

往返时延,UDT采用一种叫做ACK子序列的方式来计算RTT,接收方记录下发送的ACK时间和序号,然后等发送方返回ACK2(ACK的ACK)时,根据ACK2中携带的ACK序号,计算ACK2的到达时间和ACK的发送时间,即可得出RTT.计算公式如下,RTT表示已有值,rtt表示新计算出来的值

RTT = RTT * 0.875 + rtt * 0.125RTTVar = RTTVar * 0.875 + abs(RTT - rtt)) * 0.125

RTT通过ACK返回给发送方,RTTVar保存在本地,发送方收到新的RTT值时也通过上述公式更新其RTT值,RTTVar表示RTT的差值,用于计算RTO。

RTO:

重传超时,UDT中最小值为100ms

RTO = RTT + 4 * RTTVar 
  • 注意几种情况:
    • 如果接收方收到数据包就立即ACK,那么RTT可以在发送方通过 ACK到达时间 - 数据包发送时间 计算出来,此时不需要 ACK2
    • 如果接收方只在每个SYN时间内ACK,那么 RTO = RTT + 4 * RTTVar + SYN
    • UDT中是用ExpCount来表示连续超时次数,此时 RTO = ExpCount * ( RTT + 4 * RTTVar ) + SYN

AS包接收速率:

接收方记录了最近N个数据包之间的间隔(我们叫它接收时间窗口,大小为N),跟对包技术不同的是,对包只记录第16,17个数据包之间的时间间隔,包接收速率AS计算公式如下

AS = 1 / 平均间隔时间

在计算平均间隔时间时同样需要采用中值过滤法来过滤噪声,去除大于中值8倍和小于中值1/8的数据,然后计算平均值。

ACK 事件:

负责修改AS,SND,和CWND.
之前说到,拥塞控制算法有两个阶段,慢启动和常规阶段.在慢启动阶段中,SND初始化为0,CWND初始化为2,当每次ACK到达时设置为已经发送出的数据包总数,当收到NAK包,或者已发送的数据包总量达到CWND最大值时退出慢启动阶段。在慢启动的末期,SND包发送间隔设置为 1 / 包接收速率

SND = 1 / AS

之后进入常规阶段,常规阶段会调整通过调整 inc 这个参数来调整SND,增量 inc 通过下面公式算出

if (B <= C)        inc = 1/MSS;else         inc = max(10^(ceil(log10((B-C)*MSS*8))) * Beta/MSS, 1/MSS);    

B:链路带宽,C:当前发送速率,即C = 1 / SND = AS,MSS:MSS = MTU - UDP/UDT头大小,通常为1400,Beta:常量 0.0000015
B和C的单位都是 包数量 / 每秒,如果是以 字节 / 每秒为单位,那么可以去除MSS,算出增量 inc 后,SND和CWND通过下面公式更新:

SND = ( SND * SYN ) / ( SND * INC + SYN )CWND = AS * (RTT + SYN ) + 16

在常规阶段,每个SYN周期内,SND只能被更新1次。

NAK事件:

在此我们要知道一个拥塞周期的概念,拥塞周期就是在收到的NAK中数据包序号比已发出的最大数据包序号LastDecSeq还要大时开始,持续到下一个拥塞周期开始时结束。举例:

LastDecSeq=0     NAK       NAK          LastDecSeq=100      NAK  |----------------60---------80---------------100------------140------->   

在一开始时 LastDecSeq = 0, 当收到NAK(60)时,判断有NAK发生,进入拥塞周期,将LastDecSeq=100,然后进行降速处理
在收到NAK(80)时,查看LastDecSeq ,发现LastDecSeq比当前NAK序号大,说明还在同一个拥塞周期内,NAK(60)已经进行过降速处理,此时仍降速,幅度调小
发送方持续发送数据包,当收到NAK(140)时,发现NAK序号比LastDecSeq大,进入下一个拥塞周期,进行降速处理,幅度恢复正常

降速算法:

降速算法中用到4个参数,参数名以及他们的初始值分别如下:

AvgNAKNum = 1 : 拥塞周期内收到的NAK数量的平均值  NAKCount = 1 :当前拥塞周期内收到的NAK数量  DecCount = 0 :发送速率在当前拥塞周期内已经被降速的次数  LastDecSeq = 初始化序列号-1   
If this NAK starts a new congestion period{increase SND = SND * 1.125;Update AvgNAKNum;Reset NAKCount to 1;Compute DecRandom to a random (uniform distribution) number between 1 and AvgNAKNum;Reset DecCount to 1;Reset Update LastDecSeq;Stop.}If (DecCount <= 5) and (NAKCount == DecCount * DecRandom){Update SND period: SND = SND * 1.125;Increase DecCount by 1;}Update LastDecSeq and NAKCount.

DecRandom是一个位于1 和 周期内平均NAK数量 AvgNAKNum 之间的随机数,比如DecRandom=2,UDT就会在第1,2,4,6个NAK时进行降速,每次降速1 / 8, 但是因为每个周期内发送速率降速不能超过1 / 2 ,否则就变成AIMD了,所以在收到第6个NAK时就开始不进行降速了。

重传:

RTO是一个定时器,只会被ACK和NAK重置,RTO事件会触发重传和降速,当RTO次数超过一定阈值时,就可以认为链接已经断开了。.

GIT :[https://github.com/ktlifeng/udt-java] (https://github.com/ktlifeng/udt-java)