HTTP2牛逼在哪儿?

一、HTTP1.1的高延迟性能问题

  • HTTP头部巨大且重复
  • 对头阻塞问题
  • 不支持服务器推送消息
  • 并发连接有限

二、HTTP2的针对HTTP1.1的优化

兼容老版本

  • HTTP没有在URI里引入新的协议名,仍然用http://表示明文协议,用https://表示加密协议, 于是只需要浏览器和服务器在背后自动升级协议,这样可以让用户意识不到协议的升级,很好的实现了协议的平滑升级。
  • 只在应用层做了改变,还是基于 TCP 协议传输,应用层方面为了保持功能上的兼容,HTTP2把HTTP分解成了语义和语法两个部分,语义层不做改动,与 HTTP1.1 完全⼀致,比如请求方法、状态码、头字段等规则保留不变。 但是,HTTP/2 在语法层面做了很多改造,基本改变了 HTTP 报文的传输格式。

头部压缩

HTTP1.1存在的问题

  • 存在很多固定字段,比如Cookie、Accept等,加起来占的字节高达几百到几千,有必要进行压缩。
  • 大量的请求和报文里很多字段都是重复的,有必要避免重复性。
  • 字段是ASCII编码的,虽然易于观察,但不适合传输,有必要改成二进制编码。

HTTP2没有使用常见的gzip,而是开发了HPACK算法

  • 静态字典
  • 动态字典
  • Huffman编码(压缩算法)

客户端和服务器两端都会建立和维护字典,用长度较小的索引号表示重复的字符串,再用Huffman 编码压缩数据,可达到 50%~90% 的高压缩率。

静态表编码
概述

HTTP2为高频出现在头部的字符串和字段建⽴了⼀张静态表,它是写入到 HTTP2框架里的,不会变化的,静态表里共有61组。

过程

例如,server头部字段的Index为 54,⼆进制为110110,再加上固定01,头部格式第1个字节就是 01110110,第二个字节的首个比特位表示Value是否经过 Huffman编码,剩余的 7 位表示Value的长度,10000110,首位为1,表示 Value字符串是经过Huffman编码的,经过Huffman编码的Value长度为6。

动态表编码
概述

静态表只包含了 61 种⾼频出现在头部的字符串,不在静态表范围内的头部字符串就要自行构建动态表,它的Index从62起步,会在编码解码的时候随时更新。

过程

例如,第⼀次发送时头部中的user-agent字段数据有上百个字节,经过 Huffman 编码发送出去后,客户端和服务器双方都会更新自己的动态表,添加⼀个新的Index号62。那么在下⼀次发送的时候,就不用重复发这个字段的数据了,只用发 1 个字节的 Index号就好了,因为双方都可以根据自己的动态表获取到字段的数据。

使用前提

使用动态表的前提是:必须同⼀个连接上,重复传输完全相同的 HTTP 头部。如果消息字段在 1 个连接上只发送了1次,或者重复传输时,字段总是略有变化,动态表就无法被充分利用了。

不足

动态表越大,占用的内存也就越大,如果占用了太多内存,是会影响服务器性能的,因此Web服务器都会提供类似 http2_max_requests 的配置,用于限制⼀个连接上能够传输的请求数量,避免动态表无限增大,请求数量到达上限后,就会关闭 HTTP/2 连接来释放内存。

二进制帧

HTTP/2 把响应报文划分成了两个帧(首部,消息负载)传输,并采用二进制来编码。
首部

  • 前3个字节:代表数据帧的长度
  • 第4个字节:表示帧的类型(共有10种,一般分为数据帧和控制帧)
  • 第5个字节:标志位,用于携带简单的控制信息
    • END_HEADERS 表示头数据结束标志
    • END_STREAM 表示单方向数据发送结束,后续不会再有数据帧
    • PRIORITY 表示流的优先级
  • 最后4个字节:流标识符(StreamID),但最高位被保留不用,只有 31 位可以使用,它的作用是用来标识该 Fream 属于哪个Stream,接收方可以根据这个信息从乱序的帧里找到相同StreamID的帧,从而有序组装信息。

消息负载

  • HPACK算法压缩过的HTTP头部
  • HPACK算法压缩过的 HTTP包体
    HTTP2二进制帧结构
    在这里插入图片描述

并发传输

Steam、Message、Frame之间的关系

  • 1个TCP连接包含⼀个或者多个Stream
  • Stream里可以包含1个或多个Message,Message对应 HTTP1中的请求或响应,由HTTP 头部和包体构成
  • Message里包含⼀条或者多个Frame,Frame 是 HTTP/2最小单位,以⼆进制压缩格式存放HTTP/1中的内容(头部和包体)
  • HTTP消息可以由多个Frame构成,以及1个Frame可以由多个TCP报文构成

StreamID

  • 不同 Stream的帧是可以乱序发送的(因此可以并发不同的 Stream ),因为每个帧的头部会携带Stream ID信息,所以接收端可以通过Stream ID有序组装成HTTP消息,而同一Stream内部的帧必须是严格有序的。
  • 客户端建立的 Stream ID必须是奇数号,而服务器建立的Stream必须是偶数号。
  • 同⼀个连接中的 Stream ID是不能复⽤的,只能顺序递增,所以当 Stream ID 耗尽时,需要发⼀个控制帧 GOAWAY ,用来关闭 TCP 连接。 在 Nginx 中,可以通过http2_max_concurrent_streams 配置来设置 Stream 的上限,默认是 128 个

Stream优先级

HTTP/2还可以对每个Stream 设置不同优先级,帧头中的标志位可以设置优先级。
在这里插入图片描述

服务器主动推送资源

客户端发起的请求,必须使⽤的是奇数号Stream,服务器主动的推送,使用的是偶数号 Stream。服务器在推送资源时,会通过PUSH_PROMISE帧传输 HTTP 头部,并通过帧中的Promised Stream ID字段告知客户端,接下来会在哪个偶数号Stream 中发送包体。
在Stream 1中通知客户端CSS 资源即将到来,然后在Stream2中发送 CSS 资源,注意 Stream1和2是可以并发的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值