TCP快速重传与快速恢复原理分析

原文转自:http://blog.csdn.net/zhangskd/article/details/7174682

超时重传是TCP协议保证数据可靠性的一个重要机制,其原理是在发送一个数据以后就开启一个计时器,
在一定时间内如果没有得到发送数据报的ACK报文,那么就重新发送数据,直到发送成功为止。这是数据
包丢失的情况下给出的一种修补机制。一般来说,重传发生在超时之后,但是如果发送端接收到3个以上
的重复ACK,就应该意识到,数据丢了,需要重新传递。这个机制不需要等到重传定时器溢出,所以叫
做快速重传,而快速重传以后,因为走的不是慢启动而是拥塞避免算法,所以这又叫做快速恢复算法。

快速重传和快速恢复旨在:快速恢复丢失的数据包。
没有快速重传和快速恢复,TCP将会使用定时器来要求传输暂停。在暂停这段时间内,没有新的数据包
被发送。
快速重传和快速恢复算法是在4.3BSD中提出的,并在RFC2001和RFC2581中描述。
快速重传与快速恢复经历了几个阶段。

1. Tahoe

Tahoe算法是TCP的早期版本。它的核心思想是:让cwnd以指数增长方式迅速逼近可用信道容量,然后
慢慢接近均衡。Tahoe包括3个基本的拥塞控制算法:慢启动、拥塞避免、快速重传。

我们可以看到,Tahoe不存在快速恢复算法。这也是它的不足之处。
在收到3个重复ACK或者在超时的情况下,Tahoe置cwnd为1,然后进入慢启动阶段。这一方面会引起网
络的激烈震荡,另一方面大大降低了网络的利用率。
也就是说,一旦发现掉包,那么cwnd就被打回原形。

没有快速恢复算法,在恢复丢失数据包期间,不能发送新的数据包,这段时间的吞吐量为0。而实际上
如果利用这段时间来发送适量的新数据包,可以大大的提高丢包时的传输效率。这就是快速恢复名称的
由来。

2. Reno

Reno与Tahoe相比,增加了快速恢复阶段,也就是说,完成快速重传后,进入了拥塞避免阶段而不是慢
启动阶段。
Reno prevents the communication path from going empty after Fast Retransmit.
Reno sender uses additional incoming dup ACKs to clock subsequent outgoing packets.
算法描述:

[java] view plain copy

  1. step1:
  2. if ( dupacks >= 3 ) {
  3. ssthresh = max( 2 , cwnd / 2 ) ;
  4. cwnd = ssthresh + 3 * SMSS ;
  5. }
  6. step2:重传丢失的分组
  7. step3:此后每收到一个重复的ACK确认时,cwnd++
  8. step4:当收到对新发送数据的ACK确认时,cwnd = ssthresh,这个ACK能够对那些在
  9. 丢失的分组之后,第一个重复ACK之前发送的所有包进行确认。

在快速恢复阶段,每收到重复的ACK,则cwnd加1;收到非重复ACK时,置cwnd = ssthresh,
转入拥塞避免阶段;如果发生超时重传,则置ssthresh为当前cwnd的一半,cwnd = 1,重新进入
慢启动阶段。
Reno快速恢复阶段退出条件:收到非重复ACK。

3. NewReno

Reno不能有效的处理多个分组从同一数据窗口丢失,于是有了NewReno。
NewReno修改了Reno的快速恢复算法,处理一个窗口中的多个报文段同时丢失时出现的“部分确认”
(Partial ACKs,它在快速恢复阶段到达并且确认新数据,但它只确认进入快速重传之前发送的一部分
数据)。
在这种情况下,Reno会退出快速恢复状态,等待定时器溢出或者重复的确认ACK到达,但是NewReno
并不退出快速恢复状态,而是:

[java] view plain copy

  1. step1:重传紧接着那个部分ACK之后的报文段,拥塞窗口等于其减去partial ACK的部分。
  2. step2:对于得到确认的新数据,cwnd++
  3. step3:对于第一个或每一个Partial ACK,重传定时器复位。且每次都重置cwnd = 原cwnd / 2。

NewReno算法中有变量recover,其值为检测到丢包时的最大发送序列号。只有当recover之前的数据
报都确认完后,才能推出快速恢复,进入拥塞避免阶段。
当超时时,将发送的最大序列号保存在recover变量中,结束快速恢复过程。
NewReno不支持SACK。

 4. SACK

During Fast Recovery, SACK maintains a variable calledpipe that represents the estimated number
of packets outstanding in the path. 
 The sender only sends new or retransmitted data when the estimated number of packets in the path
is less than the congestion window. The variable pipe is incremented by one when the sender either
sends a new packet or retransmits an old packet. It is decremented by one when the sender receives
a dup ACK packet with a SACK option reporting the new data has been received at the receiver.

Use of the pipe variable decouples the decision of when to send a packet from the decision of which
packet to send.

The sender maintains a data structure, thescoreboard, that remenbers acknowledgements from
previous SACK option. When the sender is allowed to send a packet, it retransmits the next packet
from the list of packets inferred to be missing at the receiver. If there are no such packets and the
receiver‘s advertised window is sufficiently large, the sender sends a new packet.

When a retransmitted packet is itself dropped, the SACK implementation detects the drop with a
retransmit timeout, retransmitting the dropped packet and then slow-starting.
The sender exits Fast Recovery when a recovery acknowledgement is received acknowledging
all data that was outstanding when Fast Recovery was entered.

[java] view plain copy

  1. step 1:
  2. Fast Recovery is initiated,
  3. pipe -1 ( for the packet assumed to have been dropped).
  4. pipe +1 ( for the packet retransmitted)
  5. cwnd = cwnd / 2
  6. step 2 :
  7. If pipe <= cwnd,sender retransmits packets inferred to be missing.
  8. If there are no such packets, sender sends new packets.
  9. step 3:
  10. when sender receives a dup ACK, pipe = pipe - 1
  11. when sender sends a new / retransmit an old packet, pipe = pipe +1
  12. step 4:
  13. For partial ACKs :pipe = pipe - 2
  14. (one for original dropped packet,one for retransmitted packet)
  15. step 5:
  16. all packets outstanding before Fast Recovery were ACKed,
  17. exit Fast Recovery.
  18. 当退出Fast Recovery时,cwnd同样恢复成ssthresh,进入拥塞避免。

与Reno不同的是:

(1)when to send packet:由计算pipe变化决定,不再是计算cwnd变化。
(2)which packet to send:由SACK携带信息决定,反应更迅速。

问题1:在一个窗口内重复丢包会造成影响吗?

答案:会。如果只丢一个包,那么收到非重复ACK时,就能确认完本窗口内所有的包。然后进入拥塞
避免阶段。这就是Reno想达到的。
而如果丢失多个包,那么收到非重复ACK时,不能确认完本窗口内所有的包。但是,也会退出快速恢复,
进入拥塞避免阶段。

这个时候可能会发生两种情况:
(1)多次进行快速重传和快速恢复。又发现丢包,再次进入快速重传和快速恢复。注意,每次进入
快速重传和快速恢复时,ssthresh和cwnd都要减半。多次丢包最终会导致ssthresh指数减小。
通过画cwnd(t)图可以发现,不仅这段时间吞吐量非常低,而且导致恢复完后拥塞避免的起点非常低,从
而导致之后的吞吐量也很低。

(2)经过多次快速重传和快速恢复,接着发生传输超时。
那么,发生传输超时需要什么样的条件呢?

1) when two packets are dropped from a window of data, the Reno sender is forced to wait for a
retransmit timeout whenever the congestion window is less than 10 packets when Fast
Recovery is initiated, and whenever the congestion window is within two packets of the receiver‘s
advertised window when Fast Recovery is initiated.

2) when three packets are dropped from a window of data, the Reno sender is forced to wait for
a retransmit timeout whenever the number of packets between the first and the second dropped
packets is less than 2 + 3W/4, for W the congestion window just before the Fast Retransmit.

这种情况出现的概率极大,也就是说一个窗口出现3个丢包,有大概率出现超时。当丢包时窗口大小
为15,有三个丢包,那么无论丢包的顺序如何,2次FR/FR之后,总会出现超时。
超时一般是因为未确认的数据包 > 可以使用的cwnd,不能发送新的数据,而网络中有没有足够的
重复ACK来触发FR/FR。

问题2:为什么发生拥塞时,还增加cwnd?

答案:在检测到丢包时,窗口为cwnd。这时候网络中最多有cwnd个包(in_flight < cwnd )。每当收到
一个重复的ACK,则说明有数据包离开网络,达到接收端了。那么,此时网络中还可以再容纳1个包。由
于发送端滑动窗口不能移动了,所以如果想保持in_flight,可以使cwnd++。
这样一来,可以提高吞吐量。而实际上,在fast recovery期间发送的新数据包比起发生丢包的cwnd来说,
已经是大大减少了。

性能分析

Tahoe没有快速恢复机制,在丢包后,它不仅重发了一些已经成功传输的数据,而且在恢复期间吞吐量
也不高。
利用SACK option携带的信息,我们能够提前知道哪些数据包丢失了。NewReno每个RTT内只能恢复
一个丢失的数据包,所以如果丢失了N个数据包,那么Fast Recovery就要持续N*RTT的时间,当N比较
大时,这是一段相当长的时间。而SACK则没有这个限制,依靠SACK option的信息,它能够同时恢复
多个数据包,更加快速和平稳的恢复。
当发生同一窗口多个丢包时,SACK和NewReno最终都能够较为快速和平稳的恢复过来。而Reno则经
常出现超时,然后再用慢启动来恢复,这个时候Reno的表现就如同Tahoe,会造成已接受数据的重复
传送。Reno恢复期间会出现吞吐量低、恢复时间长、不必要重发数据、恢复结束后阈值过低等一些问
题,严重的影响性能。

结论

经过上述分析我们可以看出:

It is a fundamental consequence of the absence of SACK that the sender has to choose between
the following strategies to recover from lost data:

(1)retransmitting at most one dropped packet per round-trip time

(2)retransmitting packets that might have already been successfully delivered.

Reno and New-Reno use the first strategy, and Tahoe uses the second.
With SACK, a sender can avoid unnecessary delays and retransmissions, resulting in improved
throughput.

SACK的不足

上面说了很多SACK的好话,现在来谈谈它的不足之处。

For a large BDP network where the number of packets are in flight, the procesing overhead of
SACK information at the end points can be quite overhelming because each SACK block invokes
a research into the large packet buffers of the sender for acked packets in the block, and every
recovery of a loss packet causes the same search at the receiver.

在BDP网络,这个问题尤其明显,会严重的消耗CPU而导致一系列问题。在一定程度上来说,此时
的SACK就像DOS攻击一样,每次遍历都要消耗大量CPU,时间复杂度为O(n^2),n为packets in
flight的数量。

The system overload can cause serious problem : it can cause multiple timeouts (as even packet
retransmission and receptions are delayed) and a long period of zero throughput.

当然,这是中等规模的BDP(100~1000)或大规模的BDP网络才需考虑的问题,对于一般的BDP而
言不会出现太大的问题。

时间: 2024-12-09 12:35:41

TCP快速重传与快速恢复原理分析的相关文章

通过packetdrill构造的包序列理解TCP快速重传机制

TCP的逻辑是极其复杂的,其学习曲线虽然很平缓但其每一步都是异常艰难,好在这些都是体力活,只要肯花时间也就不在话下了.想彻底理解一个TCP的机制,有个四部曲:1.读与其相关的RFC:2.看Linux协议栈的TCP实现:3.通过抓包以及其它工具来确认事实就是如此:4.解决一个与之相关的网络问题.经历了以上四步骤,相信任何人都可以在相关领域内稍微装逼一把了...        本文的内容是TCP快速重传机制,但是与其它文章不同的是,本文并不剖析源码实现,也不翻译RFC,更不是原理性介绍,而是通过一个

TCP怎么保证证包有序传输的,TCP的慢启动,拥塞避免,快速重传,快速恢复

TCP提供了最可靠的数据传输,它给发送的每个数据包做顺序化(这看起来非常烦琐),然而,如果TCP没有这样烦琐的操作,那么,可能会造成更多的麻烦.如造成数据包的重传.顺序的颠倒甚至造成数据包的丢失. 那么,TCP具体是通过怎样的方式来保证数据的顺序化传输呢? 主机每次发送数据时,TCP就给每个数据包分配一个序列号并且在一个特定的时间内等待接收主机对分配的这个序列号进行确认,如果发送主机在一个特定时间内没有收到接收主机的确认,则发送主机会重传此数据包.接收主机利用序列号对接收的数据进行确认,以便检测

TCP协议可靠性数据传输实现原理分析

http://blog.csdn.net/chexlong/article/details/6123087 TCP 协议是一种面向连接的,为不同主机进程间提供可靠数据传输的协议.TCP 协议假定其所使用的网络栈下层协议(如IP 协议)是非可靠的,其自身提供机制保证数据的可靠性传输.在目前的网络栈协议族中,在需要提供可靠性数据传输的应用中,TCP 协议是首选的,有时也是唯一的选择.TCP 协议是在最早由Cerf 和Kahn[1]所提出的有关网络数据包传输协议的概念之上建立的.TCP 协议被设计成符

QUIC协议原理分析(转)

之前深入了解了一下HTTP1.1.2.0.SPDY等协议,发现HTTP层怎么优化,始终要面对TCP本身的问题.于是了解到了QUIC,这里分享一篇之前找到的有意义的文章. 原创地址:https://mp.weixin.qq.com/s/vpz6bp3PT1IDzZervyOfqw 作者介绍:lancelot,腾讯资深研发工程师.目前主要负责腾讯 stgw(腾讯安全云网关)的相关工作,整体推进腾讯内部及腾讯公有云,混合云的七层负载均衡及全站 HTTPS 接入.对 HTTPS,SPDY,HTTP2,Q

TCP拥塞控制算法 优缺点 适用环境 性能分析

[摘要]对多种TCP拥塞控制算法进行简要说明,指出它们的优缺点.以及它们的适用环境. [关键字]TCP拥塞控制算法 优点    缺点   适用环境公平性 公平性 公平性是在发生拥塞时各源端(或同一源端建立的不同TCP连接或UDP数据报)能公平地共享同一网络资源(如带宽.缓存等).处于相同级别的源端应该得到相同数量的网络资源.产生公平性的根本原因在于拥塞发生必然导致数据包丢失,而数据包丢失会导致各数据流之间为争抢有限的网络资源发生竞争,争抢能力弱的数据流将受到更多损害.因此,没有拥塞,也就没有公平

深入理解HTTP协议、HTTP协议原理分析

深入理解HTTP协议.HTTP协议原理分析 目录(?)[+] http协议学习系列 1. 基础概念篇 1.1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本.其中最著名的就是RFC 26

kafka producer实例及原理分析

1.前言 首先,描述下应用场景: 假设,公司有一款游戏,需要做行为统计分析,数据的源头来自日志,由于用户行为非常多,导致日志量非常大.将日志数据插入数据库然后再进行分析,已经满足不了.最好的办法是存日志,然后通过对日志的分析,计算出有用的数据.我们采用kafka这种分布式日志系统来实现这一过程. 步骤如下: 搭建KAFKA系统运行环境 如果你还没有搭建起来,可以参考我的博客: http://zhangfengzhe.blog.51cto.com/8855103/1556650 设计数据存储格式

AbstractQueuedSynchronizer的介绍和原理分析(转)

简介 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础.使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似acquire和release的方式来操纵状态.然而多线程环境中对状态的操纵必须确保原子性,因此子类对于状态的把握,需要使用这个同步器提供的以下三个方法对状态进行操作: java.util.concurrent.locks.Abstra

MySQL数据库InnoDB存储引擎多版本控制(MVCC)实现原理分析

文/何登成 导读:   来自网易研究院的MySQL内核技术研究人何登成,把MySQL数据库InnoDB存储引擎的多版本控制(简称:MVCC)实现原理,做了深入的研究与详细的文字图表分析,方便大家理解InnoDB存储引擎实现的多版本控制技术(简称:MVCC). 基本知识 假设对于多版本控制(MVCC)的基础知识,有所了解.MySQL数据库InnoDB存储引擎为了实现多版本的一致性读,采用的是基于回滚段的协议. 行结构 MySQL数据库InnoDB存储引擎表数据的组织方式为主键聚簇索引.由于采用索引