关于HTTP/2和流性能的流窗口大小

3
当我浏览gRPC的dial options时,我接触到了window size的概念。因为gRPC使用HTTP/2作为底层协议,所以我找到了这篇文章,其中写道:

流量控制窗口只是一个整数值,表示接收方的缓冲容量。每个发送方为每个流和整个连接都维护一个单独的流量控制窗口。

如果这就是gRPC所说的窗口大小,而且我理解得没错的话,那么这是为了让HTTP/2在同一连接中维护多个并发流。基本上,这是一个数字,告诉发送方接收方希望下一次发送多少数据。出于控制流的原因,连接将不同流的数据放置在不同的窗口中以进行串行处理。
我的问题是:窗口是全部还是无?也就是说,如果我的窗口大小为n字节,则流不会发送任何数据,直到累积至少n字节?更一般地说,如果我只维护一个流,如何最大化流的性能?我假设更大的窗口大小将有助于避免开销,但会增加数据丢失的风险?
1个回答

2
如果我的窗口大小为n字节,那么当累积的数据量达到n个字节之前,流就不会发送任何数据,是吗?
不是。 发送方可以发送小于或等于n的任何字节数。
更一般地说,如果我只维护一个流,如何最大化流的性能?
对于只有一个流的情况,只需使用最大可能的值2^31-1。 此外,您需要配置接收器尽快发送WINDOW_UPDATE帧,以便发送方始终具有足够大的流控制窗口,使其永远不会停止发送。
需要注意的一件重要事情是,最大流控制窗口的配置与接收器的内存容量有关。
由于HTTP/2是多路复用的,实现必须继续读取数据,直到流控制窗口耗尽。使用最大流控制窗口2 GiB意味着接收器需要准备好缓冲至少2 GiB的数据,直到应用程序决定消耗该数据。
换句话说:通过实现从网络读取数据,并且应用程序以不同的速度消耗该数据;如果读取速度比消耗速度快,则实现必须读取数据并将其累积到一边,直到应用程序可以消耗它。
当应用程序消耗数据时,它告诉实现消耗了多少字节,实现可以向发送方发送WINDOW_UPDATE帧,以再次扩大流控制窗口,使发送方可以继续发送。
请注意,实现确实希望施加反压力,即等待应用程序在向发送方发送WINDOW_UPDATE之前消耗数据。 如果实现(错误地)在将数据传递给应用程序之前确认数据的消耗,则存在内存膨胀的风险,因为发送方将继续发送,但接收方被迫将其累积到主机内存中,直到主机内存耗尽(假设应用程序比实现从网络读取数据更慢)。
考虑到上述情况,单个连接对于最大流控制窗口可能需要高达2 GiB的内存。 想象一下有1024个连接(对于服务器来说并不多),您需要2 TiB的内存。
还要考虑到这样的大型流控制窗口可能会在流控制窗口耗尽之前遇到TCP拥塞(头部阻塞)。 如果发生这种情况,您基本上回到了TCP连接容量,这意味着HTTP/2流控制限制永远不会触发,因为TCP限制先触发(或者受带宽等限制)。
另一个要考虑的问题是,您要避免发送方耗尽流控制窗口,因此被迫停止发送。
对于1 MiB的流量控制窗口,您不希望接收1 MiB的数据,消耗它,然后发送1 MiB的WINDOW_UPDATE,因为否则客户端将发送1 MiB,停顿,接收WINDOW_UPDATE,再次发送1 MiB,再次停顿,以此类推(请参见如何在上传时使用多路复用http2功能)。
从历史上看,小的流量控制窗口(如规范中建议的64 KiB)会导致浏览器下载非常缓慢,浏览器很快意识到他们需要告诉服务器他们的流量控制窗口足够大,以便服务器不会使下载停滞。目前,Firefox和Chrome将其设置为16 MiB。
您希望向发送方提供WINDOW_UPDATE,以便它永远不会停滞。
这是应用程序消耗接收数据的速度,您希望在发送WINDOW_UPDATE之前“累积”已消耗字节数的数量(以避免过于频繁地发送WINDOW_UPDATE),以及从接收者到发送者传递WINDOW_UPDATE所需的时间的组合。

谢谢。这是一个非常详尽的答案。 - bli00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接