当前位置: 首页 > 后端技术 > Java

Netty系列:netty在http2中实现流量控制

时间:2023-04-02 10:05:41 Java

介绍HTTP2相对于http1.1的一个重要改进就是流量控制flowcontrol。为什么会有流量控制?这是因为无论是哪种协议,客户端和服务端在接收数据时都有一个缓冲区来临时存放暂时不能处理的数据,但是缓冲区的大小是有限的,所以可能会有一个缓冲区在溢出的情况,比如客户端向服务器上传了一张大图片,可能会导致服务器上的缓冲区溢出,造成一些额外的丢包。为了避免缓冲区溢出,每个HTTP协议都提供了一定的解决方案。在HTTP1.1中,流量控制依赖于底层的TCP协议。当客户端和服务器建立连接时,系统默认设置用于建立缓冲区。数据通信时,会告诉对方自己接收窗口的大小,也就是缓冲区中剩余的可用空间。如果接收窗口大小为零,则接收方缓冲区已满,发送方将不再发送数据,直到客户端清除其内部缓冲区,然后请求恢复数据传输。HTTP2通过客户端和服务端的应用程序传输缓冲区大小消息,在应用层层面控制数据流量,因此每个应用程序都可以自行控制流量的大小,从而获得更高的连接效率。本文将介绍netty对http2流量控制的支持。介绍中也提到了http2中的流量控制。传统的HTTP1.1采用的是系统底层的流量控制机制,具体是TCP的流量控制。但是TCP的流量控制在HTTP2中还不够。因为HTTP2使用了多路复用机制,一个TCP连接可以有多个http2连接。所以对于http2来说,TCP本身的流量控制机制就太粗糙了,不够精细。所以在HTTP2中,实现了更细粒度的流控机制,允许客户端和服务端实现自己的数据流和连接级别的流控。具体过程如下。当客户端和服务端建立连接时,会发送Http2SettingsFrame。这个设置框包含SETTINGS_INITIAL_WINDOW_SIZE,这是发送方的窗口大小,用于Stream级别的流量控制。流量控制窗口的默认值设置为65,535字节,但接收方可以将其修改为最大2^31-1字节。初始窗口大小确定后,对于接收方来说,发送方每发送一个数据帧,窗口的大小就会减小,接收方每发送一个WINDOW_UPDATE帧,窗口的大小就会增加,从而达到动态控制的目的。Netty对http2流控的封装Http2FlowController从上面的介绍我们知道http2流控是通过两个方面来实现的。第一个方面是初始化的Http2SettingsFrame,通过设置SETTINGS_INITIAL_WINDOW_SIZE来控制初始窗口的大小。第二个方面是在后续的WINDOW_UPDATE帧中动态增加或减小窗口的大小。对于netty来说,这都封装在了Http2FlowController类中。Http2FlowController是一个抽象类,它有两个实现,Http2LocalFlowController和Http2RemoteFlowController。它们分别代表对DATA入站流和DATA出站流的处理。Http2FlowController中主要有五个方法,分别是:设置channelHandlerContext:将flowcontrol绑定到ChannelHandlerContext。setinitialWindowSize:初始化窗口大小,相当于设置SETTINGS_INITIAL_WINDOW_SIZE。getinitialWindowSize:返回初始窗口大小。windowSize:获取当前窗口大小。incrementWindowSize:增加流量控制窗口的大小。接下来我们看看他的两个实现类,有什么区别。Http2LocalFlowControllerLocalFlowController用于控制从远程节点发送的DATA帧的流量。它有5个主要方法。setframeWriter:用于设置用于发送WINDOW_UPDATE帧的帧编写器。receiveFlowControlledFrame:接收入站DATA帧并对其进行流控。consumeBytes:表示应用程序已经消耗了一定数量的字节,可以接受更多从远程节点发送的数据。流量控制可以发送WINDOW_UPDATE帧来重置窗口大小。unconsumedBytes:已接收但未消耗的字节数。initialWindowSize:给定流的初始窗口大小。Http2RemoteFlowControllerremoteFlowController用于处理发送到远程节点的出站数据帧。它提供了8个方法:getchannelHandlerContext:获取当前流控的上下文。addFlowControlled:将流量控制负载添加到发送到远程节点的队列中。hasFlowControlled:判断当前流队列中是否有FlowControlled帧。writePendingBytes:将流控器中的所有待定数据写入流控限制。listener:给流控制器添加监听器。isWritable:确定流是否有剩余字节供流量控制窗口使用。channelWritabilityChanged:上下文的可写状态是否已经改变。updateDependencyTree:更新流之间的依赖关系,因为流可以有父子结构。流量控制的使用flowControl相关类主要用在Http2Connection、Http2ConnectionDecoder、Http2ConnectionEncoder中,在建立http2连接时起到相应的作用。总结flowControl是http2中比较底层的概念,深入了解netty的http2实现后应该会遇到。本文已收录于http://www.flydean.com/29-netty-flowcontrol/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等着你去探索!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!