第24章 TCP的未来和性能
24.2 路径MTU发现
在2 . 9节我们描述了路径M T U的概念。这是当前在两个主机之间的路径上任何网络上的最小M T U。路径M T U发现在I P首部中继承并设置“不要分片( D F)”比特,来发现当前路径上的路由器是否需要对正在发送的 I P数据报进行分片。在 11 . 6节我们观察到如果一个待转发的 I P数据报被设置 D F比特,而其长度又超过了 M T U,那么路由器将返回 I C M P不可达的差错。在11 . 7节我们显示了某版本的 t r a c e r o u t e程序使用该机制来决定目的地的路径 M T U。在11 . 8节我们看到 U D P是怎样处理路径 M T U发现的。在本节我们将讨论这个机制是如何按照 R F C1191 [Mogul and Deering 1990]中规定的那样在T C P中进行使用的。
在本书的多种系统(参看序言)中只有Solaris 2.x支持路径MTU发现。
T C P的路径M T U发现按如下方式进行:在连接建立时, T C P使用输出接口或对端声明的M S S中的最小M T U作为起始的报文段大小。路径 M T U发现不允许T C P超过对端声明的 M S S。如果对端没有指定一个 M S S,则默认为5 3 6。一个实现也可以按 2 1 . 9节中讲的那样为每个路由单独保存路径M T U信息。
一旦选定了起始的报文段大小,在该连接上的所有被 T C P发送的I P数据报都将被设置 D F比特。如果某个中间路由器需要对一个设置了 D F标志的数据报进行分片,它就丢弃这个数据报,并产生一个我们在11 . 6节介绍的I C M P的“不能分片”差错。如果收到这个I C M P差错,T C P就减少段大小并进行重传。如果路由器产生的是一个较新的该类I C M P差错,则报文段大小被设置为下一跳的 M T U减去I P和T C P的首部长度。如果是一个较旧的该类I C M P差错,则必须尝试下一个可能的最小 M T U(见图2 - 5)。当由这个I C M P差错引起的重传发生时,拥塞窗口不需要变化,但要启动慢启动。
由于路由可以动态变化,因此在最后一次减少路径 M T U的一段时间以后,可以尝试使用一个较大的值(直到等于对端声明的 M S S或输出接口M T U的最小值)。RFC 11 9 1推荐这个时间间隔为1 0分钟(我们在11 . 8节看到Solaris 2.2使用一个3 0分钟的时间间隔)。
在对非本地目的地,默认的 M S S通常为5 3 6字节,路径M T U发现可以避免在通过 M T U小 于5 7 6(这非常罕见)的中间链路时进行分片。对于本地目的主机,也可以避免在中间链路(如以太网)的 M T U小于端点网络(如令牌环网)的情况下进行分片。但为了能使路径 M T U更加有用和充分利用 M T U大于5 7 6的广域网,一个实现必须停止使用为非本地目的制定的 5 3 6的M T U默认值。M S S的一个较好的选择是输出接口的 M T U(当然要减去I P和T C P的首部大小)(在附录E中,我们将看到大多数的实现都允许系统管理员改变这个默认的 M S S值)。
24.2.1 一个例子
在某个中间路由器的M T U比任一个端点接口M T U小的情况下,我们能够观察路径 M T U发现是如何工作的。图2 4 - 1显示了这个例子的拓扑结构。
我们从主机s o l a r i s(支持路径M T U发现机制)到主机 s l i p建立一个连接。这个建立过程与U D P的路径M T U发现(图11 - 1 3)中的一个例子相同,但在这里我们已经把 s l i p接口的M T U设置为5 5 2,而不是通常的 2 9 6。这使得s l i p通告一个5 1 2的M S S。但是在b s d i上的S L I P链路上的 M T U为2 9 6,这就引起超过 2 5 6的T C P报文段被分片。于是就可以观察在s o l a r i s上的路径M T U发现是如何进行处理的。
我们在s o l a r i s上运行s o c k程序并向s l i p上的丢弃服务器进行一个5 1 2字节的写操作:
代码语言:javascript复制solaris % sock -i -n1 -w512 slip discard
图2 4 - 2是在主机s u n的S L I P接口上收集的t c p d u m p的输出结果。
在第1和第2行的M S S值是我们所期望的。接着我们观察到 s o l a r i s发送一个包含5 1 2字节的数据和对S Y N的确认报文段(第 3行)(在习题1 8 . 9中可以看到这种把 S Y N的确认与第一个包含数据的报文段合并的情况)。这就在第4行产生了一个 I C M P差错,我们看到路由器 b s d i产生较新的、包含输出接口M T U的I C M P差错。
看来在这个差错回到s o l a r i s之前,就发送了F I N(第5行)。由于s l i p从没有收到被路由器b s d i丢弃的5 1 2字节的数据,因此并不期望接收这个序号( 5 1 3),所以在第6行用它期望的序号(1)进行了响应。
在这个时候,I C M P差错返回到了s o l a r i s,s o l a r i s用两个2 5 6字节的报文段(第 7和 第9行)重传了5 1 2字节的数据。因为在b s d i后面可能还有具有更小的 M T U的路由器,因此这两个报文段都设置了D F比特。接着是一个较长的传输过程(持续了大约 1 5分钟),在最初的5 1 2字节变为2 5 6字节以后,s o l a r i s没有再尝试使用更大的报文段。
24.2.2 大分组还是小分组
常规知识告诉我们较大的分组比较好 [Mogul 1993, 15.2.8节],因为发送较少的大分组比发送较多的小分组“花费”要少(假定分组的大小不足以引起分片,否则会引起其他方面的问题)。这些减少的花费与网络(分组首部负荷)、路由器(选路的决定)和主机(协议处理和设备中断)等有关。但并非所有的人都同意这种观点 [Bellovin 1993]。
考虑下面的例子。我们通过 4个路由器发送8 1 9 2个字节,每个路由器与一个 T 1电话线(1544 000b/s)相连。首先我们使用两个 4 0 9 6字节的分组,如图2 4 - 3所示。
基本问题在于路由器是存储转发设备。它们通常接收整个输入分组,检验包含 I P检验和的I P首部,进行选路判决,然后开始发送输出分组。在这个图中,我们可以假定在理想情况下这些在路由器内部进行的操作不花费时间(水平点状线)。然而,从R 1到R 4它需要花费4个单位时间来发送所有的8 1 9 2字节。每一跳的时间为
(将T C P和I P的首部算为4 0字节)。发送数据的整个时间为分组个数加上跳数减 1,从图中可以看到是4个单位时间,或8 5 . 6秒。每个链路空闲2个单位时间,或4 2 . 8秒。
图2 4 - 4显示了当我们发送1 6个5 1 2字节的分组时所发生的情况。
这将花费更多的单位时间,但是由于发送的分组较短,因此每个单位时间较小。
现在总时间为(1 8×2 . 9)=52.2 ms。每个链路也空闲2个单位的时间,即5.8 ms。
在这个例子中,我们忽略了确认返回所需要的时间、连接建立和终止以及链路可能被其他流量共享等的影响。然而,在 [Bellovin 1993]中的测量表明,分组并不一定是越大越好。我们需要在更多的网络上对该领域进行更多的研究。