跳到主要内容

5. 估算往返时间 (Estimating the Round-Trip Time)

从高层看, 端点把从发送一个包到该包被确认之间的时间测量为一个 RTT 样本.端点使用 RTT 样本以及对端报告的主机延迟, 见 [QUIC-TRANSPORT] 第 13.2 节, 为网络路径的 RTT 生成统计描述.端点为每条路径计算三个值: 一段时间内的最小值 (min_rtt)、指数加权移动平均值 (smoothed_rtt), 以及观测 RTT 样本的平均偏差, 本文其余部分称为 "variation", 即 rttvar.

5.1. 生成 RTT 样本 (Generating RTT Samples)

端点在收到满足以下两个条件的 ACK 帧时生成 RTT 样本:

  • 最大已确认包号是新确认的.

  • 新确认的包中至少有一个是 ack-eliciting 包.

RTT 样本 latest_rtt 是自最大已确认包发送以来经过的时间:

latest_rtt = ack_time - send_time_of_largest_acked

RTT 样本只使用收到的 ACK 帧中最大已确认包生成.这是因为对端只为 ACK 帧中最大已确认包报告确认延迟.虽然报告的确认延迟不用于 RTT 样本测量, 但会在后续 smoothed_rtt 和 rttvar 计算中用于调整 RTT 样本, 见第 5.3 节.

为避免为单个包生成多个 RTT 样本, 如果 ACK 帧没有新确认最大已确认包, 则不应使用该 ACK 帧更新 RTT 估计.

收到未新确认至少一个 ack-eliciting 包的 ACK 帧时, 禁止生成 RTT 样本.对端通常不会在只收到非 ack-eliciting 包时发送 ACK 帧.因此, 只包含非 ack-eliciting 包确认的 ACK 帧可能包含任意大的 ACK Delay 值.忽略这类 ACK 帧可避免后续 smoothed_rtt 和 rttvar 计算复杂化.

如果一个 RTT 内收到多个 ACK 帧, 发送方可能每个 RTT 生成多个 RTT 样本.如 [RFC6298] 所示, 这样做可能导致 smoothed_rtt 和 rttvar 中历史信息不足.确保 RTT 估计保留足够历史仍是开放研究问题.

5.2. 估算 min_rtt (Estimating min_rtt)

min_rtt 是发送方对给定网络路径在一段时间内观测到的最小 RTT 的估计.本文中, loss detection 使用 min_rtt 来拒绝不合理的小 RTT 样本.

在第一个 RTT 样本上, min_rtt 必须设置为 latest_rtt.对所有其他样本, min_rtt 必须设置为 min_rtt 和 latest_rtt (第 5.1 节) 中较小者.

端点计算 min_rtt 时只使用本地观测时间, 不根据对端报告的确认延迟调整.这样端点可完全基于自身观测为 smoothed_rtt 设置下界, 见第 5.3 节, 并限制对端错误报告延迟导致的潜在低估.

网络路径的 RTT 可能随时间变化.如果路径实际 RTT 降低, min_rtt 会在第一个低样本上立即适应.如果路径实际 RTT 增加, min_rtt 不会随之适应, 允许未来小于新 RTT 的 RTT 样本被纳入 smoothed_rtt.

端点在确认存在持续拥塞后, 应把 min_rtt 设置为最新 RTT 样本.这可避免 RTT 增加时反复声明持续拥塞.它也允许连接在破坏性网络事件后重置 min_rtt 和 smoothed_rtt 估计, 见第 5.3 节.

端点可以在连接中的其他时候重新建立 min_rtt, 例如流量较低且收到确认延迟较低的确认时.实现不应过于频繁刷新 min_rtt, 因为路径实际最小 RTT 并不常可观测.

5.3. 估算 smoothed_rtt 和 rttvar (Estimating smoothed_rtt and rttvar)

smoothed_rtt 是端点 RTT 样本的指数加权移动平均值, rttvar 使用平均偏差估算 RTT 样本变化.

smoothed_rtt 的计算使用根据确认延迟调整后的 RTT 样本.这些延迟从 ACK 帧的 ACK Delay 字段解码, 如 [QUIC-TRANSPORT] 第 19.3 节所述.

对端可能在握手期间报告大于其 max_ack_delay 的确认延迟, 见 [QUIC-TRANSPORT] 第 13.2.1 节.为处理这种情况, 端点在握手确认前应忽略 max_ack_delay, 握手确认定义见 [QUIC-TLS] 第 4.1.2 节.这类较大确认延迟一旦出现, 通常不会重复且限于握手期间.因此, 端点可以使用它们而不把它们限制到 max_ack_delay, 避免不必要地抬高 RTT 估计.

注意, 如果对端报告确认延迟有误, 或端点 min_rtt 估计有误, 较大的确认延迟可能导致 smoothed_rtt 被显著抬高.因此, 在握手确认前, 如果根据确认延迟调整 RTT 样本会使样本小于 min_rtt, 端点可以忽略该 RTT 样本.

握手确认后, 对端报告的任何大于其 max_ack_delay 的确认延迟都归因于非故意但可能重复出现的延迟, 例如对端调度器延迟或先前确认丢失.额外延迟也可能来自不合规接收方.因此, 这些额外延迟实际上被视为路径延迟的一部分, 并纳入 RTT 估计.

因此, 端点使用对端报告的确认延迟调整 RTT 样本时:

  • 可以忽略 Initial 包的确认延迟, 因为对端不会延迟这些确认, 见 [QUIC-TRANSPORT] 第 13.2.1 节.

  • 在握手确认前, 应忽略对端的 max_ack_delay.

  • 握手确认后, 必须使用确认延迟和对端 max_ack_delay 中较小者.

  • 如果减去确认延迟后的 RTT 样本小于 min_rtt, 禁止从 RTT 样本中减去确认延迟.这限制了错误报告对端导致的 smoothed_rtt 低估.

此外, 当对应解密密钥无法立即获得时, 端点可能推迟处理确认.例如, 客户端可能收到一个 0-RTT 包的确认, 但由于尚无 1-RTT 包保护密钥而无法解密.在这种情况下, 端点在握手确认前应从 RTT 样本中减去这种本地延迟.

类似 [RFC6298], smoothed_rtt 和 rttvar 按如下方式计算.

端点在连接建立期间初始化 RTT 估计器, 并在连接迁移期间重置估计器时重新初始化, 见 [QUIC-TRANSPORT] 第 9.4 节.新路径尚无 RTT 样本或估计器被重置时, 使用初始 RTT 初始化估计器, 见第 6.2.2 节.

smoothed_rtt 和 rttvar 按如下方式初始化, 其中 kInitialRtt 包含初始 RTT 值:

smoothed_rtt = kInitialRtt
rttvar = kInitialRtt / 2

网络路径的 RTT 样本记录在 latest_rtt 中, 见第 5.1 节.初始化后的第一个 RTT 样本会使用该样本重置估计器.这确保估计器不保留过去样本的历史.按 [QUIC-TRANSPORT] 第 9.4 节所述, 在其他路径上发送的包不会为当前路径贡献 RTT 样本.

初始化后的第一个 RTT 样本上, smoothed_rtt 和 rttvar 设置如下:

smoothed_rtt = latest_rtt
rttvar = latest_rtt / 2

后续 RTT 样本中, smoothed_rtt 和 rttvar 按如下方式演进:

ack_delay = decoded acknowledgment delay from ACK frame
if (handshake confirmed):
ack_delay = min(ack_delay, max_ack_delay)
adjusted_rtt = latest_rtt
if (latest_rtt >= min_rtt + ack_delay):
adjusted_rtt = latest_rtt - ack_delay
smoothed_rtt = 7/8 * smoothed_rtt + 1/8 * adjusted_rtt
rttvar_sample = abs(smoothed_rtt - adjusted_rtt)
rttvar = 3/4 * rttvar + 1/4 * rttvar_sample