1. 介绍
本文描述了一个用来控制对端确认延迟的QUIC扩展。
2. 动机
接收端确认接受到了报文,但是可以延迟发送这些确认。
延迟确认会影响:
- 连接吞吐量
- 发送端的丢包探测和拥塞控制器。
- 接收端的CPU利用率
降低确认频率可以在如下几点改进连接和端点性能:
- 在一些平台上发送UDP报文是CPU密集的。减少只包含ACK帧的报文数量可以降低接收端CPU消耗。经验显示这可能对高带宽连接非常关键。
- 类似地,接收和处理UDP报文也可能是CPU密集的,减少ACK频率也减少了发送端的这种成本。
- 对于非对称链路技术,如DOCSIS、LTE和卫星,当反向路径被ACK报文填满时,前向路径的连接吞吐量可能就会受到限制。当穿越这些链路,减少ACK数量可以达到更高的连接吞吐量,降低对其他流量的影响,或者优化传输资源的整体效率。
- ACK报文的速率可能降低链路效率,包括传输机会和电池寿命,还有共享连接的其他流量的可用传输机会。
如第8节所述,如果接收方不适当地降低ACK频率,可能对拥塞控制和丢包检测有不好的后果。发送端需要考虑发送对确认频率的约束,以最大限度地提高拥塞控制器和丢包恢复性能。
[QUIC-TRANSPORT]指定了一种简单的延迟确认机制,接收端可以使用该机制:每隔一个数据包发送确认,或者每发现一个无序接收的数据包发送确认([QUIC-TRANSPORT]13.2.1)。这不允许发送端发出其偏好或约束的信号。此扩展提供了一种解决此问题的机制。
3. 协商扩展使用
端点通过发送如下传输参数通告支持本文描述的扩展:
min_ack_delay (0xff04de1b):变长整数,表示发送该值的端点能够延迟确认的最小时间(以微秒为单位)。这个限制可能基于接收端的时钟或定时器粒度。对端使用min_ack_delay来避免在ACK_REQUENCY帧的Request Max Ack Delay字段中请求太小的值。
端点的min_ack_delay不得大于其max_ack_delay。支持此扩展的端点必须将接收到的大于接收到的max_ack_delay的min_ack_delay视为TRANSPORT_PARAMETER_ERROR类型的连接错误。请注意,虽然端点的max_ack_delay传输参数以毫秒为单位([QUIC-transport]18.2),但min_ack_deay是以微秒为单位指定的。
min_ack_delay传输参数是支持接收ACK_FREQUENCY帧的单方面指示。如果端点发送这个传输参数,则允许对端发送ACK_FREQUENCY帧,而与对端是否也发送min_ack_delay传输参数无关。
接收到min_ack_delay传输参数指示对端将来可能发送ACK_FREQUENCY帧。在接收到ACK_FREQUENCY帧之前,接收此传输参数不会导致端点更改其确认行为。
4. ACK_FREQUENCY帧
尽可能多地延迟确认可以减少端点所做的工作和网络负载。然而,端点的丢包检测和拥塞控制机制需要对端容忍这种延迟。端点使用ACK_FREQUENCY帧向对端发送其想要接收ACK帧的频率信号,如下所示:
ACK_FREQUENCY帧的类型是0xaf,包含以下字段:
序列号(Sequence Number):变长整数,表示发送端的ACK_FREQUENCY帧的序列号,接收端可以用来忽略过时的帧。
确认触发门限(Ack-Eliciting Threshold):变长整数,表示该帧的接收方在发送确认之前接收到的最大确认触发包数。当接收到超过此数量的确认触发包时,接收端应发送至少一个ACK帧。值为0会导致接收端立即确认每个确认触发包。默认情况下,端点为每隔一个确认触发包发送一个ACK帧,如[QUIC-TRANSPORT] 13.2.2所述,其对应于值1。
请求最大ACK时延(Request Max Ack Delay):变长整数,表示端点请求对端更新其max_ack_delay的值。此字段的值以微秒为单位,而max_ack_delay传输参数以毫秒为单位。发送小于对端通告的min_ack_delay的值是无效的。收到无效值时,必须将其视为TRANSPORT_PARAMETER_ERROR类型的连接错误。在接收到此字段中的有效值时,端点必须将其max_ack_delay更新为对端提供的值。
重排门限(Reordering Threshold):变长整数,指示在触发立即ACK之前的最大包重排数。如果没有收到ACK_FREQUENCY帧,则端点立即确认任何无序接收的后续数据包,如[QUIC-TRANSPORT]13.2所述,对应于默认值1。值为0表示无序包不会立即引发ACK。
ACK_FREQUENCY帧是确认触发帧。当一个ACK_FREQUENCY帧丢失时,除非已经发送了具有较大序列号值的ACK_FREUENCY帧,否则鼓励发送方发送另一个ACK_FREQUENCY帧。然而,并不禁止重传丢失的帧,因为接收端将基于序列号忽略重复或无序的ACK_FREQUENCY帧。
端点可以在一个连接内发送多个不同值的ACK_FREQUENCY帧。发送端必须在序列号字段中发送单调递增的值,因为该字段允许无序处理ACK_FREQUENCY帧。如果帧中的序列号值小于当前处理的最大值,则接收端点必须忽略接收到的ACK_FREQUENCY帧。
5. IMMEDIATE_ACK帧
发送端可以使用ACK_FREQUENCY帧来减少接收端发送的确认的数量,但这样做也增加了时间敏感反馈被延迟的可能性。如8.3所述,延迟确认可能会增加发送端检测数据包丢失所需的时间。发送IMMEDIATE_ACK帧可以帮助缓解此问题。
IMMEDIATE_ACK帧在其他情况下也很有用。例如,如果发送者想要立即进行RTT测量,或者发送者想要尽快建立接收者的活跃度。PING帧是确认触发帧,但是如果在没有IMMEDIATE_ACK帧的情况下发送PING帧,则接收端可能不会基于其本地ack策略立即发送ack。
根据定义,IMMEDIATE_ACK帧是确认触发帧。端点应在接收到IMMEDIATE_ACK帧后立即发送包含ACK帧的数据包。端点接收到IMMEDIATE_ACK帧,也可以延迟发送ACK帧。例如,如果接收到的大量数据包包含IMMEDIATE_ACK,或者端点负载过重,则端点不一定会执行此操作。
6. 发送确认
在接收到ACK_FREQUENCY帧之前,端点发送[QUIC-TRANSPORT] 13.2.1中规定的确认。
在接收到ACK_FREQUENCY帧并更新其max_ack_delay和Ack-Eliciting Threshold(第4节)时,当满足以下条件之一时,端点发送确认:
- 自上次确认发送以来,接收到的确认触发包数量大于ack触发阈值。
- 自最后一次确认发送以来,已过了max_ack_delay时间。
6.2节、6.4节和6.5节描述了该策略的例外情况。
6.1. 响应长空闲期
在长时间空闲之后及时接收反馈是很重要的,例如更新过时的RTT测量。当在一个平滑的往返时间内没有发送确认时,鼓励接收器在接收到确认触发包后立即发送确认。这不是本文特有的问题,但此处指定的机制可能会造成过度延迟。
6.2. 响应乱序报文
如[QUIC-TRANSPORT] 13.2.1所述,端点应在收到重新排序的确认触发包后立即发送确认。当接收到Reordering Threshold不是1的ACK_FREQUENCY帧时,此扩展将修改该行为。
如果从对端接收到的最新ACK_FREQUENCY帧的Reordering Threshold为0,则端点不应立即发送确认以响应无序接收到的数据包,而是依赖对端的ACK Eliciting Threshold和max_ack_delay阈值来发送确认。
如果从对端接收到的最新ACK_FREQUENCY帧的Reordering Threshold大于1,则端点在决定发送确认之前判断重排的量。本规范使用以下定义:
最大未确认(Largest Unacked):接受到的所有确认触发包中的最大包号。
最大已确认(Largest Acked):ACK帧中发送的最大确认值。
最大已报告(Largest Reported):根据指定Reordering Threshold判断丢失的最大包号,即Largest Acked - Reordering Threshold + 1
未报告丢失(Unreported Missing):Largest Unacked和Largest Reported之间还没接收到的的包号
当最小Unreported Missing包和最大Largest Unacked包之间的间隔大于或等于重新排序阈值时,接收到非零Reordering Threshold的ACK_FREQUENCY帧的端点应立即发送ACK。发送这个额外的ACK将重置max_ack_delay计时器和ACK Eliciting Threshold计数器(就像任何ACK一样)。¶
有关解释这种行为的示例,见6.2.1。有关发送ACK_FREQUENCY帧时如何选择重排阈值的指导,见6.3。
6.2.1. 例子
当重排阈值为1时,只要接收到一个包并且存在丢失的包,都会立即发送ACK。
如果重排保持为3,并且仅由于重排发送ACK:
收到1
收到3 -> 2 丢失
收到4 -> 2 丢失
收到5 -> 因为2发送ACK
收到8 -> 6,7丢失
收到9 -> 因为6,7发送ACK
收到10 -> 因为7发送ACK
如果重排阈值是5,并且仅由于重排发送ACK:
收到1
收到3 -> 2 丢失
收到5 -> 2丢失, 4丢失
收到6 -> 2丢失, 4丢失
收到7 -> 因2, 4丢失发送ACK
收到8 -> 4丢失
收到9 ->因为4发送ACK
6.3. 设置重排阈值
为了确保及时的丢包检测,最好发送比发送方用于丢包检测的数据包阈值小1的重排阈值。如果阈值较小,则在可以基于丢包阈值宣布包丢失之前发送ACK帧。如果该值较大,则会导致不必要的延迟。([QUIC-RECOVERY] 18.2)建议丢包检测的默认包阈值为3,相当于重排阈值为2。
6.4. 加速显式拥塞通知(ECN) 信号
当收到IP报头中标记有ECN拥塞经历(CE)[RFC3168]码点的数据包,并且之前接收到的数据包没有标记为CE时,端点应该立即发送确认。
这样做可以保持对端对拥塞事件的响应时间,但相对于以下情况与[QUIC-TRANSPORT]的13.2.1相比也降低了ACK速率:
- 极端拥塞期间
- 对端使用比经典ECN[RFC3168]更频繁标记的DCTCP[RFC8257]或其他拥塞控制器(例如[I-D.ietf-tsvwg-aqm-dualq-coupled])。
6.5. 批量处理报文
为了避免快速连续发送多个确认,端点可以在确定是否发送ACK帧作为响应之前批量处理所有数据包,如[QUIC-TRANSPORT] 13.2.2所述。
7. 计算探测超时周期
在要求对端更新max_ack_delay时,端点可以在稍后计算其探测超时(PTO)周期时使用此新值,见[QUIC-RECOVERY]5.2.1。
在确认携带该帧的数据包之前,端点必须使用当前max_ack_delay和计算PTO周期时正在运行的值中的较大值。这样做可以避免由于更新降低对端的max_ack_delay而导致的虚假PTO。
虽然预计端点在任何给定时间都只有一个ACK_FREQUENCY帧在途,但此扩展并不禁止有多个在途。当使用max_ack_delay进行PTO计算时,端点必须使用当前值和所有在途的最大值。
当在途的确认触发包的数量大于ack触发阈值时,端点可以预期对端在发送确认之前不需要等待其最大 max_ack_delay 。在这种情况下,端点可能因此将对端的max_ack_delay从其PTO计算中排除。如果启用了Ignore Order,并且丢包导致对端没有收到足够的数据包来触发立即确认,则接收方将等待max_ack_delay,从而增加过早PTO的可能性。因此,如果启用了Ignore Order,则PTO必须大于对端的max_ack_delay。
当发送PTO数据包时,可以包括IMMEDIATE_ACK帧以引发立即确认。这避免了等待确认PTO数据包的ack延迟,减少了尾部延迟,并允许发送方从后续PTO计算中排除对端的max_ack_delay。
8. 确定确认频率
本节提供了一些关于发送端选择确认频率的指导,并讨论了一些其他注意事项。实现者可以选择适当的策略来满足其应用程序和拥塞控制器的需求。
8.1. 拥塞控制
发送端需要对拥塞通知做出响应,例如丢包或ECN CE标记。降低确认频率可能会延迟发送端对网络拥塞的响应,或导致其不能充分利用可用带宽。
为了限制确认频率降低的后果,当在途有确认触发包时,发送端可以使接收端在每次往返中至少发送一次确认。
发送方可以通过将Request Max Ack Delay值设置为不超过估计的往返时间来实现这一点。发送方还可以通过将Ack Eliciting Threshold设置为不大于当前拥塞窗口的值来提高对路径RTT变化的反馈和鲁棒性。或者,发送方可以通过在每个往返时间发送一次IMMEDIATE_ACK帧来实现这一点,尽管如果包含IMMEDIATE_ACK的报文丢失,则对该丢失的检测将延迟重排阈值或请求的最大ACK延迟。
当将Request Max Ack Delay设置为RTT的函数时,通常最好使用Smoothed RTT([QUIC-RECOVERY] 5.3)或典型往返时间的一个估计值,但不要使用Min RTT。当min_rtt远小于smoothd_rtt时,这避免了引发不必要的大量确认。
请注意,拥塞窗口和RTT在连接的生命周期内会发生变化,因此可能需要频繁发送ACK_FREQUENCY帧以确保最佳性能。
RTT可能小于接收方的定时器粒度(通过min_ack_delay传输参数通告),这会阻止接收方在每个RTT及时发送确认,除非立即确认数据包。在这些情况下,除1以外的Reordering Threshold可以比一个RTT更延迟丢包检测。
8.1.1. Application-Limited连接
受拥塞窗口限制的拥塞控制器依赖于接收确认来将更多数据发送到网络中。确认延迟的增加会增加发送数据的延迟,这会降低吞吐量。拥塞窗口的增长也可能取决于收到的确认。这在慢启动时尤其重要([QUIC-RECOVERY] 7.3.1),因为延迟确认会延迟拥塞窗口的增加,导致更大的数据包突发。
如果发送方受应用程序限制(即数据量没达到带宽上限),则在进入空闲时段时,确认可能会被不必要地延迟。因此,如果缓冲区中没有更多的数据发送,则发送方可以在空闲时段之前发送带有最后一个数据分组的IMMEDIATE_ACK帧,以避免等待ACK延迟。
如果没有在途数据包,则在发送恢复时,至少在往返行程中不会收到确认。接收方使用的Max Ack Delay和Ack-Eliciting Threshold可以进一步延迟确认。在这种情况下,发送方可以在第一个ACK 触发报文中包含IMMEDIATE_ACK或ACK_FREQUENCY帧,以避免等待确认的时间远远超过往返时间。
8.2. 突发缓解
接收到确认可以让发送端将新的报文释放到网络中。如果发送短被设计为依赖对端确认的时钟(“ACK时钟”),则延迟确认可能会导致不希望的数据突发进入网络。根据[QUIC-RECOVERY] 7.7,发送方可以采用pacing或将突发限制在初始拥塞窗口。
8.3. 丢包检测和定时器
确认是QUIC可靠性的基础。因此,延迟或减少确认的频率可能导致在发送方的丢包检测被延迟。
QUIC发送方在接收到确认时使用报文阈值来检测丢失([QUIC-RECOVERY] 6.1.1);延迟确认因此延迟了这种丢包检测的方法。
降低确认频率会减少发送者接收的RTT样本数量([QUIC-RECOVERY]第5节),从而使发送者的RTT估计对路径RTT的变化响应较小。因此,任何依赖于准确RTT估计的机制,如时间阈值丢失检测([QUIC-RECOVERY] 6.1.2)或探测超时([QUIC-RECOVERY] 6.2),对路径RTT的变化的响应都会降低,从而导致延迟或不必要的包传输。
发送方可以使用定时器来检测PMTU探测包的丢失([QUIC-TRANSPORT]第14节)。发送方可以将IMMEDIATE_ACK帧与任何PMTU探测捆绑在一起,以避免触发这样的定时器。
8.4. 连接迁移
为了避免使用此扩展时连接迁移确认的额外延迟,客户端可以将IMMEDIATE_ACK帧与它发送的第一个非探测帧([QUIC-TRANSPORT] 9.2)捆绑在一起,或者可以只发送IMMEDIATE_ACK帧,这是一个非探测帧。
在确认迁移时重置端点的拥塞控制器和RTT估计器([QUIC-TRANSPORT] 9.4);这改变了迁移后接收到的确认的模式。
因此,在连接中较早发送了ACK_FREQUENCY帧的端点应当在用更新的信息确认连接迁移时发送新的ACK_FREUENCY帧,例如考虑新的RTT估计。
9. 安全考虑
配置不当或恶意的发送端可能会导致接收端比其可用资源允许的频率更频繁地进行确认。然而,有两个限制使得这种攻击在很大程度上无关紧要。首先,确认速率受接收数据的速率的限制。其次,ACK_FREQUENCY和IMMEDIATE_ACK帧只能请求增加确认率,但不能强制增加。
一般来说,使用这种扩展,发送方不能强迫接收方比接收方基于其资源约束认为安全的频率更频繁地进行确认。
10. IANA考虑
本文定义了一个新的传输参数来通告支持本文描述的扩展,以及IANQ在各自的“QUIC Protocol”注册表中根据https://www.iana.org/assignments/quic/quic.xhtml.
10.1. QUIC传输参数
表1中的以下条目已被请求临时添加到“QUIC Protocol”标题下的“QUIC Transport Parameters”注册表中。
值 参数名 说明
0xff04de1b min_ack_delay Section 3
本文获得批准时,IANA被要求分配0-63范围内的码点的永久分配,以取代上述临时码点。
10.2. QUIC帧类型
以下帧类型已请求临时添加到“QUIC Protocol”标题下的“QUIC Frame Types”注册表中。
值 帧名 说明
0xaf ACK_FREQUENCY Section 4
0x1f IMMEDIATE_ACK Section 5
当本文获得批准时,IANA被要求将注册更改为具有上述值的这些帧类型的永久分配。