TCP重传

作者 Billy 日期 2017-09-12
TCP
TCP重传

TCP重传

TCP重传次数与操作系统有关,可配###

linux:

/proc/sys/net/ipv4/tcp\_retries1 (integer; default: 3 建立连接重试次数)
TCP尝试了3次(tcp\_retries1默认3)重传后,还没有收到ACK的话,则后续每次重传都需要network layer先更新路由。

/proc/sys/net/ipv4/tcp\_retries2 (integer; default: 15 数据传输重试次数)
TCP默认最多做15次重传。根据RTO(retransmission timeout)不同,最后一次重传间隔大概是13到30分钟左右。如果15次重传都做完了,TCP/IP就会告诉应用层说:“搞不定了,包怎么都传不过去!”

RFC中如何计算RTO(Retransmission Timeout)

  1. RFC-793如何计算RTO

    详细计算:

     SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)
    

    基于SRTT,我们再来计算RTO:RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]]

    UBOUND是RTO上线,ALPHA是平滑因子(smoothing factor, e.g., .8 to .9),BETA是一个延迟方差因子(BETA is a delay variance factor (e.g., 1.3 to 2.0))。

    仔细看这两个公式大概就能理解了RTO的计算了。

    这里对上面两个公式做一个简单的注释:公式1中计算SRTT,ALPHA越接近于0,则表示SRTT越相信这一次的RTT;越接近于1,则表示SRTT越相信上次统计的RTT。公式二给RTO分别设置了一个上限和下限。

  2. RTO重传间隔是指数增加的
    上面我们介绍的是初次重传时的RTO,如果重传后还没收到另一端的响应,下一次重传RTO则会指数增加,例如第一次重传RTO是1,之后分别2,4,8,16…。

  3. RFC-2988和RFC-6298中的RTO计算
    在RFC-2988和RFC-6298中又重新改进了RTO的计算方法,Linux中的实现即使参考RFC-2988。算法核心公式:

     初始:
     SRTT <- R
     RTTVAR <- R/2
     RTO <- SRTT + max (G, K*RTTVAR)
     where K = 4.
     
     根据RTT计算SRTT:
     RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'|
     SRTT <- (1 - alpha) * SRTT + alpha * R'
    
     最后RTO:
     RTO <- SRTT + max (G, K*RTTVAR)
    
  4. Linux中的RTO(Retransmission Timeout)

    这里说的是RHEL5.4的2.6.18内核,RFC-2988实现参考net/ipv4/tcp_input.c中的tcp_rtt_estimator和tcp_set_rto。可以看到,在Linux中alpha=1/8,RTO最小为TCP_RTO_MIN。因为我们的系统中RTT总是很小,所以RTO取值总是能够取到TCP_RTO_MIN。

    在看看TCP_RTO_MIN在Linux中的定义:

     123#define TCP\_RTO\_MAX     ((unsigned)(120*HZ))
     124#define TCP\_RTO\_MIN     ((unsigned)(HZ/5))
     (这里简单的介绍介绍一下HZ,HZ可以理解为1s,所以120*HZ就是120秒,HZ/5就是200ms。详细的:HZ表示CPU一秒种发出多少次时间中断--IRQ-0,Linux中通常用HZ来做时间片的计算,参考)
    
  5. 按照200ms计算linux系统15次重传时间:

     0.1 * (2 * 2 ^ 0 + 2 * 2 ^ 1 + ... + 2 * 2 ^ 15) = 0.2 * ( 2 ^ 16 - 1 ) = 6553.5s
    
     6553.5 / 60 = 109.225 min
    

    大约1小时40分钟