无论你在做前端、后端还是运维,HTTP都是不得不打交道的网络协议。它是最常用的应用层协议,对它的优化,既能通过降低时延带来更好的体验性,也能通过降低资源消耗带来更高的并发性。
可是,学习HTTP不久的同学,很难全面说出HTTP的所有优化点。这既有可能是你没好好准备过大厂的面试,也有可能你没有加入一个快速发展的项目,当产品的用户量不断翻番时,需求会倒逼着你优化HTTP协议。
这篇文章是根据我在2019年GOPS全球运维大会上海站的演讲PPT,重新提炼文字后的总结。我希望能从四个全新的维度,带你覆盖绝大部分的HTTP优化技巧。这样,即使还不需要极致方法去解决当前的性能瓶颈,也会知道优化方向在哪,当需求来临时,能够到Google上定向查阅资料。
第一个维度,是从编码效率上,更快速地把消息转换成更短的字符流。这是最直接的性能优化点。
编码效率优化
如果你对HTTP/1.1协议做过抓包分析,就会发现它是用“whitespace-delimited”方式编码的。用空格、回车来编码,是因为HTTP在诞生之初追求可读性,这样更有利于它的推广。
然而在当下,这种低效的编码方式已经严重影响性能了,所以2009年Google推出了基于二进制的SPDY协议,大幅提升了编码效率。2015年,稍做改进后它被确定为HTTP/2协议,现在50%以上的站点都在使用它。
这是编码优化的大方向,包括即将推出的HTTP/3。
然而这些新技术到底是怎样提升性能的呢?那还得拆开了看,先从数据的压缩谈起。你抓包看到的是数据,它并不等于信息。数据其实是信息和冗余数据之和,而压缩技术,就是尽量地去除冗余数据。
压缩分为无损压缩和有损压缩。针对图片、音视频,我们每天都在与有损压缩打交道。比如,当浏览器只需要缩略图时,就没有必要浪费带宽传输高清图片。而高清视频做过有损压缩后,在肉眼无法分清时,已经被压缩了上千倍。这是因为,声音、视频都可以做增量压缩。
还记得曾经的VCD吗?当光盘有划痕时,整张盘都无法播放,就是因为那时的视频做了增量压缩,而且关键帧太少,导致关键帧损坏时,后面的增量帧全部无法播放了。
再来看无损压缩,你肯定用过gzip,它让http body实现了无损压缩。肉眼阅读压缩后的报文全是乱码,但接收端解压后,可以看到发送端的原文。然而,gzip的效率其实并不高,以Google推出的brotli做对比,你就知道它的缺陷了:
评价压缩算法时,我们重点看两个指标:压缩率和压缩速度。上图中可以看到,无论用gzip 9个压缩级别中的哪一个,它的压缩率都低于brotli(相比gzip,压缩级别它还可以配置为10),压缩速度也更慢。所以,如果可以,应该尽快更新你的gzip压缩算法了。
内容协商
在介绍 Brotli 之前,先说一下 HTTP 内容协商
同一个 URL有时可以提供不同格式的页面,有存文本的、有压缩的,压缩也有不同算法的,这就要求服务端和客户端之间有一个选择最合适版本的机制,这就是内容协商。
HTTP 的内容协商的其中一种方式:服务端根据客户端发送的请求头中某些字段自动发送最合适的版本。
可以用于这个机制的请求头字段又分两种:内容协商专用字段(Accept 字段)、其他字段。
字段情况,详见下表:
请求头字段 | 说明 | 响应头字段 |
Accept | 告知服务器可以发送何种媒体类型 | Content-Type |
Accept-Language | 告知服务器可以发送何种语言 | Content-Language |
Accept-Charset | 告知服务器可以发送何种字符集 | Content-Type |
Accept-Encoding | 告知服务器可以采用何种压缩方式 | Content-Encoding |
例如客户端发送以下请求头:
1 | Accept-Encoding:gzip,deflate,br |
表示支持采用 gzip、deflate 或 br 压缩过的资源
浏览器的响应头可能是这样的:
1 | Content-Encoding: gzip |
如果你的服务器支持br压缩会反回:
什么是 Brotli
在web应用中,为了节省流量,降低传输数据大小,提高传输效率,常用的压缩方式一般都是gzip,今天我们来介绍另外一种更高效的压缩方式brotli。
Brotli 是 google 开发的文本压缩算法,比起gzip可能会有高达37%的提升。主流浏览器都支持br算法,强烈大家升级改算法。使用算法的前提是启用了 https(它仅适用于 HTTPS),因为 http 请求中 request header 里的 Accept-Encoding: gzip, deflate 是没有 br 的。
Brotli is a generic-purpose lossless compression algorithm that compresses data using a combination of a modern variant of the LZ77 algorithm, Huffman coding and 2nd order context modeling, with a compression ratio comparable to the best currently available general-purpose compression methods. It is similar in speed with deflate but offers more dense compression.
Brotli 是基于LZ77算法的一个现代变体、霍夫曼编码和二阶上下文建模。Google软件工程师在2015年9月发布了包含通用无损数据压缩的Brotli增强版本,特别侧重于HTTP压缩。其中的编码器被部分改写以提高压缩比,编码器和解码器都提高了速度,流式API已被改进,增加更多压缩质量级别。
与常见的通用压缩算法不同,Brotli使用一个预定义的120千字节字典。该字典包含超过13000个常用单词、短语和其他子字符串,这些来自一个文本和HTML文档的大型语料库。预定义的算法可以提升较小文件的压缩密度。
使用Brotli替换Deflate来对文本文件压缩通常可以增加20%的压缩密度,而压缩与解压缩速度则大致不变。Brotli 压缩只能在https中生效,因为 在 http 请求中 request header 里的 Accept-Encoding: gzip, deflate 是没有 br 的。
浏览器对brotli协议的支持
- Mozilla Firefox在Firefox 44中实现Brotli。
- Google Chrome从Chrome 49开始支持Brotli。
- Opera从Opera 36开始支持Brotli。
各种压缩算法的在不同level下的比较
Brotli压缩算法应用在HTTP请求流程
- 用户访问支持Brotli压缩的HTTP服务器上的网站或者Web应用
- 浏览器通过使用Accept-Encoding标头通知HTTP服务器它支持解压缩的内容类型
- HTTP服务器根据请求中包含的压缩算法决定要哪种压缩内容
- 服务器通过返回头部Content-Encoding向浏览器端表明数据的压缩方式
- 浏览器将数据解压并展示在页面上
安装与配置
本教程是在原来已安装nginx,但没有编译br模块的前提下,增加br模块,开始前需要先关闭nginx服务。
安装ngx_brotli
获取编译参数Nginx Arguments
整理新的Arguments
根据获取到的configure arguments和上面软件的位置,重新整理configure arguments
然后再加上 --add-module=/usr/local/src/ngx_brotli
找到Nginx的全局配置文件
例如:Brotli和gzip是可以并存的,无需关闭gzip。
检测配置是否正常
检查br是否生效
curl检测gzip编码
curl检测br编码
或者使用浏览器工具:
检查 > Network > Headers > "Response Headers" > "Content-Encoding" header,发现有content-encoding:br
高级应用:
gzip和br可以同时生效,意味着我们可以对基于 Node.js 等会在后台自动 Gzip 的站点,设置优先使用 brotli,所以在网站反代配置里加上如下配置,告知后端:前端不接受 Gzip 编码。
在反向代理配置文件代码中添加:
例如: