最近拿到一本新书:《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-Since
,ETag
等头部检查服务端资源更新情况,如果没更新,服务端返回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。
5. HTTP/2 协议
第五章介绍了HTTP/2 协议的一些细节,帧结构、流、流量控制、优先级、服务端推送、首部压缩等内容,内容很多,每一块要理解透彻内容很多,具体还是得看书,外加查询其他资料。
- HTTP/2 简介
- HTTP2简介和基于HTTP2的Web优化 #23
- HTTP/2笔记之帧
- HTTP/2 头部压缩技术介绍
- HTTP/2笔记之流和多路复用
- HTTP2 is here, let's optimize!
- Hypertext Transfer Protocol Version 2 (HTTP/2)
6. HTTP/2 性能
- 并非所有请求在任何情况下都会从HTTP/2 受益;
- 延迟:超过一定带宽之后(实验值是5Mbit/s ),增加带宽不会减少延迟,RTT 对性能的影响更新敏感;
- 丢包:丢包对HTTP/2 影响非常大,因为一个域名就一个连接。
性能优化因人而异
注重测试,要遵循业界推荐的方式,但也不要陷入过早优化的陷阱,应当让数据为你的优化指引方向。