网路是怎样连接的(八)TCP的性能优化(上)

思考重点

  • TCP具有那些性能优化机制?
  • 滑动窗口的特色?
  • 滑动窗口发生丢包怎麽办?

核心知识

一系列的优化机制

起初的TCP采用一问一答模式,也就是说发送方一定要等到接收方返回ACK消息才能进行下一个封包的发送,撇除逾时不说,在等待的过程中等於发送方什麽事也不能做,白白浪费了这一段时间。

为了解决这个问题,发明了滑动视窗控制,使得在等待的过程中也可以持续发送封包消息,并且滑动视窗拥有比逾时重传更高效的高速重送机制,大大提升了效率问题

实现滑动视窗目的: 提高通讯效率问题

但问题来了,这麽高密度的传送封包,接收方可以承受得住吗?其实接收方有配备一个专门用来接收封包的缓冲区,若是发送来的封包来不及处理,可以先暂时储存到缓冲区中,等待之後应用程序来捞数据。问题看似解决了,其实没有。

当发送方的封包到达速率远远大於接收方处理封包的速率,就会造成缓冲区溢出问题,因此需要引入了流量控制,还记得前面提到的视窗大小吗?引入流量控制会依据接收方缓冲区当前剩余的容量来告知发送方发送封包的限制大小

实现流量控制目的: 依照接收方缓冲区大小调整封包的视窗大小

既然我们实现了高效的通讯机制以及及时调整视窗大小的功能,大抵上应该没有任何问题了吧?

请大家不要忽略了封包现实传送中的状况,以上两点的判断背景都是假设封包在传送路途中没有历经各种网路塞车问题,换言之就是将封包往返时间看成一个不变的定值,也可以说是完美的状态。

但在现实场景,网路的连线品质是一直在变动的。由於这个问题,我们不得不考虑接收方计算出来的视窗大小是否符合当前网路的连线能力,有点像高速公路目前只能容忍10台车,这时候你硬要派20台车上路,结果可想而知

实现壅塞控制目的: 依照真实情景调整允许的视窗大小,若视窗大小超过上限,则以上限为主

视窗控制

视窗控制的目的就是为了提高单位时间内发送封包的效率,而视窗控制使用了视窗大小这个概念,由接收方判断当前缓冲区可以储存多长的资料,再透过ACK告知发送方。右图中假设视窗大小为4000bytes,因此MSS长度为1000bytes的封包可以连续发送四次,这种有别於一般一问一答式的收发模式称为滑动窗口

我们假设要传送的TCP封包总长度10000bytes,从图中可以看出单位时间内两者之间的差别,不过一问一答只要负责当前的封包的收发确认即可,因此需要用来备份的内存记忆体也较小,整体行为上也较简单。滑动视窗提升了单位时间的效率,但也需要更多的内存记忆体来储存,不过因为现代存储技术的发达,这些记忆体花费几乎可以忽略不计,因此整体上滑动窗口的CP值更高

你可以想像通讯软件因为讯号问题,一分钟内可以传4条讯息,每条讯息的长度也有限制,如何在最快的时间告知对方我们的想法?不过我个人是不太喜欢第二种聊天方式,哈哈哈

滑动窗口

视窗大小的观念很有趣,它不用等待个别的ACK确认回应才进行发送,而是依照接收方设定的视窗大小依序将好几笔封包发向接收方,也就是说在滑动窗口模式下,能决定传送几笔封包是由接收方决定

我们在TCP头部有介绍过视窗大小的控制位(Window),它表示能传送的资料大小,传送的封包资料量不能超过视窗大小,但是若视窗大小为0,可以允许发送视窗探索封包来了解接收方视窗当前状况

为了要了解滑动窗口,我们必须要扒开作业系统内存,看看它葫芦里到底卖甚麽药

作业系统为了确保发送的封包确实的被接收方收到,同时实现视窗控制的目的,必须限制出一个相当於视窗大小的资料长度来指定发送并且备份封包资料,我们先以发送方为例介绍一下缓冲区中每个区块代表的意义

绿色区块
就是已经接收ACK响应的封包,这部分的记忆体将会被释放掉(因为已经没有重传的必要了)。例如在视窗控制的效率优势一图中返回包含序号1001的ACK消息,就会将当初发送的1~1000这个封包的资料释放

黄色区块
表示已经发送但还未取得响应的封包,假如发生逾时或者丢包状况,主要是重传这个区块。在视窗控制的效率优势图中5001~6000这个封包尚未接收到接收方的ACK响应

红色区块
代表在视窗范围大小内即将要发送的封包。我们一样来看看视窗控制的效率优势一图,当我们的控制流程处於第一次发布的状态时(发送资料1~4000),当作业系统正在处理并发送1~1000这个封包时,剩余的1001~2000、2001~3000、3001~4000都是处在视窗范围内但是尚未被发送的状态

紫色的区块
代表不在当前视窗大小范围内。不说了还是看同一张图,假设发送方接收到接收方5001的ACK响应,发送方作业系统会主动释放出记忆体,而多出来的这块记忆体就会让整个处理视窗向右移向原本不再视窗大小范围内的记忆体位置(紫色区块),也就是8001~9000这个封包,所以紫色区块有可能是尚未处理的资料,也有可能是别的记忆体区块

不知道大家有没有看过工厂的输送带,就是流水线上一排作业员会将输送过来的物品进行处理那种?阿呀,真的有点难解释,我自己喜欢用这种方式来理解滑动视窗内存控制,还是上图吧

发送方

这张图怎麽解释呢?首先一个作业员可以处理特定长度的数据包,我们在这里假设这个工厂有个不成文规定,当最左边的作业员完成工作後输送带就会启动,把整个数据包往左移,四个作业员就相当於当前视窗大小,要处理的资料数据总长为10个,而最右边的那位仁兄相当於作业系统

当封包在流水线上移动时,作业员分别对这些资料做处理,从图一可以看出作业员一、二已经将数据处理完成,并等待品管灯检查完毕,这相当於发送方将封包发出,等待接收方回传ACK消息,由此可知数据包1, 2处於等待回应状态,若是处理有问题将会要求重作,此外作业员三、四正在处理数据包的过程中

接下来所有作业员都完成所有工作,等待检查灯亮起。当作业员一、二的数据包确定验证成功,表示依序收到来自接收方的ACK响应,作业系统就会下令转动输送带,并把这些数据释出,并且转动输送带会将作业员三、四的数据包交给作业员一、二,同时将本来未包含再视窗大小内的数据包5, 6交给作业员三、四处理

视窗内的资料封包初始时不需要获得ACK就可以发送,但後续视窗的移动就需要使用响应来改变视窗左指标位置。上图显示接收到两个ACK响应後,原先预留给封包2001~3000、3001~4000的记忆体就会被释放,并将左指标向後移动两个封包长度,同时作业系统为了保持视窗的大小,会将右指标也向未使用记忆体区段(包含在总长内)移动两个封包长度,这种行为看起来就像是把视窗向右滑动一样,所以称之为滑动视窗控制

接收方

接收方的内存控制就相对来的简单了,作业员一受委托就会将已经被确认过後的封包数据交给应用程序,而作业员二则在清点刚刚送达的封包数据,他一次只能验证5个数据封包,这是他的最大处理数量,也就相当於视窗大小。确认成功後会把它们移交给作业员一等待应用程序调用。如上图所示,作业员二确认完数据封包5後,就可以允许发送方发送数据封包10的消息了

当接收方确认收到2001~3000、3001~4000这两个封包後,作业系统便会将指向视窗开头的指标往左移位(从2001指向4001)最终整个视窗会向右移动。新的视窗大小含意是当前尚未接收到的数据,但可以接受的序号范围,因为视窗移动的关系,增加了6001~7000、7001~8000两个封包的允许接收权

响应丢失

假设我们考虑封包丢失的状况,滑动视窗是怎麽处理的呢?其实在滑动窗口模式下即使丢失响应也不需要重传,而是可以直接利用下一个接收到的响应进行确认,起初我也是很不了解这点,既然可以忽略不计,那作业系统记忆体要怎麽知道这个记忆体区块是否需要被释放?

其实响应的丢失场景有两种,假设是响应的封包搞丢了那还好,毕竟封包已经被接收了,就没有重传的必要,只是发送方不知道而已,但如果状况是发送方的封包压根就没有发送出去怎麽办?其实这个问题在下一小节高速重传中会介绍,接收方会立即返回三个预期序号的响应,也就是说若只是封包丢失直接收到下一个响应,就代表发生的是场景一,其实封包已经被接收了

如上图所示,我们假设视窗大小为4000,资料总长为10000,当接收到响应4001时,之前遗失的2001、3001响应就会自动被作业系统确认回应,随即代表这两个资料封包的记忆体区块也会被释放,还是放图好理解

当发送方接收到接收方的第一包响应,也就是2001时,作业系统随即将备份的记忆体区块释放,於是视窗向右边移一位并且发送4001~5000 这个封包。後续因为还没有接收到任何的响应消息,为了保持视窗的大小顶多只发送到4001~5000。最後发送方接收到5001响应,意思是1~5000的资料都确实地被接收方接收,因此作业系统将1001~4001三个封包的记忆体区块释放

高速重传机制

视窗控制有搭配比逾时重传更加有效率的高速重传机制,它不是依据返回响应的时间来触发,而是接收方依据预期的序号来检视封包是否发生丢失,首先说到效率,不免俗的要跟於时重传机制来比较一下,一样我们将视窗大小设定成4000,资料总长设为10000

当接收方收到与预期序号不一样的封包时会立即在接下来返回响应时回传三次应当收到的封包序号,对发送方来说,若连续收到三次同一个响应请求重传,则会触发高速重传机制

从图中我们可以看出使用高速重传比逾时机制来的高效,在这种状况下,若是使用逾时重传,整个封包的发送就会卡在等待1~1000这个封包的响应後才会继续,但在高速重传过程中,发送方还是会继续发送符合视窗大小的资料,虽然说接收方会对这些封包进行三次的重传请求,但同时接收方还是会将这些资料存进缓冲区内,也就是默认接收了後来的这些封包,所以到最後接收方真正接收到丢失的封包时,它返回的是目前接收到的最新封包ACK

为什麽高速重传需要花费三次ACK才会触发?
因为接收方不确定接收到的回应是网路传输问题导致的丢包还是纯粹的乱序封包,两次很有可能是乱序封包,三次有很高机率是丢包造成,四次、五次、六次有更高的机率是丢包造成,为了最大化提升效率,取三次作为高速重传次数限制

接下来看看记忆体缓冲区的视窗移动,首先发送方依序将封包1~4000发出,缓冲区处立马就处於等待回应阶段,这很好理解吧,但因为不明原因导致封包2001~3000在传输过程中丢失了

当接收方接受到非预期封包时,首先会将该乱序封包储存至对应缓冲区内。然後接收方会藉由跳回重传1001~2000这个封包响应 (2001),来让发送方知道要重传2001~3000 封包。另外由於前两个封包皆成功接收,接收方会依序将ACK消息返回给发送方,同时移动自身视窗,而发送方也会因为响应释放前两个区段的记忆体,并将视窗向右移动,同时空出的位置又可以进行新封包的发布

接收方依序接收到回应的两个封包,但因为封包2001~3000尚未确认,因此整个视窗会被卡住,导致视窗无法继续向右拓展,唯一方法是接收到2001~3000的确认响应

当发送方获得三次高速回传的响应时,会立即对遗失的封包进行重传,接收方在确认丢失的封包回传後返回之前收到封包的最长位置,因此会依据视窗最新的临界指标进行ACK响应,还记得我们在响应丢失一小节说到滑动视窗会依照最新的响应序号来更新整个视窗都接收确认吗?所以连同2001~3000在内的所有封包接被确认并释放,到此为止高速重传完成它的任务


<<:  Day30-结语

>>:  Day 30 Docker 的使用安全

Android学习笔记02

DataBinding简易的单项及双向绑定 使用DataBinding之前要先在DataBingin...

Oracle 1Z0-082 Practice Exam 2021

**Actual Oracle 1Z0-082 Practice Exam - Easiest Wa...

ASP.NET C# - GridView -ButtonFiled & CommandName

环境 VS2013 ASP.NET 4.0 GridView怎麽做删除钮与编辑钮. 要做之前,我们要...

2.1 Design System - 制作的工具

「有些事现在不做,一辈子都不会做了」~练习曲 求学时,体育老师让我们看这部电影并身体力行的带我们骑...

Day_12 : 让 Vite 来开启你的Vue 之 来!开始你的 Vue 3

Hi Dai Gei Ho~ 我是Winnie~ 进入Vue章节前的 温腥提醒: 在之後的文章中,预...