Dubbo-HTTP2


  • HTTP1
    • HTTP1协议的这种格式,缺点也是很明显的
      • 额外占用了很多字节,比如众多的回车符、换行符,它们都是字符,都需要一个字节
      • 通常一个HTTP1的请求,都会携带各种请求头,我们可以通过请求头来指定请求体的压缩方式
        • 但是我们没有地方可以指定请求头的压缩方式
      • 不能并发的发送请求,因为不知道这个响应结果对应的到底是哪一个HTTP1请求
        • 可以在请求头和响应头中做一个标记
  • HTTP2
      • 帧长度,用三个字节来存一个数字,这个数字表示当前帧的实际传输的数据的大小,3个字节表示的最大数字是2的24次方(16M),所以一个帧最大为9字节+16M
      • 帧类型,占一个字节,可以分为数据帧和控制帧
        • 数据帧又分为:HEADERS 帧和 DATA 帧,用来传输请求头、请求体的
        • 控制帧又分为:SETTINGS、PING、PRIORITY,用来进行管理的
      • 标志位,占一个字节,可以用来表示当前帧是整个请求里的最后一帧,方便服务端解析
      • 流标识符,占4个字节,在Java中也就是一个int,不过最高位保留不用,表示Stream ID
      • 实际传输的数据Payload
        • 如果帧类型是HEADERS,那么这里存的就是请求头
        • 如果帧类型是DATA ,那么这里存的就是请求体
    • 如果帧的类型是HEADERS ,那就进行压缩请求头,当然压缩算法是固定的HPACK算法,不能更换
  • HTTP2-Stream
    • 流标识符,表示Stream ID,表示一个“虚拟流”
      • 可以在一个TCP连接中,同时维护多个Stream,每一个帧都是属于某一个Stream
      • 也就是说客户端在一个TCP连接上,可以并发的给服务端同时发送多个帧
  • HTTP2发送一个请求时
    • 新建一个TCP连接(三次握手)
    • 新建一个Stream,生成一个新的StreamID,生成一个控制帧
      • 帧里记录了前面生成出来的StreamID,通过TCP连接发送出去
    • 生成一个要发送的请求对应的HEADERS 帧,用来发送请求头,也是key:value的格式
      • 先利用ascii进行编码,然后利用HPACK算法进行压缩
      • 最终把压缩之后的字节存在帧中的Payload区域
      • 记录好StreamID,最后通过TCP连接把这个HEADERS 帧发送出去
    • 最后把要发送的请求体数据按指定的压缩算法(请求中所指定的压缩算法,比如gzip)进行压缩
      • 把压缩之后的字节生成DATA 帧,记录好StreamID,通过TCP连接把DATA 帧发送出去
  • 对于服务端而言
    • 会不断的从TCP连接接收到某些帧
    • 当接收到一个控制帧时,表示客户端要和服务端新建一个Stream,在服务端记录一下StreamID
      • 比如在Dubbo3.0的源码中会生成一个ServerStreamObserver的对象
    • 当接收到一个HEADERS 帧,取出StreamID,找到对应的ServerStreamObserver对象,并解压得到请求头
      • 把请求头信息保存在ServerStreamObserver对象中
    • 当接收到一个DATA 帧时,取出StreamID,找到对应的ServerStreamObserver对象
      • 根据请求头的信息看如何解压请求体
      • 解压之后就得到了原生请求体数据,然后按业务逻辑处理请求体
    • 处理完了之后,就把结果也生成 HEADERS 帧和 DATA 帧发送客户端
      • 客户端此时就变成了服务端,来处理响应结果
    • 客户端接收到响应结果的HEADERS 帧,是也先解压得到响应头,记录响应体的解压方式
    • 然后继续接收到响应结果的DATA 帧,解压响应体,得到原生的响应体,处理响应体
  • 对于Triple协议而言,我们主要理解HTTP2中的Stream、HEADERS 帧、DATA 帧就可以了

文章作者: 钱不寒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 钱不寒 !
  目录