简体   繁体   English

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

[英]Is it possible for the receiver to decrement an HTTP/2 stream flow control window?

Section 6.9 of RFC 7540 describes the mechanism for HTTP/2 flow control. RFC 7540 的第 6.9 节描述了 HTTP/2 流控制的机制。 There is a flow control window for each connection, and another flow control window for all streams on that connection.每个连接都有一个流量控制窗口,该连接上的所有流都有另一个流量控制窗口。 It provides a way for the receiver to set the initial flow control window for a stream:它为接收者提供了一种为流设置初始流控制窗口的方法:

Both endpoints can adjust the initial window size for new streams by including a value for SETTINGS_INITIAL_WINDOW_SIZE in the SETTINGS frame that forms part of the connection preface.两个端点可通过包括用于一个值调整为新流的初始窗口大小SETTINGS_INITIAL_WINDOW_SIZESETTINGS框架,所述连接序言的形成部分。

And a way for the receiver to increase the connection and stream flow control windows:以及接收方增加连接和流控制窗口的一种方式:

The payload of a WINDOW_UPDATE frame is one reserved bit plus an unsigned 31-bit integer indicating the number of octets that the sender can transmit in addition to the existing flow-control window. WINDOW_UPDATE帧的有效载荷是一个保留位加上一个无符号的 31 位整数,指示除了现有的流量控制窗口之外,发送方可以传输的八位字节数。 The legal range for the increment to the flow-control window is 1 to 2^31-1 (2,147,483,647) octets.流控制窗口增量的合法范围是 1 到 2^31-1 (2,147,483,647) 个八位字节。

[...] [...]

A sender that receives a WINDOW_UPDATE frame updates the corresponding window by the amount specified in the frame.接收 WINDOW_UPDATE 帧的发送者按帧中指定的数量更新相应的窗口。

And a way for the receiver to increment or decrement the flow control windows for all streams (but not the connection) at once:以及接收器一次增加或减少所有流(但不是连接)的流量控制窗口的方法:

When the value of SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST adjust the size of all stream flow-control windows that it maintains by the difference between the new value and the old value.SETTINGS_INITIAL_WINDOW_SIZE发生变化时,接收者必须通过新值和旧值之间的差异来调整它维护的所有流控制窗口的大小。

But as far as I can tell, there is no way for the receiver to decrement a single stream's flow control window without changing the initial window size .但据我所知,接收者无法在不改变初始窗口大小的情况下减少单个流的流量控制窗口

Is that correct?那是对的吗? If so, why not?如果是这样,为什么不呢? This seems like a reasonable thing to want to do if you are multiplexing many long-lived streams over a single connection.如果您在单个连接上多路复用许多长期存在的流,这似乎是一件合理的事情。 You may have some BDP-controlled memory budget for the overall connection, carved up across the streams, and are tuning the proportion that each stream gets according to its recent bandwidth demand.您可能有一些 BDP 控制的用于整个连接的内存预算,分配给各个流,并且正在根据每个流最近的带宽需求调整其获得的比例。 If one of them temporarily goes idle you'd like to be able to reset its window to be small so that it doesn't strand the memory budget, without affecting the other streams, and without making it impossible to receive new streams.如果其中一个暂时空闲,您希望能够将其窗口重置为小,这样它就不会占用内存预算,而不会影响其他流,并且不会导致无法接收新流。

(Of course I understand that there is a race, and the sender may have sent data before receiving the decrement. But the window is already allowed to go negative due to the SETTINGS_INITIAL_WINDOW_SIZE mechanism above, so it seems like it would be reasonable to allow for a negative window here too.) (当然我知道存在竞争,并且发送方可能在收到减量之前已经发送了数据。但是由于上面的SETTINGS_INITIAL_WINDOW_SIZE机制,窗口已经被允许为负,所以似乎允许这里也是一个负窗口。)

Is it really not possible to do this without depending on forward progress from the sender to eat up the stranded bytes in the flow control window?如果不依赖发送方的转发进度来吃掉流量控制窗口中的滞留字节,真的不可能做到这一点吗?


Here's more detail on why I'm interested in the question, because I'm conscious of the XY problem.这里有更多关于我为什么对这个问题感兴趣的细节,因为我知道 XY 问题。

I'm thinking about how to solve an RPC flow control issue.我正在考虑如何解决 RPC 流控制问题。 I have a server with a limited memory budget, and incoming streams with different priorities for how much of that memory they should be allowed to consume.我有一个内存预算有限的服务器,传入的流具有不同的优先级,它们应该允许消耗多少内存。 I want to implement something like weighted max-min fairness across them, adjusting their flow control windows so that they sum to no more than my memory budget, but when we're not memory constrained we get maximum throughput.我想在它们之间实现诸如加权最大-最小公平性之类的东西,调整它们的流量控制窗口,使它们的总和不超过我的内存预算,但是当我们不受内存限制时,我们可以获得最大吞吐量。

For efficiency reasons, it would be desirable to multiplex streams of different priorities on a single connection.出于效率原因,希望在单个连接上多路复用不同优先级的流。 But then as demands change, or as other connections show up, we need to be able to adjust stream flow control windows downward so they still sum to no more than the budget.但是随着需求的变化或其他连接的出现,我们需要能够向下调整流控制窗口,这样它们的总和仍然不超过预算。 When stream B shows up or receives a higher priority but stream A is sitting on a bunch of flow control budget, we need to reduce A's window and increase B's.当流 B 出现或获得更高的优先级但流 A 坐在一堆流量控制预算上时,我们需要减少 A 的窗口并增加 B 的窗口。

Even without the multiplexing, the same problem applies at the connection level: as far as I can tell, there is no way to adjust the connection flow control window downward without changing the initial window size.即使没有多路复用,同样的问题也适用于连接级别:据我所知,没有办法在不改变初始窗口大小的情况下向下调整连接流控制窗口。 Of course it will be adjusted downward as the client sends data, but I don't want to need to depend on forward progress from the client for this, since that may take arbitrarily long.当然,它会随着客户端发送数据而向下调整,但我不想依赖于客户端的转发进度,因为这可能需要任意长的时间。

It's possible there is a better way to achieve this!可能有更好的方法来实现这一目标!

A server that has N streams, of which some idle and some actively downloading data to the client, will typically re-allocate the connection window to active streams.有 N 个流的服务器,其中一些空闲和一些主动下载数据到客户端,通常会将连接窗口重新分配给活动流。

For example, say you are watching a movie and downloading a big file from the same server at the same time.例如,假设您正在观看电影同时从同一服务器下载一个大文件。

Connection window is 100, and each stream has a window of 100 too (obviously in case of many streams the sum of all stream windows will be capped by the connection window, but if there is only one stream it can be at max).连接窗口是 100,每个流也有一个 100 的窗口(很明显,在许多流的情况下,所有流窗口的总和将被连接窗口限制,但如果只有一个流,它可以是最大的)。

Now, when you watch and download each stream gets 50.现在,当您观看和下载每个流时,将获得 50 个。

If you pause the movie, and the server knows about that (ie it does not exhaust the movie stream window), then the server now has to serve only one stream, with a connection window of 100 and a single stream (the download one) that also has window of 100, therefore reallocating the whole window to the active stream.如果您暂停电影,并且服务器知道这一点(即它不会耗尽电影流窗口),那么服务器现在只需要提供一个流,连接窗口为 100 和一个流(下载一个)它的窗口也为 100,因此将整个窗口重新分配给活动流。

You only get into problems if the client doesn't tell the server that the movie has been paused.如果客户端没有告诉服务器电影已暂停,您只会遇到问题。 In this case, the server will continue to send movie data until the movie stream window is exhausted (or quasi exhausted), and the client does not acknowledges that data because it's paused.在这种情况下,服务器将继续发送电影数据,直到电影流窗口耗尽(或准耗尽),并且客户端不会确认该数据,因为它已暂停。 At that point, the server notices that data is not acknowledged by one stream and stops sending data to it, but of course part of the connection window is taken, reducing the window of the active download stream.此时,服务器注意到数据未被一个流确认并停止向其发送数据,但当然会占用部分连接窗口,从而减少活动下载流的窗口。

From the server point of view, it has a perfectly good connection where one stream (the download one) works wonderfully at max speed, but another stream hiccups and exhausts its window and causes the other stream to slow down (possibly to a halt), even if it's the same connection!从服务器的角度来看,它有一个非常好的连接,其中一个流(下载流)以最大速度运行良好,但另一个流打嗝并耗尽其窗口并导致另一个流变慢(可能停止),即使是相同的连接!

Obviously it cannot be a connection/communication issue, because one stream (the download one) works perfectly fine at max speed.显然,这不可能是连接/通信问题,因为一个流(下载流)在最大速度下运行得非常好。 Therefore it is an application issue.因此,这是一个应用程序问题。

The HTTP/2 implementation on the server does not know that one of the streams is a movie that can be paused -- it's the application that must communicate this to the server and keep the connection window as large as possible.服务器上的 HTTP/2 实现不知道其中一个流是可以暂停的电影——应用程序必须将其与服务器通信并保持尽可能大的连接窗口。

Introducing a new HTTP/2 frame to "pause" downloads (or changing the semantic of the existing frames to accommodate a "pause" command) would have complicated the protocol quite substantially, for a feature that is 100% application driven -- it is the application that must trigger the send of the "pause" command but at that point it can send its own "pause" message to the server without complicating the HTTP/2 specification.引入一个新的 HTTP/2 框架来“暂停”下载(或改变现有框架的语义以适应“暂停”命令)会使协议相当复杂,对于 100% 应用程序驱动的功能——它是必须触发发送“暂停”命令的应用程序,但此时它可以向服务器发送自己的“暂停”消息,而不会使 HTTP/2 规范复杂化。

It is an interesting case where HTTP/1.1 and HTTP/2 behave very differently and require different code to work in a similar way.这是一个有趣的例子,HTTP/1.1 和 HTTP/2 的行为非常不同,需要不同的代码以类似的方式工作。

With HTTP/1.1 you would have one connection for the movie and one for the download, they would be independent, and the client application would not need to communicate to the server that the movie was paused -- it could just stop reading from the movie connection until it became TCP congested without affecting the download connection -- assuming that the server is non-blocking to avoid scalability issues.使用 HTTP/1.1,您将有一个用于电影的连接和一个用于下载的连接,它们将是独立的,并且客户端应用程序不需要与服务器通信电影已暂停——它可以停止从电影中读取连接直到它变成 TCP 拥塞而不影响下载连接——假设服务器是非阻塞的以避免可扩展性问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM