来自:后端技术指南针

0x00.前言

这是TCP/IP协议栈系列的第二篇文章,之前的一篇理解TCP/IP协议栈之HTTP2.0感兴趣可以看下,今天一起来学习下一个热点问题。

通过本文你将了解到以下内容:

  • 拥塞控制概念以及其背景

  • 流量控制和拥塞控制的区别与联系

  • 拥塞控制主要过程详解

伙伴们认真学习一下,让offer来得更猛烈些吧!

0x01.TCP/IP协议栈简要回顾

来看下维基百科对TCP/IP的一些介绍,笔者做了少量的修改来确保语句通顺:

互联网协议套件是一个网络通信模型以及整个网络传输协议家族,由于该协议簇包含两个核心协议:TCP(传输控制协议)和IP(网际协议),因此常被通称为TCP/IP协议族。

TCP/IP协议对于数据应该如何封装、定址、传输、路由以及在目的地如何接收等基本过程都加以标准化。它将通信过程抽象化为四个层次,并采取协议堆栈的方式分别实现出不同通信协议,实际使用的四层结构是七层OSI模型的简化。

我们可以看到TCP/IP协议栈是一个简化的分层模型,是互联网世界连接一切的基石,一起来看一张七层模型vs四层模型的简图:


TCP/IP协议栈过于庞大,篇幅所限本文不再做更多细节的描述。

0x02.流量控制和拥塞控制

TCP是一种面向连接的、可靠的、全双工传输协议,前辈们写了很多复杂的算法为其保驾护航,其中有一组像海尔兄弟一样的算法:流量控制和拥塞控制,这也是我们今天的主角。


2.1 流量控制简介

流量控制和拥塞控制从汉语字面上并不能很好的区分,本质上这一对算法既有区别也有联系。

维基百科对于流量控制Flow Control的说明:

In data communications, flow control is the process of managing the rate of data transmission between two nodes to prevent a fast sender from overwhelming a slow receiver.

It provides a mechanism for the receiver to control the transmission speed, so that the receiving node is not overwhelmed with data from transmitting node.

翻译一下:

在数据通信中,流量控制是管理两个节点之间数据传输速率的过程,以防止快速发送方压倒慢速接收方。

它为接收机提供了一种控制传输速度的机制,这样接收节点就不会被来自发送节点的数据淹没。

可以看到流量控制是通信双方之间约定数据量的一种机制,具体来说是借助于TCP协议的确认ACK机制和窗口协议来完成的。

窗口分为固定窗口和可变窗口,可变窗口也就是滑动窗口,简单来说就是通信双方根据接收方的接收情况动态告诉发送端可以发送的数据量,从而实现发送方和接收方的数据收发能力匹配。

这个过程非常容易捕捉,使用wireshark在电脑上抓或者tcpdump在服务器上抓都可以看到,大白在自己电脑上用wireshark抓了一条:


我们以两个主机交互来简单理解流量控制过程:


接收方回复报文头部解释:


图中RcvBuffer是接收区总大小,buffered data是当前已经占用的数据,而free buffer space是当前剩余的空间,rwnd的就是free buffer space区域的字节数。

HostB把当前的rwnd值放入报文头部的接收窗口receive window字段中,以此通知HostA自己还有多少可用空间, 而HostA则将未确认的数据量控制在rwnd值的范围内,从而避免HostB的接收缓存溢出。

可见流量控制是端到端微观层面的数据策略,双方在数据通信的过程中并不关心链路带宽情况,只关心通信双方的接收发送缓冲区的空间大小,可以说是个速率流量匹配策略。

流量控制就像现实生活中物流领域中A和B两个仓库,A往B运送货物时只关心仓库B的剩余空间来调整自己的发货量,而不关心高速是否拥堵。

2.2 拥塞控制的必要性

前面我们提到了微观层面点到点的流量控制,但是我们不由地思考一个问题:只有流量控制够吗?答案是否定的。

我们还需要一个宏观层面的控去避免网络链路的拥堵,否则再好的端到端流量控制算法也面临丢包、乱序、重传问题,只能造成恶性循环。

我们从一个更高的角度去看大量TCP连接复用网络链路的通信过程:

所以拥塞控制和每一条端到端的连接关系非常大,这就是流量控制和拥塞控制的深层次联系,所谓每一条连接都顺畅那么整个复杂的网络链路也很大程度是通畅的。

在展开拥塞控制之前我们先考虑几个问题:

  • 如何感知拥塞

TCP连接的发送方在向对端发送数据的过程中,需要根据当前的网络状况来调整发送速率,所以感知能力很关键。

在TCP连接的发送方一般是基于丢包来判断当前网络是否发生拥塞,丢包可以由重传超时RTO和重复确认来做判断。

  • 如何利用带宽

诚然拥塞影响很大,但是一直低速发包对带宽利用率很低也是很不明智的做法,因此要充分利用带宽就不能过低过高发送数据,而是保持在一个动态稳定的速率来提高带宽利用率,这个还是比较难的,就像茫茫黑夜去躲避障碍物。

  • 拥塞时如何调整

拥塞发生时我们需要有一套应对措施来防止拥塞恶化并且恢复连接流量,这也是拥塞控制算法的精要所在。

0x03.理解拥塞控制

前面我们提了拥塞控制的必要性以及重要问题,接下来一起看下前辈们是如何设计实现精彩的拥塞控制策略的吧!

3.1 拥塞窗口cwnd

从流量控制可以知道接收方在header中给出了rwnd接收窗口大小,发送方不能自顾自地按照接收方的rwnd限制来发送数据,因为网络链路是复用的,需要考虑当前链路情况来确定数据量,这也是我们要提的另外一个变量cwnd,笔者找了一个关于rwnd和cwnd的英文解释:

Congestion Window (cwnd) is a TCP state variable that limits the amount of data the TCP can send into the network before receiving an ACK.

The Receiver Window (rwnd) is a variable that advertises the amount of data that the destination side can receive.

Together, the two variables are used to regulate data flow in TCP connections, minimize congestion, and improve network performance.

笔者在rfc5681文档中也看到cwnd的定义:

这个解释指出了cwnd是在发送方维护的,cwnd和rwnd并不冲突,发送方需要结合rwnd和cwnd两个变量来发送数据,如图所示:

cwnd的大小和MSS最大数据段有直接关系,MSS是TCP报文段中的数据字段的最大长度,即MSS=TCP报文段长度-TCP首部长度。

3.2 拥塞控制基本策略

拥塞控制是一个动态的过程,它既要提高带宽利用率发送尽量多的数据又要避免网络拥堵丢包RTT增大等问题,基于这种高要求并不是单一策略可以搞定的,因此TCP的拥塞控制策略实际上是分阶段分策略的综合过程:

注:有的版本的TCP算法不一定没有快速恢复阶段

如图为典型的包含4个策略的拥塞控制:

如图为发生超时重传RTO时的过程:

3.3 TCP算法常见版本

实际上TCP算法有很多版本,每个版本存在一些差异,在这里简单看一下维基百科的介绍:

  • 算法命名规则

TCP+算法名的命名方式最早出现在Kevin Fall和Sally Floyd1996年发布的论文中。

  • TCP Tahoe 和TCP Reno

这两个算法代号取自太浩湖Lake Tahoe和里诺市,两者算法大致一致,对于丢包事件判断都是以重传超时retransmission timeout和重复确认为条件,但是对于重复确认的处理两者有所不同,对于超时重传RTO情况两个算法都是将拥塞窗口降为1个MSS,然后进入慢启动阶段。

TCP Tahoe算法:如果收到三次重复确认即第四次收到相同确认号的分段确认,并且分段对应包无负载分段和无改变接收窗口的话,Tahoe算法则进入快速重传,将慢启动阈值改为当前拥塞窗口的一半,将拥塞窗口降为1个MSS,并重新进入慢启动阶段。

TCP Reno算法:如果收到三次重复确认,Reno算法则进入快速重传只将拥塞窗口减半来跳过慢启动阶段,将慢启动阈值设为当前新的拥塞窗口值,进入一个称为快速恢复的新设计阶段。

  • TCP New Reno

TCP New Reno是对TCP Reno中快速恢复阶段的重传进行改善的一种改进算法,New Reno在低错误率时运行效率和选择确认SACK相当,在高错误率仍优于Reno。

  • TCP BIC 和TCP CUBIC

TCP BIC旨在优化高速高延迟网络的拥塞控制,其拥塞窗口算法使用二分搜索算法尝试找到能长时间保持拥塞窗口最大值,Linux内核在2.6.8至2.6.18使用该算法作为默认TCP拥塞算法。

CUBIC则是比BIC更温和和系统化的分支版本,其使用三次函数代替二分算法作为其拥塞窗口算法,并且使用函数拐点作为拥塞窗口的设置值,Linux内核在2.6.19后使用该算法作为默认TCP拥塞算法。

  • TCP PRR

TCP PRR是旨在恢复期间提高发送数据的准确性,该算法确保恢复后的拥塞窗口大小尽可能接近慢启动阈值。在Google进行的测试中,能将平均延迟降低3~10%恢复超时减少5%,PRR算法后作为Linux内核3.2版本默认拥塞算法。

  • TCP BBR

TCP BBR是由Google设计于2016年发布的拥塞算法,该算法认为随着网络接口控制器逐渐进入千兆速度时,分组丢失不应该被认为是识别拥塞的主要决定因素,所以基于模型的拥塞控制算法能有更高的吞吐量和更低的延迟,可以用BBR来替代其他流行的拥塞算法。

Google在YouTube上应用该算法,将全球平均的YouTube网络吞吐量提高了4%,BBR之后移植入Linux内核4.9版本。

3.4 拥塞控制过程详解

我们以典型慢启动、拥塞避免、快速重传、快速恢复四个过程进行阐述。

  • 慢启动

慢启动就是对于刚启动的网络连接,发送速度不是一步到位而是试探性增长,具体来说:连接最初建立时发送方初始化拥塞窗口cwnd为m,之后发送方在一个RTT内每收到一个ACK数据包时cwnd线性自增1,发送方每经过一个RTT时间,cwnd=cwnd*2指数增长,经过一段时间增长直到cwnd达到慢启动阈值ssthresh。

之后cwnd不再呈指数增长从而进入拥塞避免阶段(注cwnd增长的单位是MSS),当然如果在慢启动阶段还未到达阈值ssthresh而出现丢包时进入快速重传等阶段,需要注意的是如果网络状况良好RTT时间很短,那么慢启动阶段将很快到达一个比较高的发送速率,所以将慢启动理解为试探启动更形象。

  • 拥塞避免

当慢启动阶段cwnd的值到达ssthresh时就不再疯狂增长,进入更加理性的线性阶段直至发送丢包,本次的阈值ssthresh是上一次发生丢包时cwnd的1/2,因此这是一个承上启下的过程。

本次发送丢包时仍然会调整ssthresh的值,具体拥塞避免增长过程:发送方每收到一个ACK数据包时将cwnd=cwnd+1/cwnd,每经过一个RTT将cwnd自增1。

  • 超时重传和快速重传

TCP作为一个可靠的协议面临的很大的问题就是丢包,丢包就要重传因此发送方需要根据接收方回复的ACK来确认是否丢包了,并且发送方在发送数据之后启动定时器,如图所示:



RTO是随着复杂网络环境而动态变化的,在拥塞控制中发生超时重传将会极大拉低cwnd,如果网络状况并没有那么多糟糕,偶尔出现网络抖动造成丢包或者阻塞也非常常见,因此触发的慢启动将降低通信性能,故出现了快速重传机制。

所谓快速重传时相比超时重传而言的,重发等待时间会降低并且后续尽量避免慢启动,来保证性能损失在最小的程度,如图所示:

快速重传和超时重传的区别在于cwnd在发生拥塞时的取值,超时重传会将cwnd修改为最初的值,也就是慢启动的值,快速重传将cwnd减半,二者都将ssthresh设置为cwnd的一半。

从二者的区别可以看到,快速重传更加主动,有利于保证链路的传输性能,但是有研究表明3个ACK的机制同样存在问题,本文就不做深入阐述了,感兴趣的读者可以自主查阅。

快速重传是基于对网络状况没有那么糟糕的假设,因此在实际网络确实还算好的时候,快速重传还是很有用的,在很差的网络环境很多算法都很难保证效率的。

  • 快速恢复

在快速重传之后就会进入快速恢复阶段,此时的cwnd为上次发生拥塞时的cwnd的1/2,之后cwnd再线性增加重复之前的过程。

0x05.巨人的肩膀

  • https://andrewpqc.github.io/2018/07/21/tcp-flow-control-and-congestion-control/

  • https://blog.stackpath.com/glossary-cwnd-and-rwnd/

  • https://tools.ietf.org/html/rfc5681

  • https://courses.cs.washington.edu/courses/cse461/12sp/lectures/11-congestion-avoidance.html

  • https://juejin.im/post/5acae2b55188252b0b2013aa

  • https://www.zhihu.com/question/280521822

  • https://journal.accsindia.org/experiential-learning-of-networking-technologies-5/4/

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

长按订阅更多精彩▼如有收获,点个在看,诚挚感谢

面试热点|理解TCP/IP传输层拥塞控制算法相关推荐

  1. 前端工程师如何理解 TCP/IP 传输层协议?| 技术头条

    作者 | 浪里行舟 责编 | 郭芮 网络协议是每个前端工程师都必须要掌握的知识,TCP/IP 中有两个具有代表性的传输层协议,分别是 TCP 和 UDP,本文将介绍下这两者以及它们之间的区别. TCP ...

  2. 简单理解TCP/IP传输层协议TCP和UDP

    TCP/IP模型中的传输层主要负责端到端通信,和数据链路层类似,数据链路层负责点到点的通信.TCP/IP模型的传输层主要协议有TCP (Transmission Control Protocol,传输 ...

  3. TCP/IP传输层协议实现 - TCP连接的建立与终止(lwip)

    1.lwip tcp相关数据结构 1.1.tcp报文格式 <TCP-IP详解卷 1:协议>TCP包首部结构如下: 1.2.lwip tcp数据结构 tcp相关数据结构如下,tcp_pcb_ ...

  4. TCP/IP传输层协议实现 - TCP的超时与重传(lwip)

    (参考<TCP-IP详解卷 1:协议> 第21章 TCP的超时与重传) 1.往返时间测量(RTT) 1.1.分组交换和RTT测量示例 <TCP-IP详解卷 1:协议>中分组交换 ...

  5. TCP/IP传输层协议实现 - TCP接收窗口/发送窗口/通告窗口(lwip)

    1.tcp通告窗口/接收窗口/发送窗口 接收端有一个接收窗口大小,接收端只能接收这么多数据,接收窗口的数据需要被上层接收后才释放更大接收空间,才可以接收更多数据:接收窗口之前的数据已经被接收,再次接收 ...

  6. TCP/IP传输层协议实现 - TCP的坚持定时器(lwip)

    (参考<TCP-IP详解卷 1:协议>"第22章 TCP的坚持定时器") 1.糊涂窗口综合症 <TCP-IP详解卷 1:协议>"22.3 糊涂窗口 ...

  7. OSI与TCP/IP各层的结构与功能,都有哪些协议

    前言: 今天更新一下计算机网络的一些非常重要的知识,可能很多人都不知学计算机网络有什么用,我想说的是它真的比较重要,像咱们学校只要是学计算机这个专业都要学习这门课程.另外大家要是去一些像BAT,阿里, ...

  8. tcp报文格式_腾讯面试中的TCP/IP协议简述+经典面试题

    面试题有福利 TCP/IP协议简述+ TCP握手协议 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接. 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器, ...

  9. 2021年4月1日 深入理解网络层和传输层相关协议!!!

    深入理解网络层和传输层相关协议!!! ARP/ICMP/TCP和UDP协议!!! 关于ARP ARP协议概述 局域网中主机的通信 ·IP地址与MAC地址 什么是ARP协议 ·Address Resol ...

最新文章

  1. usaco Riding the Fences(欧拉回路模板)
  2. LibreOffice使用笔记
  3. 三菱modbusRTU通讯实例_「笔记」信捷plc应用,两个plc通讯篇
  4. Ubuntu上安装Air运行时和Air程序
  5. python dataframe取一列_python - 从pandas DataFrame列标题中获取列表
  6. ContextLoaderListener.contextInitialized - how is WebApplicationContext created
  7. 字母框如何影响UI内容的理解
  8. 最短路弗洛伊德(Floyd)算法加保存路径
  9. android中的tabdemo
  10. 注册tomcat为服务
  11. HTML5应用程序网站视差模板下载
  12. 定积分算法java_变步长梯形积分算法求解函数定积分
  13. linux ext3 大文件,Linux下Ext2与Ext3文件系统
  14. jfinal 普通java工程_JFinal getModel方法如何在java项目中使用
  15. oracle定时任务按照小时,ORACLE定时任务时间间隔设置
  16. 揭开宏的神秘面纱:什么是宏,为什么使用宏?
  17. 用html做一个分类目录网站,分类目录网站做外链
  18. FANUC机器人:奇异点回避功能介绍与使用方法
  19. [赛后总结]G2022 Regular Contest 04总结
  20. 马尔科夫链蒙特卡洛(MCMC)

热门文章

  1. 关于学习Python的一点学习总结(23->while语句与else)
  2. 习题7-1 选择法排序 (20 分)
  3. Connections in Galaxy War
  4. 解题报告:Fake Maxpooling(单调队列求矩阵的和)
  5. 96.不同的二叉搜索树
  6. Hibernate学习总结【比较与Mybatis框架之间的区别】
  7. Python 初体验
  8. 不使用fastreport自带的条码组件打印快递单(一款很不错的条码组件下载)
  9. Spark 学习文章
  10. Linux内核学习总结