关于 HTTP/2 和流性能的流 window 大小
Stream window size with regards to HTTP/2 and stream performance
我在浏览 gRPC 的 dial options. Because gRPC uses HTTP/2 underneath, I dug this article 时遇到了 window 大小 的概念,它描述了:
Flow control window is just nothing more than an integer value indicating the buffering capacity of the receiver. Each sender maintains a separate flow control window for each stream and for the overall connection.
如果这是 gRPC 所说的 window 大小,我理解正确。这是为了 HTTP/2 在同一个连接中维护多个并发流。基本上是一个向发送方通告的数字,表明接收方希望发送方接下来发送多少数据。出于控制流的原因,连接将不同流的数据串行放置在不同的 windows 中。
我的问题 is/are:window 是全有还是全无?这意味着如果我的 window 大小是 n
字节,流将不会发送任何数据,直到它累积至少 n
字节?更一般地说,如果我只维持 一个流 ,我该如何最大化我的流的性能?我假设更大的 window 大小有助于避免开销但会增加数据丢失的风险?
Meaning if my window size is n
bytes, the stream won't send any data until it's accumulated at least n
bytes?
没有。
发送方可以发送小于或等于 n
.
的任意字节数
More generally, how do I maximize the performance of my stream if I maintain only one stream?
对于一个流,只使用最大可能值,2^31-1
。
此外,您希望将接收方配置为足够快地发送 WINDOW_UPDATE
帧,以便发送方始终具有足够大的流量控制 window,使其永远不会停止发送。
需要注意的一点是,最大流量控制的配置window与接收方的内存容量有关。
由于HTTP/2被多路复用,实现必须继续读取数据,直到流量控制window耗尽。
使用最大流量控制 window,2 GiB,意味着接收方需要准备缓冲至少 2 GiB 的数据,直到应用程序决定使用该数据。
换句话说:实现从网络读取数据和应用程序使用该数据可能以不同的速度发生;如果读取速度比使用速度快,则实现必须读取数据并将其累积到一边,直到应用程序可以使用它。
当应用程序消耗数据时,它告诉实现消耗了多少字节,并且实现可能会向发送方发送一个WINDOW_UPDATE
帧,以再次扩大流量控制window,这样发件人就可以继续发送了。
请注意,实现确实需要应用背压,即等待应用程序使用数据,然后再将 WINDOW_UPDATE
秒发送回发送方。
如果实现(错误地)在将数据传递给应用程序之前确认了数据的消耗,那么它可能会导致内存爆炸,因为发送方将继续发送,但接收方被迫将其累积到一边,直到接收器耗尽(假设应用程序消耗数据的速度比实现从网络读取数据的速度慢)。
鉴于上述情况,对于最大流量控制 window,单个连接可能需要多达 2 GiB 的内存。
想象一下 1024 个连接(对于服务器来说不算多),你需要 2 TiB 的内存。
还要考虑到对于如此大的流量控制 windows,您可能会在流量控制 window 耗尽之前遇到 TCP 拥塞(线头阻塞)。
如果发生这种情况,你基本上回到了 TCP 连接容量,这意味着 HTTP/2 流量控制限制永远不会触发,因为 TCP 限制之前触发(或者你受到带宽等限制)。
另一个需要考虑的因素是,您要避免发送方耗尽流量控制 window 并因此被迫停止发送。
对于 1 MiB 的流量控制 window,您不想接收 1 MiB 的数据,使用它然后发回 1 MiB 的 WINDOW_UPDATE
,否则客户端将发送 1 MiB,停止,接收 WINDOW_UPDATE
,发送另一个 1 MiB,再次停止,等等(另见 )。
从历史上看,小流量控制 windows(如 64 KiB 规范中所建议的那样)导致浏览器中的下载速度超慢,浏览器很快意识到他们需要告诉服务器他们的流量控制 window 足够大,所以服务器不会停止下载。
目前,Firefox 和 Chrome 将其设置为 16 MiB。
您想为发件人提供 WINDOW_UPDATE
s,这样它就永远不会停止。
这是应用程序消耗接收数据的速度的组合,在发送 WINDOW_UPDATE
之前您希望“累积”消耗的字节数(以避免发送 WINDOW_UPDATE
频繁),以及 WINDOW_UPDATE
从接收方到发送方需要多长时间。
我在浏览 gRPC 的 dial options. Because gRPC uses HTTP/2 underneath, I dug this article 时遇到了 window 大小 的概念,它描述了:
Flow control window is just nothing more than an integer value indicating the buffering capacity of the receiver. Each sender maintains a separate flow control window for each stream and for the overall connection.
如果这是 gRPC 所说的 window 大小,我理解正确。这是为了 HTTP/2 在同一个连接中维护多个并发流。基本上是一个向发送方通告的数字,表明接收方希望发送方接下来发送多少数据。出于控制流的原因,连接将不同流的数据串行放置在不同的 windows 中。
我的问题 is/are:window 是全有还是全无?这意味着如果我的 window 大小是 n
字节,流将不会发送任何数据,直到它累积至少 n
字节?更一般地说,如果我只维持 一个流 ,我该如何最大化我的流的性能?我假设更大的 window 大小有助于避免开销但会增加数据丢失的风险?
Meaning if my window size is
n
bytes, the stream won't send any data until it's accumulated at leastn
bytes?
没有。
发送方可以发送小于或等于 n
.
More generally, how do I maximize the performance of my stream if I maintain only one stream?
对于一个流,只使用最大可能值,2^31-1
。
此外,您希望将接收方配置为足够快地发送 WINDOW_UPDATE
帧,以便发送方始终具有足够大的流量控制 window,使其永远不会停止发送。
需要注意的一点是,最大流量控制的配置window与接收方的内存容量有关。
由于HTTP/2被多路复用,实现必须继续读取数据,直到流量控制window耗尽。
使用最大流量控制 window,2 GiB,意味着接收方需要准备缓冲至少 2 GiB 的数据,直到应用程序决定使用该数据。
换句话说:实现从网络读取数据和应用程序使用该数据可能以不同的速度发生;如果读取速度比使用速度快,则实现必须读取数据并将其累积到一边,直到应用程序可以使用它。
当应用程序消耗数据时,它告诉实现消耗了多少字节,并且实现可能会向发送方发送一个WINDOW_UPDATE
帧,以再次扩大流量控制window,这样发件人就可以继续发送了。
请注意,实现确实需要应用背压,即等待应用程序使用数据,然后再将 WINDOW_UPDATE
秒发送回发送方。
如果实现(错误地)在将数据传递给应用程序之前确认了数据的消耗,那么它可能会导致内存爆炸,因为发送方将继续发送,但接收方被迫将其累积到一边,直到接收器耗尽(假设应用程序消耗数据的速度比实现从网络读取数据的速度慢)。
鉴于上述情况,对于最大流量控制 window,单个连接可能需要多达 2 GiB 的内存。 想象一下 1024 个连接(对于服务器来说不算多),你需要 2 TiB 的内存。
还要考虑到对于如此大的流量控制 windows,您可能会在流量控制 window 耗尽之前遇到 TCP 拥塞(线头阻塞)。
如果发生这种情况,你基本上回到了 TCP 连接容量,这意味着 HTTP/2 流量控制限制永远不会触发,因为 TCP 限制之前触发(或者你受到带宽等限制)。
另一个需要考虑的因素是,您要避免发送方耗尽流量控制 window 并因此被迫停止发送。
对于 1 MiB 的流量控制 window,您不想接收 1 MiB 的数据,使用它然后发回 1 MiB 的 WINDOW_UPDATE
,否则客户端将发送 1 MiB,停止,接收 WINDOW_UPDATE
,发送另一个 1 MiB,再次停止,等等(另见 )。
从历史上看,小流量控制 windows(如 64 KiB 规范中所建议的那样)导致浏览器中的下载速度超慢,浏览器很快意识到他们需要告诉服务器他们的流量控制 window 足够大,所以服务器不会停止下载。 目前,Firefox 和 Chrome 将其设置为 16 MiB。
您想为发件人提供 WINDOW_UPDATE
s,这样它就永远不会停止。
这是应用程序消耗接收数据的速度的组合,在发送 WINDOW_UPDATE
之前您希望“累积”消耗的字节数(以避免发送 WINDOW_UPDATE
频繁),以及 WINDOW_UPDATE
从接收方到发送方需要多长时间。