简介

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 frame中包含了SETTINGS_INITIAL_WINDOW_SIZE,这个是发送端的窗口大小,用于 Stream 级别流控。流控制窗口的默认值设为65,535字节,但是接收方可以对其进行修改,最大值为2^31-1 字节。

建立好初始windows size之后,对于接收方来说,每次发送方发送data frame就会减少window的的大小,而接收方每次发送WINDOW_UPDATE frame时候就会增加window的大小,从达到动态控制的目的。

netty对http2流控制的封装

Http2FlowController

从上面的介绍我们知道,http2对流控制是通过两个方面来实施的,第一个方面就是初始化的Http2SettingsFrame,通过设置SETTINGS_INITIAL_WINDOW_SIZE来控制初始window的大小。第二个方面就是在后续的WINDOW_UPDATE frame中对window的大小进行动态增减。

对于netty来说,这一切都是封装在Http2FlowController类中的。Http2FlowController是一个抽象类,它有两个实现,分别是Http2LocalFlowController和Http2RemoteFlowController。他们分别表示对inbound flow of DATA 和 outbound flow of DATA的处理。

Http2FlowController中主要有5个方法,分别是:

  • set channelHandlerContext:绑定flowcontrol到ChannelHandlerContext上。
  • set initialWindowSize:初始化window size,等同于设置SETTINGS_INITIAL_WINDOW_SIZE。
  • get initialWindowSize: 返回初始化window size。
  • windowSize: 获取当前的windowSize。
  • incrementWindowSize: 增加flow control window的大小。

接下来我们看下他的两个实现类,有什么不一样的地方。

Http2LocalFlowController

LocalFlowController用来对远程节点发过来的DATA frames做flow control。它有5个主要的方法。

  • set frameWriter: 用来设置发送WINDOW_UPDATE frames的frame writer。
  • receiveFlowControlledFrame: 接收inbound DATA frame,并且对其进行flow control。
  • consumeBytes: 表示应用已经消费了一定数目的bytes,可以接受更多从远程节点发过来的数据。flow control可以发送 WINDOW_UPDATE frame来重置window大小。
  • unconsumedBytes: 接收到,但是未消费的bytes。
  • initialWindowSize: 给定stream的初始window大小。

Http2RemoteFlowController

remoteFlowController用来处理发送给远程节点的outbound DATA frames。它提供了8个方法:

  • get channelHandlerContext: 获取当前flow control的context.
  • addFlowControlled: 将flow control payload添加到发送到远程节点的queue中。
  • hasFlowControlled: 判断当前stream是否有 FlowControlled frames在queue中。
  • writePendingBytes: 将流量控制器中的所有待处理数据写入流量控制限制。
  • listener: 给 flow-controller添加listener。
  • isWritable: 确定流是否有剩余字节可用于流控制窗口。
  • channelWritabilityChanged: context的writable状态是否变化。
  • updateDependencyTree: 更新stream之间的依赖关系,因为stream是可以有父子结构的。

流控制的使用

flowControl相关的类主要被用在Http2Connection,Http2ConnectionDecoder,Http2ConnectionEncoder中,在建立http2连接的时候起到相应的作用。

总结

flowControl是http2中的一个比较底层的概念,大家在深入了解netty的http2实现中应该会遇到。

本文已收录于 http://www.flydean.com/29-netty-flowcontrol/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

netty系列之:netty实现http2中的流控制的更多相关文章

  1. 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?

    [读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...

  2. Netty 系列之 Netty 高性能之道 高性能的三个主题 Netty使得开发者能够轻松地接受大量打开的套接字 Java 序列化

    Netty系列之Netty高性能之道 https://www.infoq.cn/article/netty-high-performance 李林锋 2014 年 5 月 29 日 话题:性能调优语言 ...

  3. netty系列之:netty对http2消息的封装

    目录 简介 http2消息的结构 netty对http2的封装 Http2Stream Http2Frame 总结 简介 无论是什么协议,如果要真正被使用的话,需要将该协议转换成为对应的语言才好真正的 ...

  4. netty系列之:netty架构概述

    目录 简介 netty架构图 丰富的Buffer数据机构 零拷贝 统一的API 事件驱动 其他优秀的特性 总结 简介 Netty为什么这么优秀,它在JDK本身的NIO基础上又做了什么改进呢?它的架构和 ...

  5. Netty 系列之 Netty 高性能之道

    1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用 Netty4 + Thrift 压缩二进制编解码技术,他们实现了 10 W TPS(1 K 的复杂 POJO 对象)的跨 ...

  6. Netty系列之Netty高性能之道

    转载自http://www.infoq.com/cn/articles/netty-high-performance 1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Ne ...

  7. 转:Netty系列之Netty高性能之道

    1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用 ...

  8. netty系列之:netty中的ByteBuf详解

    目录 简介 ByteBuf详解 创建一个Buff 随机访问Buff 序列读写 搜索 其他衍生buffer方法 和现有JDK类型的转换 总结 简介 netty中用于进行信息承载和交流的类叫做ByteBu ...

  9. netty系列之:netty中的Channel详解

    目录 简介 Channel详解 异步IO和ChannelFuture Channel的层级结构 释放资源 事件处理 总结 简介 Channel是连接ByteBuf和Event的桥梁,netty中的Ch ...

随机推荐

  1. JAVA反序列化漏洞基础原理

    JAVA反序列化漏洞基础原理 1.1 什么是序列化和反序列化? Java序列化是指把Java对象转换为字节序列的过程: Java反序列化是指把字节序列恢复为Java对象的过程: 1.2 为什么要序列化 ...

  2. 图论---最小生成树----普利姆(Prim)算法

    普利姆(Prim)算法 1. 最小生成树(又名:最小权重生成树) 概念:将给出的所有点连接起来(即从一个点可到任意一个点),且连接路径之和最小的图叫最小生成树.最小生成树属于一种树形结构(树形结构是一 ...

  3. Loadrunner拼装唯一值方法

    由于Loadrunner函数有限性,唯一值需要几个函数的字符串进行拼装,可实现流水号.订单号等等数值的唯一性.具体可见下列方法: 方法一: char OraderID[15];srand(time{N ...

  4. 学习PHP中的国际化功能来查看货币及日期信息

    做为一门在世界范围内广泛使用的编程语言,国际化能力往往是衡量一个编程语言是否能够大范围流行的重要内容.特别是对于 PHP 这种以 Web 页面编程为主战场的语言来说,国际化能力更是重中之重.在 PHP ...

  5. Docker系列(3)- 配置阿里云镜像加速

    step-1 登录阿里云找到容器服务 step-2 找到镜像加速地址 step-3 配置使用 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon ...

  6. Kotlin协程入门

    开发环境 IntelliJ IDEA 2021.2.2 (Community Edition) Kotlin: 212-1.5.10-release-IJ5284.40 介绍Kotlin中的协程.用一 ...

  7. chrome 的 options 参数

    在使用selenium浏览器渲染技术,爬取网站信息时,默认情况下就是一个普通的纯净的chrome浏览器,而我们平时在使用浏览器时,经常就添加一些插件,扩展,代理之类的应用.相对应的,当我们用chrom ...

  8. c++ 的学习 第二集函数的重载

    1. 规则 函数名相同参数个数不同.参数类型不同.参数顺序不同 2. 注意 返回值类型与函数重载无关 调用函数时,实参的隐式类型转换可能会产生二义性 返回值类型与函数重载无关 什么意思? 返回 ...

  9. P1912-[NOI2009]诗人小G【四边形不等式,单调队列】

    正题 题目链接:https://www.luogu.com.cn/problem/P1912 题目大意 给出\(n\)个字符串,把这些字符串依次用空格(算一个长度)连接分成若干段,若一段长度为\(x\ ...

  10. 📝 没 2 年 React Native 开发经验,你都遇不到这些坑

    如果你喜欢我的文章,希望点赞 收藏 评论 三连支持一下,谢谢你,这对我真的很重要! React Native 开发时,如果只是写些简单的页面,基本上按着官方文档 reactnative.dev就能写出 ...