Scalable TCP拥塞算法

Scalable TCP(STCP)拥塞控制算法,在每个RTT周期内,如果没有发生拥塞,将在接收到每个ACK报文后,将拥塞窗口增加0.01(a值)。

cwnd =  cwnd + 0.01

如果在一个RTT周期内第一次检测到拥塞发生,将拥塞窗口减低1/8倍(b值),在同一个RTT周期仅降低一次拥塞窗口。

cwnd =  cwnd − [0.125 * cwnd]

使用STCP算法的发送端在任一发送速率下,经过大约70个RTT可实现速率的翻倍,其窗口更新算法具有可扩展性。如下,以窗口减半为例,即1/2cwnd, Nrtt表示经过多少个RTT周期窗口能增长1/2cwnd,按照STCP的增长算法,每100个ACK将使拥塞窗口增加1,那么在一个RTT周期内,窗口的增加值为cwnd/100。如下等式可得Nrtt为50,即经过50个RTT周期,拥塞窗口可增长一倍。考虑延迟ACK因素,在SCTP的文章(Scalable TCP: Improving Performance in Highspeed Wide Area Networks)中,作者给出的值为70。

cwnd / 100  *  Nrtt  =  1/2 * cwnd

由以上可见,不同于传统TCP拥塞算法(a=1/cwnd, b=0.5),其丢包恢复时间与连接的窗口大小和RTT成比例,这意味着随着带宽的增长,拥塞窗口的增加,发送丢包之后,恢复时间将变得非常长,而STCP的丢包恢复时间仅与RTT成固定比例,这使得STCP在高速WAN网中拥有比传统TCP更高的性能和可扩展性。STCP参数(a,b)的数值选择考虑了对传统TCP流量的影响,带宽分配属性,流量速率变化,收敛属性和控制理论稳定性等。

假设TCP连接的RTT时长为200ms,发送的报文长度为1500字节,带宽为1Gbps,对应于17000个报文(1Gbps / [1/0.2 * 1500 * 8]),对于传统TCP拥塞算法,在发生拥塞时,窗口减半为8500,对应于带宽500Mbps,要再次达到1Gbps的带宽,拥塞窗口需要增加8500,每个RTT(200ms)增加1,需要经过1700秒(8500*0.2=28分钟)。即便经过如此长的时间恢复到1Gbps的带宽,还有前提条件,即在28分钟内,没有再发生任何拥塞。可见,由于较长的丢包恢复时间和对较低丢包率的要求,传统TCP拥塞算法在高速WAN网路中,很难合理利用可用带宽。

依据以上的网络情况,对于STCP,首先,其将拥塞窗口检查1/8;再次,STCP的拥塞窗口不依赖当前窗口,故STCP拥塞窗口增加1/8,所需的时间为: 100/8 = 12.5个RTT,即2.5秒(12.5 * 0.2),远低于传统TCP的28分钟。

在Scalable TCP: Improving Performance in Highspeed Wide Area Networks中定义了原始的窗口增加值a和拥塞减少系数b分别为0.01和0.125,但在内核实现中为弥补延迟ACK带来的损失,a取值增加一倍,为0.02。开启延迟ACK的接收端在接收到两个MSS大小的报文后回复ACK报文,或者等待延迟ACK超时。

如下内核函数tcp_scalable_ssthresh,在发生拥塞时,将慢启动阈值ssthresh设置为当前拥塞窗口的7/8倍。

#define TCP_SCALABLE_MD_SCALE   3

static u32 tcp_scalable_ssthresh(struct sock *sk)
{   
    const struct tcp_sock *tp = tcp_sk(sk);
    
    return max(tp->snd_cwnd - (tp->snd_cwnd>>TCP_SCALABLE_MD_SCALE), 2U);
}

在ACK报文的处理过程中,如果报文发送并没有受到拥塞窗口的限制,不进行窗口调整。如果套接口处于慢启动阶段,应用慢启动窗口增长策略,反之,执行AI(Additive Increase)增长,每接收到50个(TCP_SCALABLE_AI_CNT)ACK报文拥塞窗口增加1。

但是,如果当前拥塞窗口值小于50,执行传统TCP拥塞增长算法,即每CWND个ACK报文,拥塞窗口增加1。这要增加了STCP算的TCP友善性(TCP-friendly)。

#define TCP_SCALABLE_AI_CNT 50U

static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked)
{   
    struct tcp_sock *tp = tcp_sk(sk);
    
    if (!tcp_is_cwnd_limited(sk))
        return;
    
    if (tcp_in_slow_start(tp))
        tcp_slow_start(tp, acked);
    else
        tcp_cong_avoid_ai(tp, min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT), 1);
}

内核版本 5.0

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页