接收方是否可以递减 HTTP/2 流控制窗口?

问题描述

RFC 7540 的

Section 6.9 描述了 HTTP/2 流控制的机制。每个连接都有一个流量控制窗口,该连接上的所有流都有另一个流量控制窗口。它为接收者提供了一种为流设置初始流控制窗口的方法

两个端点都可以通过在构成连接前言的 SETTINGS_INITIAL_WINDOW_SIZE 帧中包含 SETTINGS 的值来调整新流的初始窗口大小。

接收方增加连接和流控制窗口的方法

WINDOW_UPDATE 帧的有效载荷是一个保留位加上一个无符号的 31 位整数,指示除了现有的流量控制窗口之外,发送方可以传输的八位字节数。流量控制窗口增量的合法范围是 1 到 2^31-1 (2,147,483,647) 个八位字节。

[...]

收到 WINDOW_UPDATE 帧的发送方按照帧中指定的数量更新相应的窗口。

还有一种让接收者一次性增加或减少所有流(但不是连接)的流量控制窗口的方法

SETTINGS_INITIAL_WINDOW_SIZE 的值发生变化时,接收者必须通过新值和旧值之间的差异来调整它维护的所有流控制窗口的大小。

但据我所知,接收方无法在不改变初始窗口大小的情况下减少单个流的流量控制窗口

这样对吗?如果是这样,为什么不呢?如果您在单个连接上多路复用许多长期存在的流,这似乎是一件合理的事情。您可能有一些 BDP 控制的用于整个连接的内存预算,分配给各个流,并且正在根据每个流最近的带宽需求调整其获得的比例。如果其中一个暂时空闲,您希望能够将其窗口重置为小,这样它就不会占用内存预算,同时不会影响其他流,也不会导致无法接收新流。>

(当然我理解有竞争,发送方可能在收到减量之前已经发送了数据。但是由于上面的SETTINGS_INITIAL_WINDOW_SIZE机制,窗口已经被允许为负,所以看起来像在这里也允许负窗口是合理的。)

如果不依赖发送方的转发进度来吃掉流控制窗口中的滞留字节,真的不可能做到这一点吗?


这里有更多关于我为什么对这个问题感兴趣的细节,因为我意识到了 XY 问题。

我正在考虑如何解决 RPC 流控制问题。我有一个内存预算有限的服务器,传入的流具有不同的优先级,它们应该允许消耗多少内存。我想在它们之间实现诸如加权最大-最小公平性之类的东西,调整它们的流量控制窗口,使它们的总和不超过我的内存预算,但是当我们不受内存限制时,我们可以获得最大吞吐量。

出于效率原因,希望在单个连接上多路复用不同优先级的流。但是随着需求的变化或其他连接的出现,我们需要能够向下调整流控制窗口,以便它们的总和仍然不超过预算。当流 B 出现或获得更高的优先级但流 A 坐在一堆流量控制预算上时,我们需要减少 A 的窗口并增加 B 的窗口。

即使没有多路复用,同样的问题也适用于连接级别:据我所知,没有办法在不改变初始窗口大小的情况下向下调整连接流控制窗口。当然,随着客户端发送数据,它会向下调整,但我不想依赖于客户端的转发进度,因为这可能需要任意长的时间。

可能有更好的方法来实现这一目标!

解决方法

有 N 个流的服务器,其中一些是空闲的,一些是主动向客户端下载数据,通常会将连接窗口重新分配给活动流。

例如,假设您正在观看电影同时从同一服务器下载一个大文件。

连接窗口为 100,每个流也有一个 100 的窗口(显然在很多流的情况下,所有流窗口的总和将被连接窗口限制,但如果只有一个流,它可以在最大).

现在,当您观看和下载每个流时,您可以获得 50 个。

如果您暂停电影,并且服务器知道这一点(即它不会耗尽电影流窗口),那么服务器现在只需提供一个流,连接窗口为 100 和单个流(下载一个窗口也为 100 的),因此将整个窗口重新分配给活动流。

如果客户端没有告诉服务器电影已暂停,您只会遇到问题。 在这种情况下,服务器将继续发送电影数据,直到电影流窗口耗尽(或准耗尽),并且客户端不会确认该数据,因为它已暂停。 此时,服务器注意到数据未被一个流确认并停止向其发送数据,但当然会占用部分连接窗口,从而减少活动下载流的窗口。

从服务器的角度来看,它有一个非常好的连接,其中一个流(下载流)以最大速度运行良好,但另一个流打嗝并耗尽其窗口并导致另一个流变慢(可能到停止),即使是同一个连接!

显然这不可能是连接/通信问题,因为一个流(下载流)在最大速度下运行良好。 因此,这是一个应用程序问题。

服务器上的 HTTP/2 实现不知道其中一个流是可以暂停的电影——它是应用程序必须与服务器通信并保持尽可能大的连接窗口。

>

引入一个新的 HTTP/2 框架来“暂停”下载(或改变现有框架的语义以适应“暂停”命令)会使协议相当复杂,对于 100% 应用程序驱动的功能 - - 应用程序必须触发“暂停”命令的发送,但此时它可以向服务器发送自己的“暂停”消息,而不会使 HTTP/2 规范复杂化。

这是一个有趣的例子,HTTP/1.1 和 HTTP/2 的行为非常不同,需要不同的代码以类似的方式工作。

使用 HTTP/1.1,您将有一个用于电影的连接和一个用于下载的连接,它们将是独立的,并且客户端应用程序不需要与服务器通信电影已暂停——它可以停止阅读从电影连接直到它变得 TCP 拥塞而不影响下载连接——假设服务器是非阻塞的以避免可扩展性问题。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...