• TCP/IP重传超时--RTO


    概述:本文讨论主机在发送一个TCP数据包后,如果迟迟没有收到ACK,主机多久后会重传这个数据包。主机从发出数据包到第一次TCP重传开始,RFC中这段时间间隔称为retransmission timeout,缩写做RTO。本文会先看看RFC中如何定义RTO,然后看看Linux中如何实现。本文旨在分享:当遇到了TCP层问题改如何去查找、阅读文档,该如何去在Linux源码中寻求答案。

    1. 起源

    在分析MySQL Semi-sync故障时,我们用Tcpdump+Wireshark(感谢淘宝雕梁)抓住当时的网络包传送细节,观察到了一次TCP重传最终导致了Semi-sync超时:

    看到两次传送间隔约201毫秒,即第一次传输201毫秒后,还没有收到ACK响应,TCP认为传输超时,开始重传。

    疑问:host和host之间的RTT大约是0.5毫秒,为什么第一次重传需要等200毫秒?(我希望是<20ms)socket程序可以配置吗RTO吗?TCP有参数可配置RTO吗?

    2. Google/书籍/RFC

    翻开TCP/IP详解找到关于TCP Retransmission章节,较详细的介绍TCP的超时机制,书中是个概述,于是又找到RFC1122。

    RFC1122的4.2.2.15和4.2.3.1都介绍了Retransmission Timeout的处理(说来惭愧,这是第一次阅读TCP相关RFC)。

    RFC中搜索Retransmission发现RFC 793 1122 2988 6298都有对重传算法、和初次重传超时的描述。于是开始阅读这个四个RFC,耗时约2小时,了解了大致的重传超时算法。

    3. RFC中如何计算RTO(Retransmission Timeout)

    3.1 RFC-793如何计算RTO

    概述:先根据该socket的RTT计算出SRTT(Smoothed Round Trip Time),然后根据一个最大、最小超时时间确定当前RTO。说明:srtt可以理解为“平滑化”的RTT,即在保持计算简单的情况尽量考虑历史RTT。

    详细计算: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分别设置了一个上限和下限。

    3.2 RTO重传间隔是指数增加的

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

    3.3 RFC-2988和RFC-6298中的RTO计算

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

    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中的定义:

    (这里简单的介绍介绍一下HZ,HZ可以理解为1s,所以120*HZ就是120秒,HZ/5就是200ms。详细的:HZ表示CPU一秒种发出多少次时间中断--IRQ-0,Linux中通常用HZ来做时间片的计算,参考)

    5. 其他: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就会告诉应用层说:“搞不定了,包怎么都传不过去!”

    6. 最后

    回答前面的问题:即使RTT很小(0.8ms),但是因为RTO有下限,最小必须是200ms,所以这是RTT再小也白搭;RTO最小值是内核编译是决定的,socket程序中无法修改,Linux TCP也没有任何参数可以改变这个值。

    好了,不容易。

    参考文献

    1. RFC 1122 ... (在哪儿查找RFC) TCP协议相关的RFC:
    RFC 675 - Specification of Internet Transmission Control Program, December 1974 Version
    RFC 793 - TCP v4
    RFC 1122 - includes some error corrections for TCP
    RFC 1323 - TCP-Extensions
    RFC 1379 - Extending TCP for Transactions—Concepts
    RFC 1948 - Defending Against Sequence Number Attacks
    RFC 2018 - TCP Selective Acknowledgment Options
    RFC 2988 - Computing TCP's Retransmission Timer
    RFC 4614 - A Roadmap for TCP Specification Documents
    RFC 5681 - TCP Congestion Control

    原文链接:http://www.orczhou.com/index.php/2011/10/tcpip-protocol-start-rto/

  • 相关阅读:
    view间传值的方法总结
    初学者关于内存的思考(不断加深不断更新中)
    UITableView刷新数据reLoadData
    rsync安装指南
    Makefile完全解析PART5.使用变量
    Makefile完全解析PART10.使用make更新函数库文件
    windows linux 文件同步 cwrsync工具
    Makefile完全解析PART4.书写命令
    Makefile完全解析PART7.使用函数
    RSYNC安装使用详解
  • 原文地址:https://www.cnblogs.com/a3192048/p/12241268.html
Copyright © 2020-2023  润新知