1. 引言 (Introduction)
Van Jacobson 的包守恒原则 [Jacobson88] 定义了一种自时钟 (self clock) 过程: 交付到接收方的 N 个数据段会产生确认, 数据发送方再把这些确认作为时钟, 触发向网络发送另外 N 个数据段.
Reno [RFC5681] 和 CUBIC [RFC9438] 等拥塞控制算法都建立在这种自时钟过程的概念基础上. 它们通过拥塞窗口 ("cwnd") 限制 "inflight" 来控制传输协议连接的发送过程, 其中 inflight 是连接估计在某一时刻仍在网络中的数据量. 此外, 这些算法要求传输协议连接在响应丢包时降低 cwnd. 快速恢复 (见 [RFC5681] 和 [RFC6675]) 是利用确认反馈执行这种 cwnd 降低的算法. 其目标是在恢复期间依靠返回的 ACK 为更多数据进入网络提供时钟, 从而维持发送方的自时钟.
如果没有比例速率降低 (Proportional Rate Reduction, PRR), 快速恢复通常会先等待一个往返时间 (RTT) 的大部分时间再发送任何数据, 以此调整窗口. 对 Reno [RFC5681] 而言这是半个 RTT 的 ACK, 对 CUBIC [RFC9438] 而言是 30% 的 RTT.
[RFC6675] 通过计算 "pipe" (发送方对网络中仍未完成交付的字节数的估计), 使支持选择性确认 (Selective Acknowledgment, SACK) [RFC2018] 的快速恢复更加准确. 使用 [RFC6675] 时, 快速恢复会在每个 ACK 上按需发送数据, 使 pipe 上升到匹配 ssthresh, 即拥塞控制算法为快速恢复设置的目标窗口大小. 在大量丢包的许多场景中, 这可以避免快速恢复超时. 但是, [RFC6675] 有两个显著缺点.
第一, 由于它在快速恢复开始时对 cwnd 做很大的乘法降低, 如果窗口后半部分的所有数据或 ACK 丢失, 就可能导致超时. 第二, 单个携带 SACK 选项且暗示大量数据缺失的 ACK 可能使 pipe 估计器出现阶跃不连续, 进而导致快速重传时突发发送一批数据.
PRR 在快速恢复期间调节发送过程, 避免这些过度的窗口调整, 使发送平滑进行, 并在恢复结束时让实际窗口大小尽可能接近 ssthresh.
PRR 的方法受 Van Jacobson 包守恒原则启发. PRR 尽可能依赖自时钟过程, 只会轻微受到估计器准确性的影响, 例如对在途数据量的估计. 因此, 即使发生会让其他估计器产生不确定性的事件, 该算法也能保持准确性.
当 inflight 高于 ssthresh 时, PRR 以与已交付数据和 ssthresh 成比例的速率安排发送, 从而将 inflight 平滑降低到 ssthresh.
当 inflight 低于 ssthresh 时, PRR 会在两个降低边界 (Reduction Bounds) 之间自适应选择, 以限制所有机制导致的总窗口降低, 包括瞬时应用停顿和丢包本身. 作为基线, PRR 使用保守降低边界 (Conservative Reduction Bound, CRB) 严格遵循包守恒, 以便在可能存在严重拥塞时保持谨慎. 当恢复看起来进展良好时, PRR 使用慢启动降低边界 (Slow Start Reduction Bound, SSRB), 它相对于 PRR-CRB 最多每个 ACK 多发送一个段.
PRR-CRB 满足附录 A 中描述的强包守恒边界 (Strong Packet Conservation Bound). 但是, 在实际网络中, 单独使用 PRR-CRB 的性能不如 [RFC6675] 中描述的算法, 后者在大量场景中被证明更激进. PRR-SSRB 提供了一种折中方案: 在某些情况下, 它允许连接相对于 PRR-CRB 每个 ACK 多发送一个段. 虽然 PRR-SSRB 没有 [RFC6675] 激进, 即发送的段更少或发送耗时更长, 但由于恢复期间额外丢包的概率更低, 它的表现优于后者.
包守恒原则的原始定义 [Jacobson88] 将推定丢失的包, 例如标记为重传候选的包, 视为已经离开网络. PRR 使用的 inflight 估计器体现了这一思想, 但它不同于附录 A 中描述的强包守恒边界, 后者只基于实际到达接收方的数据来定义.
相对于 [RFC6937] 中较早版本的 PRR, 本文档规定了若干主要变更. 第一, 它引入了新的自适应启发式方法, 用来替代一个手动配置参数; 该参数曾决定当 inflight 低于 ssthresh 时 PRR 应多保守, 即使用 PRR-CRB 还是 PRR-SSRB.
第二, 该算法规定了非 SACK 连接的行为, 即未通过 "SACK-permitted" 选项协商 SACK [RFC2018] 支持的连接. 第三, 即使发送方经历严重重排序, 并且直到相当大的序列空间已被 SACKed 后才开始丢失恢复, 该算法也能确保平滑发送.
最后, 本文档还进一步讨论了 PRR 与拥塞控制算法和丢失检测算法的集成.
自 2011 年第一个被广泛部署的 TCP PRR 实现 [First_TCP_PRR] 以来, PRR 已经在多个 TCP 实现中积累了大量部署经验.