作为用户的我们在 "上网冲浪" 的时候总是希望快一点,尤其是抢演唱会门票的时候,但是现实并非如此,有时候我们会遇到页面加载缓慢、响应延迟的情况。
而 http 协议作为互联网世界的基础,从网站打开速度到移动应用的响应时间,http 性能的优化直接关系到我们在网络世界的舒适体验程度。
更快的响应时间和速度能够提供更好的用户体验,不但如此,还可以降低和网络带宽的使用,从而节省相关的成本。
那么今天我们就来聊聊 http 性能如何进行优化。
数据压缩
随着互联网的发展,网路上传输的数据越来越大,随随便便一个文件几个 g 甚至上百 g,就算你是百兆、千兆带宽也扛不住。
如何能够在有限的带宽里传输更多的数据,常见的解决方式是数据压缩。
如果压缩率能有 50%,例如 100k 的数据能够压缩成 50k 的大小,那么就相当于在带宽不变的情况下网速提升了一倍,加速的效果是非常明显的。
使用常见的压缩算法(如 gzip 和 br )对数据进行压缩,不但如此,我们可以对 http 中传输的各种数据进行针对性地压缩,做到【对症下药】。
- html/css/js
对于这类纯文本格式数据,我们在进行压缩时通常会去除其中多余的空格、换行和注释等元素。尽管压缩后的文本可能看起来比较混乱,对人类可读性较差,但这对计算机并不影响流畅阅读。
- jpg/jpeg/png
对于这类图片格式数据,虽然它本身已经被压缩过了,不能被 gzip、br 处理,但仍然有优化的空间。
例如,可以考虑去除图片中的拍摄时间、地点、机型等元数据,适度降低分辨率和缩小尺寸。
此外,尽量采用高压缩率的格式,有损格式可以选择 jpeg,而无损格式则可以考虑使用 webp 格式。
- 小数据
对于较小的数据,http 中有一种被称为 “资源合并”(concatenation)的优化方式,即将多个小资源合并成一个大资源,通过单个请求下载到客户端,随后由客户端使用 javascript、css 等进行拆分使用。
这种方式虽然减少了请求的次数,但是处理起来比较麻烦。
需要注意的是,在数据压缩的时候应当注意选择适当的压缩率,不要追求最高压缩比,否则会耗费服务器的计算资源,增加响应时间,反而会“得不偿失”。
上面讲的都是针对 http 报文里的 body 的压缩方式,对于 header 的压缩在 http/1 里是没有的(http/2 才有)。
不过我们可以采取一些手段来减少 header 的大小,不必要的字段就尽量不发(例如 user-agent、server、x-powered-by)
使用缓存
数据 “千里迢迢” 从服务端到客户端,我们可以把这些 “来之不易” 的数据【暂时保存】起来,以便在下次请求时直接复用,从而避免多次请求带来的高昂成本。
比如说网站上访问量最高的网页、热点新闻,尤其是【读多写少】的数据,把它们缓存下来能够把巨大的流量挡在外面,减轻服务器的压力,对性能的改善是非常显著的。
http 传输的每一个环节基本上都会有缓存,不过大致可以分成:
-
浏览器端缓存
-
服务端缓存
-
中间传输缓存
在浏览器端,通过与服务端协商相关的缓存策略,将一些资源缓存到本地,以便在下次访问时进行复用。
常见的缓存策略包括 http 头中的 cache-control
、expires
以及 etag
等,通过这些标识,浏览器可以判断是否需要从服务端重新获取资源,或者直接使用本地缓存。
在服务端,可以借助专门的缓存中间件,如 memcache 或 redis,将计算得到的中间结果和资源存储在内存或硬盘中。
这样,web 服务器在处理请求时会首先检查缓存,如果找到相应的数据,就能够立即返回给客户端,避免了访问后端服务或数据库的时间开销。
而关于中间传输的缓存,常见的有 http 代理缓存和 cdn(content delivery network,内容分发网络)。
http 代理缓存,通过使用增加了缓存功能的 http 代理服务器(例如 nginx),缓存源服务器的数据,分发给下游的客户端。
而使用 cdn 把源服务器的内容逐级缓存到网络中的每一个 cdn 节点中,这样用户在上网的时候就不直接访问源站,而是访问离它最近的一个 cdn 节点(其实就是缓存了源服务器内容的代理服务器)
使用高性能 web 服务器
除了传输过程中对数据进行压缩和使用缓存,我们还可以在服务端下手。
首先我们应该选择高性能的 web 服务器,最常见的应该就是 nginx 了。
作为一款【高性能,轻量级】的 web 服务器,【进程池 单线程】的工作模式让 nginx 消耗较少的 cpu 和内存,非常轻量,而【i/o 多路复用】又使得 nginx 的工作效率大大提升。
我们还可以通过 nginx 实现【动静分离】:把动态页面和静态页面交给不同的服务器来解析,来加快解析速度,提高请求的访问效率,降低原来单个服务器的压力。
# nginx 动静分离配置
server {
listen 80 ;
location ~* \.(png)$ {
root /var/images/png/;
}
location ~* \.(php)$ {
proxy_pass http://php_back_end;
}
}
不但如此,在配置 nginx 的时候还应该开启 http 长连接。
这样做可以平均握手成本到多次请求中,避免了每个请求都要进行 tcp 连接建立和断开的开销,从而提高了性能。连接的复用使得后续的请求不再需要进行完整的三次握手过程,减少了连接建立的延迟。
升级 http/2
除了上面的【数据压缩】、【使用缓存】、【使用高性能 web 服务器】,http 性能优化还有一个选择,那就是【把协议由 http/1 升级到 http/2】
http/2 基于 google 的 spdy 协议,完全兼容 http/1,我们来看看它的一些优点。
- 头部压缩
报文 header 一般会携带 “user agent”、“cookie”、“accept”、“server” 等许多固定的头字段,多达几百字节甚至上千字节,但 body 却经常只有几十字节(比如 get 请求)
更要命的是,成千上万的请求响应报文里有很多字段值都是重复的,非常浪费,导致大量带宽消耗在了这些冗余度极高的数据上。
为了压缩头部,http/2 开发了专门的 “hpack” 算法:在客户端和服务器两端建立“字典”,用索引号表示重复的字符串,还釆用哈夫曼编码来压缩整数和字符串,可以达到 50%~90% 的高压缩率。
- 二进制格式
相较于 http/1 里纯文本形式的报文,http/2 全面采用二进制格式,既方便计算机解析,而且体积小、速度快,使性能大大提高。
除此之外,http/2 使用虚拟的流(stream)传输消息,解决了“队头阻塞”问题,同时实现了“多路复用”,提高连接的利用率;
今天这篇文章讲了 http 性能优化的一些方法,希望能对你有帮助!