深入理解http2.0协议

http2.0是一种安全高效的下一代http传输协议。安全是因为http2.0建立在https协议的基础上,高效是因为它是通过二进制分帧来进行数据传输。正因为这些特性,http2.0协议也在被越来越多的网站支持。

在发布这篇文章时,本站已全面切换 http2.0

相较与http1/1.1,有以下特点:

  • 对1.x协议语意的完全兼容

  • 性能的大幅提升

优化内容

1. 添加了二进制分祯Binary Frame

http2.0之所以能够突破http1.X标准的性能限制,改进传输性能,实现低延迟和高吞吐量,就是因为其新增了二进制分帧层。

帧(frame)包含部分:类型Type, 长度Length, 标记Flags, 流标识Stream和frame payload有效载荷。

消息(message):一个完整的请求或者响应,比如请求、响应等,由一个或多个 Frame 组成。

流是连接中的一个虚拟信道,可以承载双向消息传输。每个流有唯一整数标识符。为了防止两端流ID冲突,客户端发起的流具有奇数ID,服务器端发起的流具有偶数ID。

流标识是描述二进制frame的格式,使得每个frame能够基于http2发送,与流标识联系的是一个流,每个流是一个逻辑联系,一个独立的双向的frame存在于客户端和服务器端之间的http2连接中。一个http2连接上可包含多个并发打开的流,这个并发流的数量能够由客户端设置。

在二进制分帧层上,http2.0会将所有传输信息分割为更小的消息和帧,并对它们采用二进制格式的编码将其封装,新增的二进制分帧层同时也能够保证http的各种动词,方法,首部都不受影响,兼容上一代http标准。其中,http1.X中的首部信息header封装到Headers帧中,而request body将被封装到Data帧中。

image.png

2. 多路复用 Multiplexing / 连接共享

在http1.1中,浏览器客户端在同一时间,针对同一域名下的请求有一定数量的限制,超过限制数目的请求会被阻塞。这也是为何一些站点会有多个静态资源 CDN 域名的原因之一。

而http2.0中的多路复用优化了这一性能。多路复用允许同时通过单一的http/2 连接发起多重的请求-响应消息。有了新的分帧机制后,http/2 不再依赖多个TCP连接去实现多流并行了。每个数据流都拆分成很多互不依赖的帧,而这些帧可以交错(乱序发送),还可以分优先级,最后再在另一端把它们重新组合起来。

http 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接(每个域名一个连接)即可。http2连接可以承载数十或数百个流的复用,多路复用意味着来自很多流的数据包能够混合在一起通过同样连接传输。当到达终点时,再根据不同帧首部的流标识符重新连接将不同的数据流进行组装。 image.png 上图展示了一个连接上的多个传输数据流:客户端向服务端传输数据帧stream5,同时服务端向客户端乱序发送stream1和stream3。这次连接上有三个响应请求乱序并行交换。 image.png

上图就是http1.X和http2.0在传输数据时的区别。以货物运输为例再现http1.1与http2.0的场景:

http1.1过程:货轮1从A地到B地去取货物,取到货物后,从B地返回,然后货轮2在A返回并卸下货物后才开始再从A地出发取货返回,如此有序往返。

http2.0过程:货轮1、2、3、4、5从A地无序全部出发,取货后返回,然后根据货轮号牌卸载对应货物。

显然,第二种方式运输货物多,河道的利用率高。

3. 头部压缩Header Compression

http1.x的头带有大量信息,而且每次都要重复发送。http/2使用encoder来减少需要传输的header大小,通讯双方各自缓存一份头部字段表,既避免了重复header的传输,又减小了需要传输的大小。

对于相同的数据,不再通过每次请求和响应发送,通信期间几乎不会改变通用键-值对(用户代理、可接受的媒体类型,等等)只需发送一次。

事实上,如果请求中不包含首部(例如对同一资源的轮询请求),那么,首部开销就是零字节,此时所有首部都自动使用之前请求发送的首部。

如果首部发生了变化,则只需将变化的部分加入到header帧中,改变的部分会加入到头部字段表中,首部表在 http 2.0 的连接存续期内始终存在,由客户端和服务器共同渐进地更新。

需要注意的是,http 2.0关注的是首部压缩,而我们常用的gzip等是报文内容(body)的压缩,二者不仅不冲突,且能够一起达到更好的压缩效果。

http/2使用的是专门为首部压缩而设计的HPACK②算法。

image.png

4. 请求优先级Request Priorities

把http消息分为很多独立帧之后,就可以通过优化这些帧的交错和传输顺序进一步优化性能。每个流都可以带有一个31比特的优先值:0 表示最高优先级;2的31次方-1 表示最低优先级。

服务器可以根据流的优先级,控制资源分配(CPU、内存、带宽),而在响应数据准备好之后,优先将最高优先级的帧发送给客户端。高优先级的流都应该优先发送,但又不会绝对的。绝对地准守,可能又会引入首队阻塞的问题:高优先级的请求慢导致阻塞其他资源交付。

分配处理资源和客户端与服务器间的带宽,不同优先级的混合也是必须的。客户端会指定哪个流是最重要的,有一些依赖参数,这样一个流可以依赖另外一个流。优先级别可以在运行时动态改变,当用户滚动页面时,可以告诉浏览器哪个图像是最重要的,你也可以在一组流中进行优先筛选,能够突然抓住重点流。

  • 优先级最高:主要的html
  • 优先级高:CSS文件
  • 优先级中:js文件
  • 优先级低:图片

5. 服务端推送Server Push

服务器可以对一个客户端请求发送多个响应,服务器向客户端推送资源无需客户端明确地请求。并且,服务端推送能把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。

正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。Server Push 让 http1.x 时代使用内嵌资源的优化手段变得没有意义;如果一个请求是由你的主页发起的,服务器很可能会响应主页内容、logo 以及样式表,因为它知道客户端会用到这些东西,这相当于在一个 HTML 文档内集合了所有的资源。

不过与之相比,服务器推送还有一个很大的优势:可以缓存!也让在遵循同源的情况下,不同页面之间可以共享缓存资源成为可能。

image.png

注意两点:

1、推送遵循同源策略;

2、这种服务端的推送是基于客户端的请求响应来确定的。

当服务端需要主动推送某个资源时,便会发送一个 Frame Type 为 PUSH_PROMISE 的 Frame,里面带了 PUSH 需要新建的 Stream ID。意思是告诉客户端:接下来我要用这个 ID 向你发送东西,客户端准备好接着。客户端解析 Frame 时,发现它是一个 PUSH_PROMISE 类型,便会准备接收服务端要推送的流。

WRITTEN BY

lidong

鄂ICP备20003892号Copyright © 2017-2023 leedong.cn

ABOUT ME

Hello,这里是「我的心情永不立冬」
一个想到什么就做什么的个人站点,所有内容纯主观、有偏见