网路是怎样连接的(九)TCP的性能优化(下)

思考重点

  • 流量控制的原理以及实现目的?
  • 壅塞控制的原理以及实现目的?

核心知识

流量控制

流量控制的目的在上一篇中有提到,是为了防止接收方大量且无节制的接收封包,换言之就是避免接收方处理不及产生超负荷,或者漏接封包等,这些问题可能会触发接收方进行丢包处理,让本来就很严重的网路状况火上加油

因此流量控制的重点在於接收方的处理能力。TCP会在头部提供视窗大小的栏位,接收方可以依照当前缓冲区内可用的记忆体来决定视窗大小。当应用程序向缓冲区拿取数据的速率大於封包到达的速率时,视窗大小就会变大,相反的若接收速率大於应用程序的处理速率,则会造成缓冲区大小缩减,视窗大小这时就会向下修正。接收方可以藉由更改视窗大小栏位,并透过ACK响应告诉发送方,我现在处理封包的上限有多大

接收方配置的缓冲区示意图如上所示,封包到达缓冲区後接收方的应用程序通常不会马上向其拿取数据,因为它自己也忙於其他事情,因此当前缓冲区处在一个只进不出的状态,这时候接收方会藉由调整指向已接收并确认封包指标位置来进行视窗滑动,这个滑动视窗的大小就是流量控制视窗大小。视窗大小的长度必须小於等於缓冲区总长,端看接收方的处理消息能力

可以试着联想这种场景,有一间非常有名的餐厅一次最多只能有效处理10名顾客的点餐,而整个餐厅总共可以容纳100人,若是进餐厅的人控制在10人以内,那麽就可以很好的消化排队人潮,反之假如进餐厅的人数太多就必须在餐厅门口限制进店人数,好让店员能够有效处理人流。进店人数限制相当於视窗大小,店员相当於接收方处理能力,餐厅容纳人数相当於缓冲区大小

视窗大小更新的主要时机是应用程序向缓冲区拿取数据以及缓冲区已满。也就是说接收方不会在每次响应中更变视窗大小,一来在每次接收封包过程中都需要处理视窗大小的判断太浪费效率,二来接收方应用程序不会在每次收到封包会就准时向缓冲区拿取数据

真实的操作情况是,接收方不会每接收一个封包就发布一次更新响应,而是会等待一段时间,看看当前是否有其他通知,例如更新或者新的封包接收等,不仅可以将响应封包与视窗更新结合在一起节省响应封包数量,也可以在需要连续发布响应时减少响应次数,如同我们在接收方响应丢失中介绍,TCP可以根据最後接收到的响应判断前面的封包接成功被接收方接收

假若接收方连续收到封包後,应用程序依然没有从缓冲区中拿取数据,这时的缓冲区呈现爆满状态,也就是滑动视窗根本没有移动的空间,指向下一个封包的指标与缓冲区边界重叠,接收方必须通知发送方视窗大小为0的响应。对於发送方来说,它没有收到封包的响应确认,所以视窗不会移动,再来接收到视窗大小为0的更新後更是把整个滑动视窗的机制锁住

接收到视窗大小为0的发送方会贴心地等待接收方处理缓冲区数据,并回传一个视窗更新通知,不过它的耐心也是有极限就对了。通常接收方系统会设定一个逾时重传时间,若超过时间内没有收到更新消息,就立刻发送一个资料长度为1 byte的探索封包,向接收方询问缓冲区大小,为了防止返回更新视窗大小的响应遗失,接收方必须时刻准备探索封包的发送,不然整个收发流程将会无法继续进行

壅塞控制

TCP可以透过滑动视窗来增加封包的发送效率,但也衍生了网路壅塞问题。封包在网路核心中透过路由器传递过程中可能遭遇排队延迟,逾时、封包丢失等情形,为了避免发送方在网路壅塞时还使用滑动视窗发布大量封包,TCP会在发送第一个封包时使用缓启动机制,慢慢增加封包发送数量

缓启动

所谓的缓启动,就是在开始传送封包时将视窗大小限制成一个最小单位封包(MSS),如果接收方成功返回响应则将视窗大小增加为2,若连续发送两个封包也成功返回响应,则将视窗大小增加为4,由此可知壅塞视窗大小是根据封包成功响应後呈指数增加,不过是在没有遇上封包返回逾时的前提下

如图所示,发送方请求从1开始,成功返回响应後便会将滑动视窗提升为当前的2倍,直到到达双方约定的视窗大小限制为止。除此之外,壅塞控制的一大重点就是壅塞视窗的计算。壅塞视窗是由发送方维护的一个视窗范围,它会根据当前网路阻塞状况做出调整,限制发送方视窗

发送方会把接收方给定的视窗大小与壅塞视窗大小做比对,取其中的最小值作为发送视窗大小,也就是说如果接收方可以接受总视窗大小长度为4000,但当前网路状况只允许传递长度为2000的视窗,发送方会依照壅塞视窗的限制将视窗大小设为2000,待网路状况回稳後再将视窗提升至4000

但是壅塞控制不单单只有指数成长这麽简单,当封包响应发生逾时或其中的发送封包丢失时,壅塞视窗就会马上发生变化,也就是说若是没有发生上述状况,壅塞视窗会在合理范围内不断变大。上文提及壅塞视窗是呈现指数性增长,接下来就来看看网路发生阻塞时的壅塞视窗调整

壅塞控制流程

壅塞避免演算法

假设根据流量控制,若双方约定视窗大小为16,TCP使用滑动视窗进行封包发送,黄色区块1显示缓启动机制的指数叠加过程(1-->4-->8-->16),假如壅塞视窗超过16,则以16设为发送视窗。当TCP发现封包发送在第4轮发生逾时,会直接将壅塞视窗设定成1,并且设定缓启动阀值,每当封包到达临界缓启动阀值时就会触发以线性方式增长壅塞视窗大小,这个机制称为壅塞避免演算法

壅塞避免演算法的操作

  • 将壅塞视窗大小设为1
  • 将发生逾时的壅塞视窗大小数除以2,并设定该值为缓启动阀值
  • 一旦超过阀值,改以线性方式叠加封包发送数量

壅塞视窗一旦超过缓启动阀值就会以每一轮增加一个封包的方式叠加。举个例子,假如该次滑动视窗连续发送8个封包,当确实收到8个响应时,会在下一轮将连续发送数量提高到9次,也就是说每收到一个响应增加1/N个封包

因此我们在红色区块2中可以发现,壅塞视窗下降到1,在还没触及缓启动阀值前,壅塞视窗依旧以指数方式增加。直到壅塞视窗达到8(16/2),也就是整个黄色区块3的变化。当到达缓启动阀值,如图绿色区块4,经由壅塞避免演算法的调教,每一轮成功接收响应,仅增加一个封包的数量,如此一来视窗大小就不会一下增加太快,导致网路壅塞

如图所示,当网路状况不稳时,随时可能发生逾时。在绿色区块4过程中,壅塞视窗稳定增加到12,这时却遇上网路壅塞,於是壅塞避免演算法再次将缓启动阀值调整至6(12/2),壅塞视窗降为1

特别注意黄色区块6的第16轮发送,当下一轮的指数增加恰巧会超过缓启动阀值时,则以缓启动阀值为主,所以壅塞视窗会从8改为6

快速恢复机制

不过话又说回来,上图的壅塞避免演算法将发生逾时的壅塞视窗除以2,并将壅塞视窗设为1的这些操作是以发生封包逾时的前提设定的,也就是说封包返回时间超过TCP设定的RTO时间。但触发高速重传时的网路状况并没有那麽严重,所以这种极端的作法应该要有更好的替代方案

快速回复机制使用快速回复演算法,因为高速重传还需要另外对接收方发送3个响应封包,代表当时网路壅塞状况还可以接受。快速恢复演算法对壅塞视窗的调整没有如壅塞避免演算法那样强烈,而是会把壅塞视窗改为当前的一半後再加上3

快速回复演算法的操作

  • 将当前壅塞视窗除以2再加上3(来自接收方的3个响应被收到)
  • 缓启动阀值等於当前视窗大小
  • 一旦超过阀值,改以线性方式叠加封包发送数量

从上图可以看出,发送第12轮封包时触发了高速重传,发送方接收到三个响应後进入丢失封包重传,同时将壅塞视窗改成之前的一半,由於先前已接收到三个响应,因此会将逾时视窗再加上3。途中的第13轮壅塞视窗就是12/2+3=9,到此快速恢复结束,发送方壅塞视窗紧接着进入壅塞避免算法,尔後呈现线性方式成长。整个过程比直接将壅塞视窗降到1更为平滑,也更有效率

我们可以发现快速恢复演算法的特色,它会将壅塞视窗设置成较适合的大小,不断地呈现锯齿状的成长,结合高速重传的特色,能快速对壅塞网路做出调整。不过TCP发生逾时的情况相较之下没那麽大,还记得TCP会动态调整封包的RTO时间吗,但若许多客户端同时大量传送封包,那就可能造成网路核心发生一连串的排队甚至丢包

Tahoe与Reno版本差别
快速恢复演算法并非TCP壅塞控制必要元素,例如一种旧TCP版本Tahoe,它不管发生逾时重传或是3个响应的高速重传,都会将壅塞视窗降为1,然後进入缓启动。另外一种较新的版本Reno,则混合了两种方式,当封包响应超过RTO时间发生逾时时,则会启用将壅塞视窗降为1的机制,相反的,若其中的发送封包遗失造成接收方的高速响应回传的话,则会启用快速恢复演算法。从上面的范例可以看出我们介绍的是Reno版本


<<:  Day33 - 【实战篇-预告】Device Code(4)

>>:  注意!所以会点开来!

Day_12 有线网路应用(四)

如果没有USB网卡但也想要扩充LAN网口数量呢? 那麽vlan这个强大功能一定要了解一下。 虚拟区域...

Day15 Gin's Router And RESTful API

What is API and HTTP? API得全名叫做Application Programm...

Day 13: 时间管理、预估、压力 (待改进中... )

CH9: 时间管理 「专业开发人员同样清楚会议的高昂成本,他们同样清楚自己的时间是宝贵的。所以,如果...

第33天~还原资料库

这个的上一篇:https://ithelp.ithome.com.tw/articles/10283...

#30 No-code 之旅 — 恭喜完赛!

最後一天!礼拜五快乐!恭喜大家完赛!恭喜自己XD 今天来回头看看我们这三十天学了哪些事,还有讲一下未...