fangpsh's blog

《HTTP/2 基础教程》读书笔记

http2

最近拿到一本新书:《HTTP/2 基础教程》,薄薄一本,除去附录100页不到,卖的挺贵,49元。《精通正则表达式》的译者余晟为这书写了序,也在他的个人公众号上推荐,读完却觉得作为基础教程还不错,翻译上觉得略生硬。作点简单的笔记,方便以后“按图索骥”。

3.1.2 关键性能指标

  • 延迟
    • 延迟是制约Web 性能的主要瓶颈,后文还会提到,丢包会严重影响HTTP/2 的性能
    • 这就是为什么CDN 的边缘节点要近可能的靠近目标用户,做到本地覆盖。
  • 带宽
    • 带宽可能会成为性能的瓶颈,不过对于普通的网页,目前大多数用户的带宽已经不是瓶颈,延时和丢包更加重要
  • DNS 查询
    • 网址的域名解析,网页内各项资源的域名解析时间,这块查询时间占比较大,特别是在移动端。
  • 建立连接的时间
    • TCP 三次握手
  • TLS 协商时间
    • 采用HTTPS 之后,TLS 握手,TLS 1.2 需要消耗2个RTT,不过新的TLS1.3 只需要1个RTT。
    • 针对TLS 有非常多的优化手段,建议阅读《Web 性能权威指南》
  • 首字节时间(TTFB)
    • 客户端开始访问网页,到收到服务器响应的第一个字节的时长。
  • 内容下载时间
    • 从客户端开始访问,到最后一个响应字节到达客户端的时长。
  • 开始渲染时间
    • 用户看到空白页面的时长。
  • 文档加载完成时间(又叫页面加载时间)
    • 浏览器认为页面加载完毕的时长。

互联网发展,遇到的挑战:

  • 更多的字节:页面资源的体积变大
  • 更多的资源:页面资源数量变多
  • 更高的复杂度: 页面越来越复杂,渲染变长
  • 更多的域名: 一个页面包含的域名越来越多,增加了DNS 查询耗时、建立连接耗时、TLS 协商耗时。
  • 更多的TCP socket:浏览器会对同一个域名开启多个连接,这增加了服务器协商耗时,加重设备负担,有可能导致网络过载等问题。

3.1.3 HTTP/1 的问题

  • 队头堵塞
    • HTTP/1 有个特性叫管道化(pipelining),允许一次发送一组请求,当时只能按照发送顺序依次接收请求,
    • 在应答过程中,如果有一个请求阻塞了,后续所有工作都会被阻塞。现代浏览器会对单个域名开启6个连接,当时每个连接还是会受到“队头阻塞”的影响。
  • 低效的TCP 利用
    • 拥塞控制算法,慢启动,以及拥塞避免,TCP 并不高效。
  • 臃肿的消息首部
    • HTTP/1 消息头部无法被压缩,如果再带上cookies,有个几千字节很常见。大量请求下,消息头的占比不可忽视。
  • 受限的优先级设置
    • 处理高优先级的资源时,不会对低优先级的资源发起请求。
  • 第三方资源
    • 日益增多的第三方资源引用,消耗了大量资源。HTTP/2 对此也束手无策。

3.2.1 Web 性能的最佳实践

1. DNS 查询优化

  • 限制不同域名的数量。
  • 保证低限度的解析延迟,定期监控用户分布所有地区的解析时间。
  • 在主体页面HTML 活响应中利用DNS 预取命令。 例: <link rel="dns-prefetch" hrefp="//ajax.googleapis.com">

2. 优化TCP 连接

  • 利用preconnect 指令。 例: <link rel="preconnect" href="//fonts.example.com" crossorigin>
  • 尽早终止并响应,借助CDN,降低RTT,尽快响应。
  • 实施最新的TLS 最佳实践来优化HTTPS。

3. 避免重定向

重定向通常会触发与额外域名建立连接,简单的解决方案就是彻底消灭重定向。

  • 利用CDN 代替客户端在云端实现重定向,意思就是让CDN 重定向去取回资源再返回给客户端。
  • 如果是同一域名的重定向,利用Web 服务器上的rewrite 规则,避免重定向。例如Nginx、Apache 里面的rewrite,客户端无需再发起一次请求。

4. 客户端缓存

客户端直接使用本地缓存是最快的。建议所有的静态资源名称都带上一个随机的ID,然后给一个超长的缓存时间即可。部分需要更新的资源,可以按需调整缓存时间。

5. 网络边缘的缓存

利用CDN,缓存部分数据。如果一份资源需要缓存,它必须满足:

  • 在多用户间可共享,并且
  • 能够接受一定程度的旧数据

用户的隐私信息、以及贵时间敏感的内容都不可以缓存。

6. 条件缓存

使用Last-Modified-SinceETag 等头部检查服务端资源更新情况,如果没更新,服务端返回304,否则返回新的资源。

7. 压缩和代码极简化

去除前端代码里面多余的注释、空格、换行,牺牲可读性降低体积,再通过gzip、deflate、Brotli等算法压缩传输。

8. 避免阻塞CSS/JS

CSS 要放在head 标签里,在任何JS 和图片前面。

  • 定期校验JS 资源的使用情况,清楚不再需要的资源。
  • 如果JS 执行顺序无关紧要,并且必须在onload 事件触发之前运行,可以设置async 属性, 例:
 < script async src="/js/myfile.js">
  • 如果JS 执行顺序很重要,并且也能接受脚本在DOM 加载完之后运行,可以使用defer 属性, 例:
 <script defer src="/js/myjs.js">
  • 对于不行影响到页面初次展示的JS脚本,必须在onload 事件触发之后请求(处理)它。

9. 图片优化

图片越来越多,针对图片的2条优化建议:

  • 删除图片元信息,例如题材、地理信息、时间戳、尺寸和像素信息等。
  • 针对不同设备提供不同尺寸的图片,另外例如七牛、又拍云等CDN 厂商都提供图片处理服务,使用起来简单快捷。

关于图片优化可以阅读书籍:《High Performance Images》

之前也整理过一篇:[[../2017/170608 图片优化笔记]]。

3.2.2 反模式

4.3 撤销针对HTTP/1.1 的优化

6.7 HTTP/2 反模式

一些在HTTP/1.X 上使用的优化手段,若应用到HTTP/2 上,会适得其反,书里有三个地方都提到了“反模式”:

  • 生成精灵图和资源合并/内联:对于HTTP/2 来说,使用精灵图没有意义。也不要将资源进行合并,缓存控制上会不方便,粒度太粗。
  • 域名拆分:迁移到HTTP/2 需要收拢域名。
  • 禁用cookie的域名:HTTP/2 中,头部信息会被压缩,无需再对特定域名禁用cookie。

null

5. HTTP/2 协议

第五章介绍了HTTP/2 协议的一些细节,帧结构、流、流量控制、优先级、服务端推送、首部压缩等内容,内容很多,每一块要理解透彻内容很多,具体还是得看书,外加查询其他资料。

6. HTTP/2 性能

  • 并非所有请求在任何情况下都会从HTTP/2 受益;
  • 延迟:超过一定带宽之后(实验值是5Mbit/s ),增加带宽不会减少延迟,RTT 对性能的影响更新敏感;
  • 丢包:丢包对HTTP/2 影响非常大,因为一个域名就一个连接。

性能优化因人而异

注重测试,要遵循业界推荐的方式,但也不要陷入过早优化的陷阱,应当让数据为你的优化指引方向。

8. HTTP/2 调试

  • Chrome 开发者工具
    • chrome://net-internals
    • Inspect -> Network
  • Firefox 开发者工具
  • iOS:Charles Proxy
  • Android:手机端-开发者模式-USB调试(USB debugging),PC-Chrome-开发者工具-Remote devices
  • WebPagetest
  • OpenSSL
  • nghttp
  • curl -v --http2
  • h2i
  • Wireshark