1.首部压缩
1.X版本中,首部用文本格式传输,通常会给每个传输增加500-800字节的开销。现在打开一个网页上百个请求已是常态,而每个请求带的一些首部字段都是相同的,例如cookie、user-agent等。HTTP2为此采用HPACK压缩格式来压缩首部。头部压缩需要在浏览器和服务器端之间:
- 维护一份相同的静态字典,包含常见的头部名称,以及常见的头部名称和值的组合
- 维护一份相同的动态字典,可以动态的添加内容
- 支持基于静态哈夫曼码表的哈夫曼编码(Huffman Coding)
HTTP2静态字典的一部分如下:
静态字典的作用有两个:
1)对于完全匹配的头部键值对,例如 :method: GET
,可以直接使用一个字符表示;
2)对于头部名称可以匹配的键值对,例如 cookie: xxxxxxx
,可以将名称使用一个字符表示。
比方说我们要传:method: GET,可以直接传一个字符2。同时,浏览器可以告知服务端,将 cookie: xxxxxxx
添加到动态字典中,这样后续整个键值对就可以使用一个字符表示了。类似的,服务端也可以更新对方的动态字典。需要注意的是,动态字典上下文有关,需要为每个 HTTP/2 连接维护不同的字典。
使用字典可以极大地提升压缩效果,其中静态字典在首次请求中就可以使用。对于静态、动态字典中不存在的内容,还可以使用哈夫曼编码来减小体积。
2.二进制分帧层
帧:HTTP/2数据通信的最小单位。
消息:指HTTP/2中逻辑上的HTTP消息。例如请求和响应等,消息由一个或多个帧组成。
流:已建立的TCP连接上的双向字节流,可以承载一个或多个消息,每个流都有一个唯一的整数ID。一个流代表一次完整的请求-响应过程。
流具有有序性和双向性
- 有序性:帧(frames)在流上的发送顺序很重要. 接收方将按照他们的接收顺序处理这些frame. 特别是HEADERS和DATA frame的顺序, 在协议的语义上显得尤为重要.
- 双向性:同一个流内,可同时发送和接受数据;
HTTP/2在其应用层(HTTP/2)与传输层(tcp/udp)之间加了一个二进制分帧层
在二进制分帧层 HTTP2会将所有的传输信息分割为更小的消息和帧,并对他们采用二进制的编码。
3.多路复用
HTTP协议的初始版本中,每进行一次HTTP通信就要断开一次TCP连接。
我们知道,现在打开一个网站,需要发送几百个请求都是常有的事,如果每一个请求都要经历一次 建立TCP连接-断开TCP连接,那么通信量会非常大。
在HTTP/1.1 和一部分的HTTP/1.0提出了持久连接的方法(Keep-Alive)。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持TCP连接状态。这样,只需要建立一次TCP连接,就可以进行多次请求-响应的交互。
但是Keep-Alive还是存在很多问题
1) 串行的文件传输。当请求a文件时,b文件只能等待,等待a连接到服务器、服务器处理文件、服务器返回文件,这三个步骤。我们假设这三步用时都是1秒,那么a文件用时为3秒,b文件传输完成用时为6秒,依此类推。(注:此项计算有一个前提条件,就是浏览器和服务器是单通道传输)
2) 连接数过多。我们假设Apache
设置了最大并发数为300,因为浏览器限制,浏览器发起的最大请求数为6,也就是服务器能承载的最高并发为50,当第51个人访问时,就需要等待前面某个请求处理完成。
为了解决这些问题,HTTP/2提出了多路复用
1)HTTP/1.x中数据传输是文本格式,所有数据都必须按顺序传输,不能并行传输。但在HTTP/2中,由于二进制分帧层的存在,可以进行并行传输。HTTP2建立一个TCP连接,一个连接上面可以有任意多个流,消息分割成一个或多个帧在流里面传输。帧传输过去以后,再进行重组(帧对数据进行顺序标识),形成一个完整的请求或响应。这使得所有的请求或响应都无法阻塞。
2)HTTP/2
对同一域名下所有请求都是基于流
,也就是说同一域名不管访问多少文件,也只建立一路连接。同样Apache
的最大连接数为300,因为有了这个新特性,最大的并发就可以提升到300,比原来提升了6倍!
总结一下HTTP/2多路复用
a.同域名下的所有通信都在单个连接上完成。(不管多少个文件)
b.单个连接可以承载任意数量的双向数据流。
c.数据流以消息的形式发送,消息由一个或多个帧组成,多个帧可以乱序发送然后再重组。
以前我们做的性能优化不适用于HTTP/2
了
- JS文件的合并。我们现在优化的一个主要方向就是尽量的减少HTTP的请求数, 对我们工程中的代码,研发时分模块开发,上线时我们会把所有的代码进行压缩合并,合并成一个文件,这样不管多少模块,都请求一个文件,减少了HTTP的请求数。但是这样做有一个非常严重的问题:文件的缓存。当我们有100个模块时,有一个模块改了东西,按照之前的方式,整个文件浏览器都需要重新下载,不能被缓存。现在我们有了
HTTP/2
了,模块就可以单独的压缩上线,而不影响其他没有修改的模块。 - 多域名提高浏览器的下载速度。之前我们有一个优化就是把css文件和js文件放到2个域名下面,这样浏览器就可以对这两个类型的文件进行同时下载,避免了浏览器6个通道的限制,这样做的缺点也是明显的,1.DNS的解析时间会变长。2.增加了服务器的压力。有了
HTTP/2
之后,根据上面讲的原理,我们就不用这么搞了,成本会更低。
4.Server Push
服务端能够更快的把资源推送给客户端。例如服务端可以主动把 JS 和 CSS 文件推送给客户端,而不需要客户端解析 HTML 再发送这些请求。当客户端需要的时候,它已经在客户端了。
比如,客户端请求index.html,服务器端能够额外推送script.js和style.css。 实现原理就是客户端发出页面请求时,服务器端能够分析这个页面所依赖的其他资源,主动推送到客户端的缓存,当客户端收到原始网页的请求时,它需要的资源已经位于缓存。
参考链接:
https://juejin.im/post/5c0ce870f265da61171c8c66