【交代:时间是在距今的 5 年后,由于我的智能滑板鞋,还有智能小内内的创业失败,为了在这个先看胸再看脸的时代活下去,我不得不重操旧业,去面试 web 前端工程师的工作。多年没有接触 web 开发了,找了个 AlloyTeam 的老同事晨伯帮我温习一下知识, 好让面试通过】
“多年没见,你的女神后来什么样了” 晨伯总是这么八卦我的女神,而不是我。
“你先写个小页面给我看看吧,我指导一下你吧。”晨伯一幅很吊的样子。
但是这样的小 case 当然难不了我,虽然多年没碰 web,但是我当年可以是 AlloyTeam 的成员啊。很快我就啪啪啪地完成了页面。晨伯看完我写的页面,一幅 “我可是有女朋友的男人” 的表情,感叹了一句 “现在是 HTTP2.0 的时代啦,给你普及一下知识点”。
HTTP2.0 性能增强的核心:二进制分帧
HTTP 2.0 最大的特点: 不会改动 HTTP 的语义,HTTP 方法、状态码、URI 及首部字段,等等这些核心概念上一如往常,却能致力于突破上一代标准的性能限制,改进传输性能,实现低延迟和高吞吐量。而之所以叫 2.0,是在于新增的二进制分帧层。
既然又要保证 HTTP 的各种动词,方法,首部都不受影响,那就需要在应用层 (HTTP2.0) 和传输层 (TCP or UDP) 之间增加一个二进制分帧层。
在二进制分帧层上, HTTP 2.0 会将所有传输的信息分割为更小的消息和帧, 并对它们采用二进制格式的编码 ,其中 HTTP1.x 的首部信息会被封装到 Headers 帧,而我们的 request body 则封装到 Data 帧里面。
然后,HTTP 2.0 通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。相应地,每个数据流以消息的形式发送,而消息由一或多个帧组成,这些帧可以乱序发送,然后再根据每个帧首部的流标识符重新组装。
“听起来好屌的样子,但是那样,所有的二进制帧都会带上 Headers 帧,这是多大的数据冗余传送啊,性能会多....” 我疑问道。
HTTP2.0 首部压缩
HTTP 2.0 在客户端和服务器端使用 “首部表” 来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送; 通信期间几乎不会改变的通用键-值对 (用户代理、可接受的媒体类型, 等等) 只 需发送一次。事实上, 如果请求中不包含首部 (例如对同一资源的轮询请求), 那么 首部开销就是零字节。此时所有首部都自动使用之前请求发送的首部。
如果首部发生变化了,那么只需要发送变化了数据在 Headers 帧里面,新增或修改的首部帧会被追加到 “首部表”。首部表在 HTTP 2.0 的连接存续期内始终存在, 由客户端和服务器共同渐进地更新 。
“好了,现在你倒是给我解释一下,这里使用自动化合并文件和 Sprite 合图是什么回事?” 晨伯不解
“本质上,当然是为了减少请求啦,通过多个 js 或 css 合并成一个文件,多张小图片拼合成 Sprite 图,可以让多个 HTTP 请求减少为一个,减少额外的协议开销,而提升性能。” 如是道也
“当然,一个 HTTP 的请求的 body 太大也是不合理的,有个度。文件的合并也会牺牲模块化和缓存粒度,可以把 “稳定” 的代码 or 小图 合并为一个文件 or 一张 Sprite,让其充分地缓存起来,从而区分开迭代快的文件” 我不明白晨伯的问题,就稍微补充了一下方案。
所有的 HTTP2.0 的请求都在一个 TCP 链接上
HTTP2.0 所有通信都是在一个 TCP 连接上完成。HTTP 2.0 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应 着逻辑流中的消息。并行地在同一个 TCP 连接上双向交换消息。就好比,我请求一个页面 http://www.qq.com。页面上所有的资源请求都是客户端与服务器上的一条 TCP 上请求和响应的!
有关注 TCP 性能的同学就会知道,HTTP 性能的关键在于低延迟而不是高带宽!大多数 HTTP 连接的时间都很短,而且是突发性的,但 TCP 只在长时间连接传输大块数据时效率才最高。HTTP 2.0 通过让所有数据流共用同一个连接,可以更有效地使用 TCP 连接,让高带宽也能真正的服务于 HTTP 的性能提升。
同时,单链接多资源的方式,使到至上而下的层面都得到了好处:
1. 可以减少服务链接压力, 内存占用少了, 连接吞吐量大了
2. 由于 TCP 连接减少而使网络拥塞状况得以改观;
3. 慢启动时间减少, 拥塞和丢包恢复速度更快。
也就是说,“资源合并减少请求” 的优化手段对于 HTTP2.0 来说是没有效果的,只会增大无用的工作量而已。
他说得好有道理,我竟然掩脸而对(因为脸被打疼了)。
“你在再我说说,这些 cdn1.cn,cdn2.cn,cdn3.cn 是什么回事啊” 晨伯又问到。
“因为 HTTP1.x 上如果一个只用一个持久链接,请求只能一个一个顺序请求,为了高效地并行下载资源,浏览器允许我们打开多个 TCP 会话,但是一个域名下限制 6 个链接。为了突破这些限制,我们可以域名分区,提高并行下载资源能力.....” 我只好把我当年知道的说出来
并行双向字节流的请求和响应
在 HTTP2.0 上,客户端和服务器可以把 HTTP 消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来。注意,同一链接上有多个不同方向的数据流在传输。客户端可以一边乱序发送 stream,也可以一边接收者服务器的响应,而服务器那端同理。
把 HTTP 消息分解为独立的帧, 交错发送, 然后在另一端重新组装是 HTTP 2.0 最 重要的一项增强。事实上, 这个机制会在整个 Web 技术栈中引发一系列连锁反应, 从而带来巨大的性能提升, 因为:
可以并行交错地发送请求, 请求之间互不影响;
可以并行交错地发送响应, 响应之间互不干扰;
只使用一个连接即可并行发送多个请求和响应;
消除不必要的延迟, 从而减少页面加载的时间;
那么也就是说 “域名分区” 这种优化手段对于 HTTP2.0 是无用的,因为资源都是并行交错发送,且没有限制,不需要额外的多域名并行下载。
“既然所有资源都是并行交错发送,会不会出现这样的情况 【浏览器明明在等关键的 CSS 和 JS,你 TMD 的服务器还在发送图片】” 我疑问道。
HTTP2.0 的请求优先级
每个 HTTP2.0 流里面有个优先值,这个优先值确定着客户端和服务器处理不同的流采取不同的优先级策略,高优先级的流都应该优先发送,但又不会绝对的。绝对地准守,可能又会引入首队阻塞的问题:高优先级的请求慢导致阻塞其他资源交付。分配处理资源和客户端与服务器间的带宽,不同优先级的混合也是必须的。
“有了优先级,HTTP2.0 根本不会发生【浏览器明明在等关键的 CSS 和 JS,你 TMD 的服务器还在发送黄图】” 晨伯道。
“我根本没有说是服务器在发黄图,好不好。” 我吐槽了一下。
“还有还有,你这里的一段 base64 内嵌图片又是什么回事?是黄图吗?” 晨伯又挑战我了。
内嵌图片这种,有使用条件的优化手段,我还是不要说话好,不然的话按照这个故事的尿性,他应该又要飞拳我。
HTTP2.0 的服务器推送
HTTP 2.0 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。换句话说,服务器可以强奸你的浏览器,哦不,应该是,除了对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确地请求。
当浏览器请求一个 html,服务器其实大概知道你是接下来要请求资源了,而不需要等待浏览器得到 html 后解析页面再发送资源请求。我们常用的内嵌图片也可以理解为一种强制的服务器推送:我请求 html,却内嵌了张黄图。
有了 HTTP2.0 的服务器推送,HTTP1.x 时代的内嵌资源的优化手段也变得没有意义了。而且使用服务器推送的资源的方式更加高效,因为客户端还可以缓存起来,甚至可以由不同的页面共享(依旧遵循同源策略)。当然,你是个正直的浏览器,是可以决绝服务器推送的黄图的。
不知道为什么,说到黄图这个家伙就兴奋起来了,再也没有打我了。然后交谈就变成了 16+周岁的少女不宜收听的内容了。不过 HTTP2.0 的知识收获了不少。
到了我要面试的日子了,互联网公司 A 果真要(笔试|鄙视)一下我。我写出了下面的页面
在场面试官,纷纷鼓掌站了起来,“如此高效的页面,难得啊~你被录取了!”。
这看着这份如同我前端实习时候写的页面,我心中默默感叹 “十年前端,终归如初”。
出于礼貌,我想起了晨伯教我的新式前端工程师肢体礼仪,然后.....
参考:
aaa 2019 年 2 月 12 日
十年前端,终归如初。
划繁为简。
小胖爽 2018 年 3 月 19 日
写的真心不错, 欢笑中了解了 HTTP 2.0.
vevlins 2018 年 3 月 8 日
写的太好了!
lizzvia 2017 年 4 月 12 日
但是那样,所有的二进制帧都会带上 Headers 帧,这是多大的数据冗余传送啊,性能会多….”
所有的帧结构都一样啊。。。(length+ tye + flags + r + stream id + payload)。
头部压缩是指的 HEADER frame 的 payload 部分,有一个字段是 header block fragment。表示的差异的部分。这一块的内容对帧头字节增加是没有影响的吧。
Mark Zhang 2017 年 1 月 20 日
哈哈,写的有意思
HTTP,HTTP2.0,SPDY,HTTPS你应该知道的一些事 | 2016 年 11 月 11 日
[…] 更多关于 HTTP2 的问题可以参考:HTTP2 奇妙日常,以及 HTTP2.0 的官方网站。 […]
深入研究:http2的真正性能到底如何 – IT知库 2016 年 10 月 21 日
[…] HTTP2.0 的奇妙日常 […]
Milo 2016 年 7 月 22 日
老司机最终又回到菜鸟时代。
一年后 2016 年 6 月 22 日
楼主,你有没有使用过 express 中使用过 http2.0?
麦新杰 2016 年 4 月 3 日
图文并茂,幽默有料,学习了。
zyg 2016 年 3 月 23 日
赞