打赏

牛客网Java刷题知识点之拥塞发生的主要原因、TCP拥塞控制、TCP流量控制、TCP拥塞控制的四大过程(慢启动、拥塞避免、快速重传、快速恢复)

 

 

  不多说,直接上干货!

 

 

福利 => 每天都推送 

欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑         Java全栈大联盟
 
     每天都有大量的学习视频资料和精彩技术文章推送... 人生不易,唯有努力。
 
     百家号 :九月哥快讯               快手号:  jiuyuege
 
 
 
 
 
 
 

 

 

什么是拥塞?

  当大量的分组进入通信子网,超出了网络的处理能力时,就会引起网络局部或整体性能下降,这种现象称为拥塞。拥塞常常使问题趋于恶化。

       另一种对拥塞的解释,即对资源的需求超过了可用的资源。若网络中许多资源同时供应不足,网络的性能就要明显变坏,整个网络的吞吐量随之负荷的增大而下降。

 

 

 

 

 

拥塞的发生与其不可避免   
  拥塞发生的主要原因在于网络能够提供的资源不足以满足用户的需求,这些资源包括缓存空间、链路带宽容量和中间节点的处理能力。由于互联网的设计机制导致其缺乏“接纳控制”能力,因此在网络资源不足时不能限制用户数量,而只能靠降低服务质量来继续为用户服务,也就是“尽力而为”的服务

  拥塞其实是一个动态问题,我们没有办法用一个静态方案去解决,从这个意义上来说,拥塞是不可避免的

 

  静态解决问题办法1:
    例如:增加缓存空间到一定程度时,只会加重拥塞,而不是减轻拥塞,这是因为当数据包经过长时间排队完成转发时,它们很可能早已超时,从而引起源端超时重发,而这些数据包还会继续传输到下一路由器,从而浪费网络资源,加重网络拥塞。事实上,缓存空间不足导致的丢包更多的是拥塞的“症状”而非原因。另外,增加链路带宽及提高处理能力也不能解决拥塞问题。
  静态解决问题办法2:
    例如:我们有四台主机ABCD连接路由器R,所有链路带宽都是1Gbps,如果A和B同时向C以1Gbps的速率发送数据,则路由器R的输入速率为2Gbps,而输出速率只能为1Gbps,从而产生拥塞。避免拥塞的方法只能是控制AB的速率,例如,都是0.5Gbps,但是,这只是一种情况,倘若D也向R发送数据,且速率为1Gbps,那么,我们先前的修正又是不成立的。

 

 

 

 

拥塞控制和流量控制的差别
       所谓拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能承受现有的网络负荷。
       流量控制往往指的是点对点通信量的控制,是个端到端的问题。流量控制所要做的就是控制发送端发送数据的速率,以便使接收端来得及接受。
 
 
 

 

 

TCP的拥塞控制   

  为什么需要拥塞控制?

  答:由于TCP采用了超时重传机制,如果拥塞不加以控制,将导致大量的报文重传,并再度引起大量的数据报丢弃,直到整个网络瘫痪。这种现象称为拥塞崩溃。

  在网络实际的传输过程中,会出现拥塞的现象,网络上充斥着非常多的数据包,但是却不能按时被传送,形成网络拥塞,其实就是和平时的堵车一个性质了。TCP设计中也考虑到这一点,使用了一些算法来检测网络拥塞现象,如果拥塞产生,变会调整发送策略,减少数据包的发送来缓解网络的压力。

 

       拥塞控制:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提:网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。

 

 

 

 

 

TCP的流量控制   
  • 早期的TCP协议只有基于窗口的流控制(flow control)机制,我们简单介绍一下,并分析其不足。   在TCP中,为了实现可靠性,发送方发出一个数据段之后要等待接受方相应的确认信息,而不是直接发送下一个分组。
  • 具体的技术是采用滑动窗口,以便通信双方能够充分利用带宽。滑动窗口允许发送方在收到接收方的确认之前发送多个数据段。窗口大小决定了在收到目的地确认之前,一次可以传送的数据段的最大数目。窗口大小越大,主机一次可以传输的数据段就越多。当主机传输窗口大小数目的数据段后,就必须等收到确认,才可以再传下面的数据段。例如,若视窗的大小为 1,则传完数据段后,都必须经过确认,才可以再传下一个数据段;当窗口大小等于3时,发送方可以一次传输3个数据段,等待对方确认后,再传输下面三个数据段。  
  •  窗口的大小在通信双方连接期间是可变的,通信双方可以通过协商动态地修改窗口大小。在TCP的每个确认中,除了指出希望收到的下一个数据段的序列号之外,还包括一个窗口通告,通告中指出了接收方还能再收多少数据段(我们可以把通告看成接收缓冲区大小)。如果通告值增大,窗口大小也相应增大;通告值减小,窗口大小也相应减小。但是我们可以发现,接收端并没有特别合适的方法来判断当前网络是否拥塞,因为它只是被动得接收,不像发送端,当发出一个数据段后,会等待对方得确认信息,如果超时,就可以认为网络已经拥塞了。
  • 所以,改变窗口大小的唯一根据,就是接收端缓冲区的大小了。   
  • 流量控制作为接受方管理发送方发送数据的方式,用来防止接受方可用的数据缓存空间的溢出。
  • 流控制是一种局部控制机制,其参与者仅仅是发送方和接收方,它只考虑了接收端的接收能力,而没有考虑到网络的传输能力;
  • 而拥塞控制则注重于整体,其考虑的是整个网络的传输能力,是一种全局控制机制。正因为流控制的这种局限性,从而导致了拥塞崩溃现象的发生。  

 

 

 

 

 

 

TCP拥塞控制的四大过程(慢启动、拥塞避免、快速重传、快速恢复)

  TCP的拥塞控制由4个核心算法组成:“慢启动”(Slow Start)、“拥塞避免”(Congestion voidance)、“快速重传 ”(Fast Retransmit)、“快速恢复”(Fast Recovery)。

   为了方便起见,把发送端叫做client,接收端为server,每个segment长度为512字节,阻塞窗口长度为cwnd(简化起见,下面以segment为单位),sequence number为seq_num,acknowledges number为ack_num。通常情况下,TCP每接收到两个segment,发送一个ack。

 

 

 

 

  (1)慢启动   
  早期开发的TCP应用在启动一个连接时会向网络中发送大量的数据包,这样很容易导致路由器缓存空间耗尽,网络发生拥塞,使得TCP连接的吞吐量急剧下降。由于TCP源端一开始并不知道网络资源当前的利用状况,因此新建立的TCP连接不能一开始就发送大量数据,而只能逐步增加每次发送的数据量,以避免上述现象的发生,这里有一个“学习”的过程。   假设client要发送5120字节到server,
  慢启动过程如下:   
    1、初始状态,cwnd=1,seq_num=1;client发送第一个segment。  
    2、server接收到512字节(一个segment),回应ack_num=513。
    3、client接收ack(513),cwnd=1+1=2;现在可以一次发送2个数据段而不必等待ack。   
    4、server接收到2个segment,回应ack_num=513+512*2=1537  。 
    5、client接收ack(1537),cwnd=2+1;一次发送3个数据段   。
    6、server接收到3个segment,回应2个ack,分别为ack_num=1537+1024=2561和ack_num=2561+512=3073   。
    7、client接收ack(2561)和ack(3073),cwnd=3+2=5;一次可以发送5个数据段,但是只用4个就满足要求了   。
    8、server接收到4个segment,回应2个ack,分别为4097,5121   9.已经发送5120字节,任务完成!
  总结一下: 当建立新的TCP连接时,拥塞窗口(congestion window,cwnd)初始化为一个数据包大小。源端按cwnd大小发送数据,每收到一个ACK确认,cwnd就增加一个数据包发送量。  

 

 

(1)慢启动算法是一个在连接上发起数据流的方法。

(2)慢启动过程:

         初始时将拥塞窗口的初始为一个MSS,每次收到一个报文段的确认时发送方将拥塞窗口增大一个MSS,并发送两个最大长度的报文段。两个报文段被确认后,则发送方复每个报文段的确认增加一个MSS,使得拥塞窗口变为4个MSS,这样每过一个RTT,发送速率就翻番。因此,在慢启动阶段以指数增长。

(3)慢启动的结束:

          当出现一个由超时指示的丢包事件,TCP发送方将cwnd设置为1,并重新开始慢启动。

 

 

 

 

 

  (2) 拥塞避免 
    可以想象,如果按上述慢启动的逻辑继续下去而不加任何控制的话,必然会发生拥塞,引入一个慢启动阈值ssthresh的概念,当cwnd<ssthresh的时候,tcp处于慢启动状态,否则,进入拥塞避免阶段。通常,ssthresh初始化为 64 Kbytes。   当cwnd = 64947 + 512 = 65459,进入拥塞避免阶段,假设此时seq_num = _101024:   
  1、client一次发送cwnd,但是先考虑头两个segment  。
     2、server回应ack_num = 102048   。
  3、client接收到ack(102048),cwnd = 65459 + [(512 * 512) /65459] = 65459 + 4 = 65463,也就是说,每接到一个ack,cwnd只增加4个字节。   
  4、client发送一个segment,并开启ack timer,等待server对这个segment的ack,如果超时,则认为网络已经处于拥塞状态,则重设慢启动阀值ssthresh=当前cwnd/2=65463/2=32731,并且,立刻把cwnd设为1,很极端的处理!
   5.此时,cwnd<ssthresh,所以,恢复到慢启动状态。
  总结一下:如果当前cwnd达到慢启动阀值,则试探性的发送一个segment,如果server超时未响应,TCP认为网络能力下降,必须降低慢启动阀值,同时,为了避免形势恶化,干脆采取极端措施,把发送窗口降为1,个人感觉应该有更好的方法。
 
 
 

(1)拥塞避免算法是一种处理丢失分组的方法。(当到达中间路由器的极限时,分组将被丢弃。)

(2)拥塞避免过程:

         进入拥塞避免时,拥塞窗口的值大约是上次遇到拥塞时值的一半,每个RTT只将拥塞窗口的值增加1个MSS.

(3)结束条件:超时或丢包。

 

 

 

 

 

  (3)(4)快速重传和快速恢复   
  前面讲过标准的重传,client会等待RTO时间再重传,但有时候,不必等这么久也可以判断需要重传,
快速重传
  例如:client一次发送8个segment,seq_num起始值为100000,但是由于网络原因,100512丢失,其他的正常,则server会响应4个ack(100512)(为什么呢,tcp会把接收到的其他segment缓存起来,ack_num必须是连续的),这时候,client接收到四个重复的ack,它完全有理由判断100512丢失,进而重传,而不必傻等RTO时间了。  
  快速恢复
  我们通常认为client接收到3个重复的ack后,就会开始快速重传,但是,如果还有更多的重复ack呢,如何处理?这就是快速恢复要做的,事实上,我们可以把快速恢复看作是快速重传的后续处理,它不是一种单独存在的形态。   
 
以下是具体的流程:  
  假设此时cwnd=70000,client发送4096字节到server,也就是8个segment,起始seq_num = _100000:   
  1、client发送seq_num = _100000   。
  2、seq_num =100512的segment丢失  。 
  3、client发送seq_num = _101024   。
  4、server接收到两个segment,它意识到100512丢失,先把收到的这两个segment缓存起来  。 
  5、server回应一个ack(100512),表示它还期待这个segment  。
  6、client发送seq_num = _101536   。
  7、server接收到一个segment,它判断不是100512,依旧把收到的这个segment缓存起来,并回应ack(100512)  。
  8、以下同6、7,直到client收到3个ack(100512),进入快速重发阶段。   
  9、重设慢启动阀值ssthresh=当前cwnd/2=70000/2=35000   。
  10、client发送seq_num = 100512     以下,进入快速恢复阶段。   
  11、重设cwnd = ssthresh + 3 segments =35000 + 3*512 = 36536,之所以要加3,是因为我们已经接收到3个ack(100512)了,
              根据前面说的,每接收到一个ack,cwnd加1   。
  12、client接收到第四个、第五个ack(100512),cwnd=36536+2*512=37560  。
    13、server接收到100512,响应ack_num = _104096   14.此时,cwnd>ssthresh,进入拥塞避免阶段。

 

 

(1)执行条件及过程

     当收到3个或3个以上的重复ACK时,就非常有可能是一个报文段丢失了。于是我们就重传丢失的数据报文段,而不等待超时定时器溢出。这就是快速重传。接下来执行的不是慢启动,而是拥塞避免,这就是快速恢复。

(2)原因:

    没有执行慢启动的原因是由于收到的重复的ACK不仅仅告诉我们一个分组丢失了。由于接收方只有在收到另一个报文段时才会产生重复的ACK,而该报文段已经离开网络并进入了接收方的缓存。也就是说在收发两端之间仍然有流动的数据,而我们不想执行慢启动来突然减少数据流。

 

 

 

 

 

 

  真实例子

  想想看,能不能把TCP解决拥塞的方法应用到交通拥塞呢?   我们有两个原则:一是拥塞不可避免,单纯增加资源并不能避免拥塞的发生,只能用动态的方法加以解决;二是数据包守恒原则。政府花费很大资金修路,并不能避免堵车,只能从源头控制,例如首先限制车辆进入主路,根据实际情况,再慢慢增加每一个路口的车流量,但是,当达到一个阀值,增加速度要放缓,并不时探测整个主路的拥堵情况,如果情况危急,立刻封闭半个路口,并将车流量降到最低,也就是重新回复到慢启动状态。   呵呵,有趣!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

欢迎大家,加入我的4个微信公众号:    大数据躺过的坑     Java从入门到架构师    人工智能躺过的坑     Java全栈大联盟    
 
 
 

同时,大家可以关注我的个人博客

   http://www.cnblogs.com/zlslch/   和     http://www.cnblogs.com/lchzls/      http://www.cnblogs.com/sunnyDream/   

   详情请见:http://www.cnblogs.com/zlslch/p/7473861.html

 

  人生苦短,我愿分享。本公众号将秉持活到老学到老学习无休止的交流分享开源精神,汇聚于互联网和个人学习工作的精华干货知识,一切来于互联网,反馈回互联网。
  目前研究领域:大数据、机器学习、深度学习、人工智能、数据挖掘、数据分析。 语言涉及:Java、Scala、Python、Shell、Linux等 。同时还涉及平常所使用的手机、电脑和互联网上的使用技巧、问题和实用软件。 只要你一直关注和呆在群里,每天必须有收获

 

      对应本平台的讨论和答疑QQ群:大数据和人工智能躺过的坑(总群)(161156071) 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

     打开百度App,扫码,精彩文章每天更新!欢迎关注我的百家号: 九月哥快讯

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2017-10-01 21:01  大数据和AI躺过的坑  阅读(2372)  评论(0编辑  收藏  举报