HTTP2的特性解析

Posted TinyChen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HTTP2的特性解析相关的知识,希望对你有一定的参考价值。


本文主要介绍了HTTP2相对于HTTP1.1的一些改进和新特性。

1、HTTP1.1的不足

HTTP协议采用“request-response”模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器都要新建一个连接,完成之后立即断开连接(HTTP协议为无连接的协议)。对于一个复杂的页面,一般都会有多个资源需要获取。如果是每个资源都单独建立一个TCP连接去获取,每次都需要进行三次握手建立连接来通信,这是十分耗费资源的。

随后出现了Keep-AliveKeep-Alive解决的核心问题是一定时间内,同一域名多次请求数据,只建立一次HTTP请求,其他请求可复用每一次建立的连接通道,以达到提高请求效率的问题。这里面所说的一定时间一般是可以自行配置的。当使用Keep-Alive模式(又称持久连接、连接重用)时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。

HTTP1.1中是默认开启了Keep-Alive,虽然解决了多次连接的问题,但是依然有两个比较严重的问题:

串行传输:在单通道传输的前提下,假设要传输10个文件,那么只能依次逐个传输,传输完第一个再传输第二个,以此类推;连接数问题:HTTP/1.1 虽然默认开启keep-alive可以复用一部分连接,但域名分片等情况下仍然需要建立多个connection,耗费资源,给服务器带来性能压力。

作为 HTTP/1.x 的连接,请求是序列化的,哪怕本来是无序的,在没有足够庞大可用的带宽时,也无从优化。一个解决方案是,浏览器为每个域名建立多个连接,以实现并发请求。曾经默认的连接数量为 2 到 3 个,现在比较常用的并发连接数已经增加到 6 条。如果尝试大于这个数字,就有触发服务器 DoS 保护的风险。如果服务器端想要更快速的响应网站或应用程序的应答,它可以迫使客户端建立更多的连接。例如,不要在同一个域名下获取所有资源,假设有个域名是 www.example.com,我们可以把它拆分成好几个域名:www1.example.comwww2.example.comwww3.example.com。所有这些域名都指向同一台服务器,浏览器会同时为每个域名建立 6 条连接(在我们这个例子中,连接数会达到 18 条)。这一技术被称作域名分片。

HTTP1.1中的数据传输是基于文本来进行传输的,这就需要保证在传输的过程中必须是按照文本原有的顺序进行传输。按照顺序传输的一大弊端就是没办法进行并行传输,例如一句Hello就只能按照字母顺序逐个传输,如果并行传输,字母到达的先后顺序是不一定和在文本中的顺序一样的,而字母本身又没有顺序标号,就没有办法对其进行排序,很有可能就会导致内容错乱,Hello就可能变成leloH

2、HTTP2的特性

2.1 二进制分帧

http2采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。HTTP / 1 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。

流:流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2…N);消息:是指逻辑上的 HTTP 消息,比如请求、响应等,由一或多个帧组成。帧:HTTP 2.0 通信的最小单位,每个帧包含帧首部,至少也会标识出当前帧所属的流,承载着特定类型的数据,如 HTTP 首部、负荷,等等

HTTP/2引入的二进制数据帧的概念,其中帧对数据进行顺序标识,这样浏览器收到数据之后,就可以按照序列对数据进行合并,而不会出现合并后数据错乱的情况。同样是因为有了序列,服务器就可以并行的传输数据,这就是所做的事情。

我们可以从下面的两张图来对其进行了解:

HTTP2的特性解析

多路复用 (multiplexing)

HTTP2的特性解析

在HTTP/2 协议中, Connection 和 Keep-Alive 是被忽略的;主要使用了多路复用来进行连接管理。在 HTTP/2 中,有了二进制分帧之后,HTTP /2 不再依赖 TCP 连接去实现多流并行了,在 HTTP/2 中

同域名下所有通信都在单个连接上完成单个连接可以承载任意数量的双向数据流数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。

这一特性,使性能有了极大提升:

同个域名只需要占用一个 TCP 连接,使用一个连接并行发送多个请求和响应,消除了因多个 TCP 连接而带来的延时和内存消耗并行交错地发送多个请求和响应,两两之间互不影响在 HTTP/2 中,每个请求都可以带一个 31bit 的优先值,0 表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。

HTTP2的特性解析

使用浏览器的开发者模式查看相关资源的加载情况,可以看到对应的http2的资源在加载的时候会使用多路复用,客户端可以同时请求多个资源;而下方的http1.1则在请求资源的时候出现了等待的情况。

HTTP2的特性解析

2.2 首部压缩(header compression)

在同一个HTTP页面中,许多资源的Header是高度相似的,但是在HTTP2之前都是不会对其进行压缩的,这使得在多次传输中白白浪费了资源来进行重复无谓的操作。

在HTTP中,首部字段是一个键值对,所有的首部字段组成首部字段列表。在HTTP/1.x中,首部字段都被表示为字符串,一行一行的首部字段字符串组成首部字段列表。而在HTTP/2的首部压缩HPACK算法中,则有着不同的表示方法。

HPACK算法的具体细节可以参考RFC7541[1]

HPACK算法表示的对象,主要有原始数据类型的整型值和字符串,头部字段,以及头部字段列表。

HTTP2的特性解析

头部压缩需要在支持 HTTP/2 的浏览器和服务端之间:

维护一份相同的静态字典[2](Static Table),包含常见的头部名称,以及特别常见的头部名称与值的组合。其主要作用有两个:对于完全匹配的头部键值对,例如 :method: GET,可以直接使用一个字符表示;对于头部名称可以匹配的键值对,例如 cookie: xxxxxxx,可以将名称cookie使用一个字符表示。维护一份相同的动态字典(Dynamic Table),可以动态地添加内容。对于cookie: xxxxxxx 这样的内容,可以将其添加到动态字典中,之后整个键值对只使用字段中替代的字符来表示即可。需要注意的是,动态字典上下文有关,需要为每个 HTTP/2 连接维护不同的字典。支持基于静态哈夫曼码表的哈夫曼编码(Huffman Coding);

使用字典可以极大地提升压缩效果,其中静态字典在首次请求中就可以使用。对于静态、动态字典中不存在的内容,还可以使用哈夫曼编码来减小体积。HTTP/2 使用了一份静态哈夫曼码表[3],也需要内置在客户端和服务端之中。

下面的表格截取了部分静态字典的内容:

HTTP2的特性解析

2.3 服务器推送(server push)

Server Push 即服务端能通过 push 的方式将客户端需要的内容预先推送过去,也叫“cache push”。这个新特性是有些颠覆了传统的HTTP模式的,因为传统的HTTP模式是客户端请求(request)资源,然后服务器才会返回(response)对应的资源,而Server Push的方式是服务器主动将资源推送到客户端。

HTTP2的特性解析

可以想象以下情况,某些资源客户端是一定会请求的,这时就可以采取服务端 push 的技术,提前给客户端推送必要的资源,这样就可以相对减少一点延迟时间。例如服务端可以主动把 JS 和 CSS 文件推送给客户端,而不需要客户端解析 html 时再发送这些请求。

服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送 RST_STREAM 帧来拒收。实际上服务器应该避免推送已经被客户端缓存了的资源,一般可以通过判断请求中的缓存相关字段来确定是否需要推送。主动推送也遵守同源策略,换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。

还可以使用server push可以提前将需要加载的资源推送到客户端,这样还可以有效提升页面的加载速度:

HTTP2的特性解析

从上面两张图片的对比中我们可以看到一个大小为50KB左右的main.css文件在使用了服务器推送功能之后的加载时间从原来的73.98ms变为19.54ms

3、HTTP2协商机制

由于目前并不是所有的客户端和服务器都支持HTTP2,因此在建立HTTP连接的过程中必然会存在一个协商的过程,具体的协商流程如下:

4、HTTP2的不足

HTTP2在我个人看来在协议的设计方面应该已经是发挥了目前的全部性能,除非有什么惊人的压缩算法之类的出现,否则很难再有极大的改进(实际上HTTP2对比HTTP1.1在实际应用上的性能提升也并不算特别大)。但是由于HTTP协议的传输层还是使用的TCP,这就导致了可能会出现TCP的一些问题。

例如在多路复用的情况下, 一般来说同一域名下只需要使用一个 TCP 连接。但当这个连接中出现了丢包的情况,TCP的特性会需要重新传输,也就是需要把所有的请求都重新传输一次,那就会导致 HTTP/2 的表现情况反倒不如 HTTP/1.1 了。因为在出现丢包的情况下,整个 TCP 都要开始等待重传,也就导致了后面的所有数据都被阻塞了。但是对于 HTTP/1.1 来说,可以开启多个 TCP 连接,出现这种情况反倒只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。这种情况和队头堵塞情况有些类似,但是HTTP2的这种情况一般会出现在网络较差的情况下,也就是说HTTP2会有一种快的更快,慢的更慢的倾向。

Head-Of-Line Blocking(HOLB):导致带宽无法被充分利用,以及后续健康请求被阻塞。HOLB[4] 是指一系列包(package)因为第一个包被阻塞;当页面中需要请求很多资源的时候,HOLB(队头阻塞)会导致在达到最大请求数量时,剩余的资源需要等待其他资源请求完成后才能发起请求。

References

[1] RFC7541: https://tools.ietf.org/html/rfc7541
[2] 静态字典: https://httpwg.org/specs/rfc7541.html#static.table.definition
[3] 静态哈夫曼码表: https://httpwg.github.io/specs/rfc7541.html#huffman.code
[4] HOLB: http://stackoverflow.com/questions/25221954/spdy-head-of-line-blocking


以上是关于HTTP2的特性解析的主要内容,如果未能解决你的问题,请参考以下文章

HTTP2的新特性

HTTP2的新特性

❲拥抱变化❳HTTP2的新特性

HTTP2的新特性

网络HTTP2.0新特性

http2新特性