作为用户的我们在 "上网冲浪" 的时候总是希望快一点,尤其是抢演唱会门票的时候,但是现实并非如此,有时候我们会遇到页面加载缓慢、响应延迟的情况。
而 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 性能优化的一些方法,希望能对你有帮助!