RFC8312
摘要
CUBIC是当前TCP标准的扩展。它与现有的TCP标准仅在发送方的拥塞控制算法上有所不同。特别地,它采用了三次函数代替了现有TCP标准中的线性窗口增加函数,提高了在高速长距离网络环境下的可扩展性和稳定性。CUBIC及其前身的算法已经被Linux作为默认算法使用了很多年。本文档提供了CUBIC的规范,以支持第三方实现,并通过对CUBIC性能的实验来征求社区反馈。
此 Memo 的状态
本文件不是互联网标准跟踪规范;它是为了提供信息而出版的。
本文档是Internet工程任务组(IETF)的产品。它代表了IETF社区的共识。它已经收到了公众的审查,并已批准出版的互联网工程指导小组(IESG)。并非所有IESG批准的文件都适用于任何级别的互联网标准;见RFC 7841第2节。
有关本文件的当前状态、任何勘误表以及如何提供反馈的信息,请访问https://www.rfc-editor.org/info/rfc8312.
1. 介绍
TCP在快速长距离网络中的低利用率问题在[K03]和[RFC3649]中有很好的描述。这个问题产生于在具有大带宽延迟积(BDP)的网络中,拥塞事件之后拥塞窗口的缓慢增加,在 [HKLRX06] 指出,即使在数百个数据包的拥塞窗口大小范围内,也经常观察到这个问题。这个问题同样适用于所有 Reno 风格的TCP标准及其变体,包括TCP-Reno[RFC5681]、TCP-NewReno[RFC6582][RFC6675]、SCTP[RFC4960]和TFRC[RFC5348],它们使用相同的线性增加函数进行窗口增长,我们在下文中将它们统称为“标准TCP”(Standard TCP)。
CUBIC最初是在 [HRX08] 中提出的,它是对标准TCP拥塞控制算法的一种改进。本文档描述了CUBIC的最新规范。具体来说,CUBIC使用了一个CUBIC函数来代替标准TCP的线性窗口增加函数,以提高在快速和长距离网络下的可扩展性和稳定性。
Binary-Increase拥塞控制(BIC-TCP)[XHR04] 是CUBIC的前身,在2005年被Linux选为默认的TCP拥塞控制算法,已经被整个互联网社区使用了好几年。CUBIC使用了与BIC-TCP类似的窗口增加功能,在保持BIC-TCP的优势(如稳定性、窗口可伸缩性和RTT公平性)的同时,它在带宽使用方面比BIC-TCP更具攻击性和公平性。CUBIC已经取代BIC-TCP成为Linux中默认的TCP拥塞控制算法,并被Linux全局部署。通过在各种互联网场景中的广泛测试,我们相信CUBIC在全球互联网上的测试和部署是安全的。
在接下来的章节中,我们首先简要说明了CUBIC的设计原则,然后提供了CUBIC的确切规格,最后根据[RFC5033]中规定的指南讨论了CUBIC的安全特性。
2. 约定
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
本文件中的关键词“必须”、“不得”、“必须”、“应”、“不应”、“应”、“不应”、“建议”、“不建议”、“可”和“可选”在所有大写字母出现时(且仅在所有大写字母出现时)应按照BCP 14[RFC2119][RFC8174]的规定进行解释,如下所示。
3. CUBIC 设计原理
CUBIC遵循以下设计原则:
原则1:为了更好的网络利用率和稳定性,CUBIC使用了一个三次函数的凹凸曲线来增加拥塞窗口的大小,而不是仅仅使用一个凸函数。
原则2:为了对TCP友好,CUBIC被设计成在RTT短、带宽小、标准TCP性能好的网络中表现得像标准TCP。
原则3:对于RTT公平性,CUBIC被设计成在具有不同RTT的流之间实现线性带宽共享。
原则4:CUBIC适当设置乘性窗口递减因子,以平衡可伸缩性和收敛速度。
3.1 原则1
为了更好的网络利用率和稳定性,CUBIC使用了一个三次函数的凹凸曲线来增加拥塞窗口的大小,而不是仅仅使用一个凸函数。
为了更好的网络利用率和稳定性,CUBIC [HRX08] 使用了一个三次函数来增加窗口,该函数根据距离上一次拥塞事件所经过的时间来计算窗口增加的大小。大多数替代标准TCP的拥塞控制算法都使用凸函数来增加拥塞窗口,而CUBIC算法同时使用凸函数和凹函数来增加窗口。在通过冗余ACK或显式拥塞通知(ECN Echo ACKs)[RFC3168] 检测到拥塞事件,使得窗口减小之后,CUBIC将检测到拥塞时的窗口大小记录为 ,并对拥塞窗口进行乘性减少。在进入拥塞避免阶段后,利用三次函数的凹形曲线(左边)增加拥塞窗口。三次函数的稳定点设置为 ,窗口大小在到达 之前会遵循三次函数曲线持续增长。在窗口大小达到 之后,三次函数进入到凸形曲线区域(右边),窗口大小开始沿着凸形区域增大。这种窗口调整方式(先凹后凸)提高了算法的稳定性,同时保持了较高的网络利用率[CEHRX07]。这是因为窗口大小几乎保持不变,围绕着 形成一个稳态区域,此时网络利用率被认为是最高的。在稳态下,CUBIC的大多数窗口大小样本都接近于 ,从而提高了网络的利用率和稳定性。需要注意的是,那些仅使用凸函数来增加拥塞窗口大小的拥塞控制算法的在接近 时窗口会剧烈增加,从而在网络饱和点附近引入大量的包突发,可能导致频繁的全局丢失同步( global loss synchronizations )。
- => 记录了早期检测到拥塞时的窗口大小,表征客户端窗口如果超过这个值太多可能会导致大量丢包,应该尽量的接近并稳定在这个值(在稳态阶段);
- 全局同步:每个发送方与其他发送方同时降低和增加传输速率的这种模式被称为“全局同步”。=> TCP global synchronization
3.2 原则2
为了对TCP友好,CUBIC被设计成在RTT短、带宽小、标准TCP性能好的网络中表现得像标准TCP。
CUBIC 通过建立 “TCP友好区域” ,使其在较小的 BDP 场景下,将每个流的公平性提升到标准TCP的水平。注意,标准TCP在短RTT和小带宽(或小BDP)网络下表现良好,但在具有长RTT和大带宽(或大BDP)的网络中,存在可扩展性问题。标准TCP的另一种拥塞控制算法设计为在每个流的基础上对标准TCP友好,必须在小型BDP网络中比在大型BDP网络中更有效地增加拥塞窗口。CUBIC 的侵略性主要取决于窗口缩减前的最大窗口大小 ,小BDP网络的 小于大BDP网络。因此,CUBIC在小型BDP网络中增加拥塞窗口的力度小于大型BDP网络。因此,当 CUBIC 算法的三次函数增加拥塞窗口的力度小于标准TCP时,CUBIC 只遵循标准TCP的窗口大小,以确保 CUBIC 算法在小型BDP网络中至少达到与标准TCP相同的吞吐量。我们将 CUBIC 类似于标准TCP的区域称为“TCP友好区域”。
3.3 原则3
对于RTT公平性,CUBIC被设计成在具有不同RTT的流之间实现线性带宽共享。
具有不同RTT的两个 CUBIC 流( CUBIC flow ) 的吞吐量比率( ratio )与其RTT比率的倒数成正比,其中对于每一个流的吞吐量近似于其拥塞窗口的大小除以其RTT。具体地说,CUBIC在TCP友好区之外保持独立于RTT的窗口增长率,因此具有不同RTT的流在稳定状态下在TCP友好区之外操作时具有相似的拥塞窗口大小。这种线性吞吐率的概念类似于高统计复用环境下的标准TCP,在这种环境下,数据包丢失与单个流量无关。然而,在低统计复用环境下,具有不同RTT的标准TCP流的吞吐量比与其RTT比的倒数成二次比例[XHR04]。CUBIC始终确保线性吞吐量比与统计复用的级别无关。这是对标准TCP的改进。虽然对不同RTT流的特定吞吐量比率没有共识,但我们认为在有线互联网下,使用线性吞吐量比率似乎比使用相等吞吐量(即,不同RTT流的相同吞吐量)或更高阶吞吐量比率(例如:低统计复用环境下标准TCP的二次吞吐率)更加合理。
3.4 原则4
CUBIC适当设置乘性窗口递减因子,以平衡可伸缩性和收敛速度。
为了在可扩展性和收敛速度之间取得平衡,CUBIC将乘性窗口递减因子设置为0.7,而标准TCP使用0.5。虽然这提高了CUBIC的可伸缩性,但这种决策的一个副作用是收敛较慢,特别是在低统计复用环境下。这种设计选择遵循了《高速TCP》(HSTCP)[RFC3649]一书的作者和其他研究人员(例如[GV02])所做的观察:当前的互联网变得更加异步,丢失同步频率更低,统计复用率更高。在这种环境下,即使严格的乘增乘减(MIMD)也可以收敛。具有相同RTT的 CUBIC流 总是独立于统计复用收敛到相同的吞吐量,从而实现算法内公平性。我们还发现,在统计复用充分的环境下,CUBIC流 的收敛速度是合理的。
4. CUBIC 拥塞控制
本文档中所有窗口大小的单位为最大段大小(MSS, Maximum Segment Size )的段,所有时间的单位为秒。cwnd 表示流的拥塞窗口大小, ssthresh 表示慢启动阈值。
4.1 窗口增加函数
CUBIC通过仅在接收到ACK时增加拥塞窗口来维持标准TCP的确认(ACK)时钟。它不会对TCP的快速恢复和重传进行任何更改,例如TCP NewReno [RFC6582] [RFC6675]。在拥塞避免期间,如果重复ack检测到数据包丢失或ack使用ECN Echo flags[RFC3168]检测到网络拥塞,CUBIC将更改标准TCP的窗口增加功能。假设在上一次拥塞事件中窗口缩小之前的窗口大小为 。
CUBIC使用以下函数进行窗口的增加:
Eq. 1
其中 C 是一个常数,用于确定高BDP网络中窗口增加的侵略性,t 是从当前拥塞避免开始所经过的时间, K 是上述函数将当前窗口大小增加到 所需的时间,如果没有进一步的拥塞事件,则使用以下公式计算:
Eq. 2
其中 是CUBIC的乘性递减因子,即,当检测到拥塞事件时,CUBIC将其 cwnd 减少到 。我们将在第4.5节讨论如何设置 ,在第5节讨论如何设置 C 。
当在拥塞避免期间接收到ACK时,CUBIC使用 Eq. 1
计算下一RTT期间的窗口增加率 作为拥塞窗口的候选目标值,其中RTT是由标准TCP计算的加权平均RTT。
根据当前拥塞窗口大小 cwnd 的值,CUBIC以三种不同的模式运行:
- TCP友好区域 ,确保CUBIC至少达到与标准TCP相同的吞吐量;
- 凹区域 ,如果 CUBIC 不在TCP友好区域,且 cwnd 小于 ;
- 凸区域 ,如果 CUBIC 不在TCP友好区域,且 cwnd 大于 。
下面,我们将描述CUBIC在每个区域采取的确切行动。
4.2 TCP友好区域
标准TCP在某些类型的网络中表现良好,例如,在短RTT和小带宽(或小BDP)网络下。在这些网络中,我们使用TCP友好区域来确保CUBIC至少达到与标准TCP相同的吞吐量。
根据[FHP00]中的分析,设计了TCP友好区。分析研究了加法因子为 (每RTT增加一个窗口)、乘法因子为 (表示为)的加法增乘减(AIMD)算法的性能. 具体地说, 的平均拥塞窗口大小可以使用 Eq .3
(其中 )来计算窗口大小,以此来实现与使用AIMD(1,0.5)的标准TCP相同的平均窗口大小。
Eq .3
基于上述分析,CUBIC使用Eq. 4
来估计窗口大小 ( , 其中 , )的 与 以及 ,它实现了与标准TCP相同的平均窗口大小。当在拥塞避免阶段收到 ACK 时,( cwnd 可以大于或小于 ),CUBIC 检查 是否小于 。 如果小于,则 CUBIC 当前位于TCP友好区域,在每次收到ACK时, cwnd 应该设置为 。
Eq .4
4.3 凹区域
当在拥塞避免阶段接收到ACK时,如果CUBIC不在TCP友好区域并且 cwnd 小于 ,那么 CUBIC 处于凹区域。CUBIC算法处于次区域时,每收到一个ACK,cwnd 必须增加 ,其中 使用 Eq. 1
计算。
4.4 凸区域
当在拥塞避免阶段接收到ACK时,如果CUBIC不在TCP友好区域并且 cwnd 大于或等于 , 那么 CUBIC 处于凸区域。凸区域表示自上一次拥塞事件以来,网络条件可能受到了干扰,这可能意味着在一些流离开之后,可用带宽会增加。由于因特网是高度异步的,所以在不引起可用带宽的重大变化的情况下,一定量的扰动总是可能的。在这个区域,CUBIC非常小心,非常缓慢地增加它的窗口大小。凸函数曲线确保窗口在开始时增长非常缓慢,并逐渐增加其增长率。我们也把这个区域称为“最大探测阶段”,因为CUBIC正在寻找一个新的 。CUBIC算法处于次区域时,每收到一个ACK,cwnd 必须增加 ,其中 使用 Eq. 1
计算。
4. 5 乘性减少
当收到三次冗余ACK、检测到丢包或收到显示拥塞控制包时,检测到网络拥塞,CUBIC 通过如下步骤更新其 、 cwnd 和 ssthresh :
其中 应设置为0.7
; // save window size before reduction
; // new slow-start threshold
; // threshold is at least 2 MSS
; // window reduction
W_max = cwnd; // save window size before reduction
ssthresh = cwnd * beta_cubic; // new slow-start threshold
ssthresh = max(ssthresh, 2); // threshold is at least 2 MSS
cwnd = cwnd * beta_cubic; // window reduction
将 设置为一个大于 0.5 的值的副作用为收敛速度较慢。我们认为,虽然设置自适应的 可以使得算法更快的收敛,但这将使得 CUBIC 的分析更加困难。这种自适应调整 是将会在 CUBIC 的下一个版本纳入考虑。
4.6 Fast Convergence
为了提高 CUBIC 算法的收敛速度,我们在 CUBIC 算法中加入了一个启发式算法。当一个新的流加入网络时,如果现有的流已经使用了网络的所有带宽,那么网络中的现有流需要放弃一些带宽来允许新的流有一些增长的空间。为了加速现有流的带宽释放,应该实现以下称为“快速收敛”的机制。
通过快速收敛,当发生拥塞事件时,在拥塞窗口的窗口缩小之前,每个流会记住自己在更新 之前最后一个 的值,我们将其标记为 。
if (W_max < W_last_max){ // should we make room for others
W_last_max = W_max; // remember the last W_max
W_max = W_max*(1.0+beta_cubic)/2.0; // further reduce W_max
} else {
W_last_max = W_max // remember the last W_max
}
在一个拥塞事件发生时,如果的当前 值小于 ,则表示由于可用带宽的变化,该流的饱和点正在减小。然后我们允许这个流通过进一步减少 来释放更多的带宽。此操作有效地延长了此流增加其拥塞窗口的时间,因为减少 会迫使流更早地达到饱和点。这使得新的流有更多的时间赶上它的拥塞窗口大小。
4.7 Timeout
在超时的情况下,CUBIC遵循标准TCP来减少 cwnd [RFC5681],与标准TCP[RFC5681]有一点不同的是,CUBIC 使用 来设置 ssthresh 。
在超时之后的第一次拥塞避免期间,CUBIC使用 Eq. 1
增加其拥塞窗口大小,其中 t 是自当前拥塞避免开始以来经过的时间, K 被设置为0,并且 被设置为当前拥塞避免开始时的拥塞窗口大小。
4.8 Slow Start
当 cwnd 不大于 ssthresh 时,CUBIC必须采用慢启动算法。在慢启动算法中,CUBIC可以在一般网络中选择标准TCP慢启动算法RFC5681,也可以在快速和长距离网络中选择有限慢启动算法RFC3742或混合慢启动算法HR08。
在CUBIC运行混合慢启动[HR08]的情况下,它可以退出第一个慢启动而不引起任何分组丢失,因此是未定义的。在这种特殊情况下,CUBIC切换到拥塞避免并使用 Eq. 1
增大其拥塞窗口大小,其中 t 是自当前拥塞避免开始以来经过的时间,K 被设置为0,并且 设置为当前拥塞避免开始时的拥塞窗口大小。