[原]【原创】TCP超时重传机制探索

标签: | 发表时间:2015-06-08 01:51 | 作者:heiyeshuwu
出处:http://blog.csdn.net/heiyeshuwu


TCP超时重传机制探索

作者:tll (360电商技术)


1)通信模型

TCP(Transmission Control Protocol)是一种可靠传输协议,在传输过程中当发送方(sender)向接收方(receiver)发送的数据丢失时,将引起发送方向接收方重传丢失的数据包。其通信模型如下:


 

图1

2)超时重传

重传机制在实现数据可靠传输功能的同时,也引起了相应的性能问题:何时进行数据重传?如何保证较高的传输效率?

重传时间过短:在网络因为拥塞引起丢包时,频繁的重传会进一步加剧网络拥塞,引起丢包,恶化网络传输性能。

重传时间过长:接收方长时间无法完成数据接收,引起长时间占用连接线路造成资源损耗、传输效率较低等问题。

针对上述问题,TCP中设计了超时重传机制。该机制规定当发送方A向B发送数据包P1时,开启一个时长为RTO(Retransmission Timeout)的重传定时器,如果A在RTO内未收到B对P1的确认报文,则认为P1在网络中丢失,此时重新发送P1。由此,引出RTO大小的设定问题。

对RTO大小的设定,由于的传输特性不同将导致发送与接收方完成一次数据传输(发送与应答)的时间不同(例:通常有线网络的传输速率远高于无线网络),因此固定大小的RTO无法满足不同环境下的传输需求,由此TCP采用针对具体传输环境动态测量的方式来确定当前时刻的RTO.

针对上述问题TCP中引入RTT(Round Trip Time),其中RTT为一个数据包从发出去到收到对该包确认的时间差,并根据RTT计算RTO.

由于RTT为单次测量的结果,常常受到网络迟延等因素的影响,波动较大,便记录多次的RTT值,通过加权移动的方式计算出一个更加合理的数值即SRTT(Smoothed RTT),根据SRTT计算RTO.由此一次RTO的计算通过如下过程得出:   

RTT---->SRTT---->RTO

对于上述数值的计算 RFC793做了相应描述,具体公式如下

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

RTO = min[UBOUND, max[LBOUND, (β*SRTT)]]

其中 UBOUND 为timeout的上限 (e.g., 1 minute),

     LBOUND 为timeout的下限 (e.g., 1 second),

α为平滑因子 (e.g., .8 to .9), 

β为时延变化因子 (e.g., 1.3 to 2.0).

由上式可以看出RTO的计算相对保守,每次新到的RTT对RTO影响较少,如此将导致RTO在RTT变化较大的环境中不能做及时调整,更好的适应当前环境。如此,Van jacobson在 Congestion Avoidance and Control 一文中对RTO的计算提出了一种快速算法


 

其中A为SRTT,M为最新RTT,D为偏差,g=1/2^n ,进一步


 

如此求得A与D,而RTO=A+4D,完成对RTO计算。

Linux中具体实现参考 tcp_rtt_estimator

 

其中而在Linux中RTO的最小值为200ms  

#define TCP_RTO_MIN((unsigned)(HZ/5))         /* 200ms */


3)快速重传

TCP继续发展,重传机制得到进一步加强,出现了快速重传。如下图所示:


图2

 

快速重传机制规定:发生丢包时,在重传定时器被触发之前,当发送方连续收到3个对丢失数据包的重传请求时将引起立即重传。

如上图所示,数据包2在发送过程中丢失,然而在此时的重传定时器未到达之前,发送方连续收到4个ACK,其中第一个为对数据包1的确认,后3个ACK在对收到的数据包4,5,6做选择性应答的同时,连续3次告知对方缺少对数据包2的接收,由此触发快速重传,数据包10为对丢失数据包2的重传。

此时如果超时计时未到,将使得发送方能更加及时的发送出待重传数据包;如果超时计时到达,则同样立即发送待重传数据包。

由此可看出,快速重传机制在一定程度上弥补了超时重传机制,使得重传更加及时。


4)选择性重传

由于网络传输路径往往是复杂的,数据包在传输中可能发生丢包或者乱序到达,而TCP只对连续的最后一个序列号做应答,使得乱序提前到达的数据包被重传,导致传输性能下降。

为改善此现状,RFC2018中提出了SACK(Selective Acknowledgement)。通过对ACK选项中添加已经接收的不连续数据块信息,通过对方不必重复发送对方已经接收的乱序数据块。

其中TCP首部中SACK选项如下所示:


图3

选项中分别用Left Edge of Block 与 Right Edge of Block来表示一个不连续数据块的第一个数据序号和最后一个数据序号+1,由此Right Edge of Block(n)与Left Edge of Block(n-1) – 1 的间隔表示丢失数据段。


  图4

 

如上图所示,发送方在发送报文段5,6丢失的情况下,接收方应答报文9完成对序列号201之前数据的应答,同时以SACK  301-401 501-601告知对方已接收数据段。发送方此时只需重传丢失数据段201-300以及401-500之间的数据即可。

选择重传的出现,在一定程度上大大降低了网络重传的数量,提高了网络吞吐量。

 

 

5)定时器的开启


 

图5

 

a. 重传计时器对哪些数据包进行计数?

TCP对每一个连接采用一个重传计时器,当定时器已被使用时,当前发送的数据段不被计时。

如上图所示,由于发送数据段3时启动计时器,所以数据段4在计时器结束之前不再计时。

b. 重传计时器的起始时间?

如图发送数据段3,开启计时器,同时记录此时发送数据包的SEQ(257),在接收到含有SEQ的ACK时,完成计时。如确认段5对SEQ 513之前数据的确认,包含RTT#2 计时起始的SEQ(257),此时RTT#2完成计时。

同理RTT#3中开启计时时SEQ(769)此时确认段8中是对SEQ在769之前的确认(不包含769),所以此时RTT3并不结束。


6)重传次数与时间

图2描述了网络中生成一次丢包与重传的情景,然而网络的传输场景是复杂的,引起网络的多次重传,针对连续的重传定时TCP采用了指数退让的方式来降低网络负载。


 

                         图6

 

如上图所示,在第12数据包发生丢失时,连续重传13,14,15,16,17号数据包,其间隔时间分别为6s,12s,24s,48s,96s

 

1)为什么不是准确的2倍?

Linux同BSD版TCP采用500ms作为一个滴答的定时器完成定时功能。例定时6s则需要记录12次滴答即可。

如下图所示,TCP设置一个6s定时器,则在第0个滴答到来时,完成计时。由于计时开始发生在12到11的任意时间,所以此时完成计时的时间将在5.5~6s之间。


 图7

 

2)关于默认值


 

如此可看出,默认重传次数为3,最高重传次数为15

 

3)关于参数的设置与服务的配置

a. 内核中参数的设置

proc文件中查看当前网络协议栈等内核信息

sysctl –a 显示所有系统参数

例查看ipv4一些参数的设置:


 

图8

通过echo完成对内核参数的动态修改,重启失效。

在/etc/sysctl.conf文件中完成对参数的修改,使用sysctl –p 使之永久生效。

 

b. Web server中TCP的参数设置

 Apache中对网络连接的设置:


 

图9

 

c. 应用程序对TCP连接参数的设置

通过setoptsock对socket选项完成对连接参数的设置,包括拥塞算法、保活时间等参数


 

setoptsock---> tcp_setsockopt ---> do_tcp_setsockopt

其中do_tcp_setsockopt部分代码如下:


 

7)小结

TCP是一项复杂的协议,重传机制作为其保证进行可靠传输而存在,致使网络编程(TCP和UDP)是一个相对复杂的任务,可以使用默认参数进行传输,然而为了提升传输性能,往往需要针对具体的环境做相应的参数设置与细节处理。例如对MTU(Maximum Transmission Unit)的考虑,不同的网络传输环境MTU可能不同,采用同等较大的数据包传输层则会引起传输效率问题,传输数据包过大会引起分片,数据包过小带块利用率较低(其中TCP数据字节流传输,用户发送数据时在传输层受限与MSS大小完成数据段分割;UDP为数据报传输,IP报文段大小受限于链路层MTU的大小,过大的数据包将完成数据分片并带来性能损耗,所以应尽量在应用层完成对报文段大小的确认,避免传输过程中不必要的分片过程)。

对保活连接时长和重传请求次数以及拥塞控制算法的选取都与应用场景有着密切的关系。如果需要进一步提升网络性能需要对具体参数做针对性调整。

 

<完>


-------------------------------------------------------------------------------------

黑夜路人,一个关注开源技术、乐于学习、喜欢分享的程序员


博客: http://blog.csdn.net/heiyeshuwu

微博: http://weibo.com/heiyeluren

微信: heiyeluren2012  

想获取更多IT开源技术相关信息,欢迎关注微信!

微信二维码扫描快速关注本号码:



作者:heiyeshuwu 发表于2015/6/7 17:51:07 原文链接
阅读:31 评论:0 查看评论

相关 [原创 tcp] 推荐:

[原]【原创】TCP超时重传机制探索

- - heiyeluren的blog(黑夜路人的开源世界)
作者:tll (360电商技术). TCP(Transmission Control Protocol)是一种可靠传输协议,在传输过程中当发送方(sender)向接收方(receiver)发送的数据丢失时,将引起发送方向接收方重传丢失的数据包. 重传机制在实现数据可靠传输功能的同时,也引起了相应的性能问题:何时进行数据重传.

tcp/ip调优

- Lucseeker - 在路上
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接. 第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认;. 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;.

浅谈TCP优化

- - 火丁笔记
很多人常常对 TCP优化有一种雾里看花的感觉,实际上只要理解了TCP的运行方式就能掀开它的神秘面纱. Ilya Grigorik 在「 High Performance Browser Networking」中做了很多细致的描述,让人读起来醍醐灌顶,我大概总结了一下,以期更加通俗易懂. 传输数据的时候,如果发送方传输的数据量超过了接收方的处理能力,那么接收方会出现丢包.

TCP报文结构

- - 互联网 - ITeye博客
一、TCP报文结构如下:.  固定首部长度为20字节,可变部分0~40字节,各字段解释:. source port number:源端口,16bits,范围0~65525. target port number:目的端口,16bits,范围同上. sequence number:数据序号,32bits,TCP 连接中传送的数据流中的每一个字节都编上一个序号.

TCP 状态变化

- - 互联网 - ITeye博客
关闭socket分为主动关闭(Active closure)和被动关闭(Passive closure)两种情况. 前者是指有本地主机主动发起的关闭;而后者则是指本地主机检测到远程主机发起关闭之后,作出回应,从而关闭整个连接. 将关闭部分的状态转移摘出来,就得到了下图:. 通过图上,我们来分析,什么情况下,连接处于CLOSE_WAIT状态呢.

TCP/IP分享——链路层

- Goingmm - 弯曲评论
在张国荣自尽8周年纪念日,也就是愚人节的前几十分钟,终于把第二章弄完了. 首席似乎不是特别有空,我就斗胆在这里自己发了,从前面2期的反响来看,相当热烈,我也是摆出一副要杀要剐,悉听尊便的架势,这可能是受最近流行霸气外露的影响,批评几句又伤不了皮毛,也影响不了我的工作和正常生活,只要给大家带来快乐,我就很开心,似乎历史上很多想法都是在争吵中诞生的.

TFO(tcp fast open)简介

- chenqj - pagefault
原创文章,转载请注明: 转载自pagefault. 本文链接地址: TFO(tcp fast open)简介. 这个是google的几个人提交的一个rfc,是对tcp的一个增强,简而言之就是在3次握手的时候也用来交换数据. 这个东西google内部已经在使用了,不过内核的相关patch还没有开源出来,chrome也支持这个了(client的内核必须支持).

TCP/IP重传超时--RTO

- dennis - 一个故事@MySQL DBA
Shared by 子非鱼 安知余(褚霸). 概述:本文讨论主机在发送一个TCP数据包后,如果迟迟没有收到ACK,主机多久后会重传这个数据包. 主机从发出数据包到第一次TCP重传开始,RFC中这段时间间隔称为retransmission timeout,缩写做RTO. 本文会先看看RFC中如何定义RTO,然后看看Linux中如何实现.

TCP协议通讯流程

- - 操作系统 - ITeye博客
服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回.

TCP短链接调优

- - 操作系统 - ITeye博客
最近在做一个项目,用到HttpClient查询数据,由于服务端强制做成了短链接(大家都知道http1.1默认是带有keepalive机制),导致了请求方TCP状态很多都是TIME_WAITZ状态,端口被全部占用,请求失败. net.ipv4.tcp_tw_reuse = 1 表示开启重用. 允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;.