You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 40 | HTTP性能优化面面观
今天我们继续上次的话题看看HTTP性能优化有哪些行之有效的手段。
上一讲里我说到了在整个HTTP系统里有三个可优化的环节分别是**服务器**、**客户端**和**传输链路**“第一公里”和“中间一公里”。但因为我们是无法完全控制客户端的所以实际上的优化工作通常是在服务器端。这里又可以细分为后端和前端后端是指网站的后台服务而前端就是HTML、CSS、图片等展现在客户端的代码和数据。
知道了大致的方向HTTP性能优化具体应该怎么做呢
总的来说,任何计算机系统的优化都可以分成这么几类:硬件软件、内部外部、花钱不花钱。
**投资购买现成的硬件**最简单的优化方式比如换上更强的CPU、更快的网卡、更大的带宽、更多的服务器效果也会“立竿见影”直接提升网站的服务能力也就实现了HTTP优化。
另外,**花钱购买外部的软件或者服务**也是一种行之有效的优化方式最“物有所值”的应该算是CDN了参见[第37讲](https://time.geekbang.org/column/article/120664)。CDN专注于网络内容交付帮助网站解决“中间一公里”的问题还有很多其他非常专业的优化功能。把网站交给CDN运营就好像是“让网站坐上了喷气飞机”能够直达用户几乎不需要费什么力气就能够达成很好的优化效果。
不过这些“花钱”的手段实在是太没有“技术含量”了,属于“懒人”(无贬义)的做法,所以我就不再细说,接下来重点就讲讲在网站内部、“不花钱”的软件优化。
我把这方面的HTTP性能优化概括为三个关键词**开源**、**节流**、**缓存**。
## 开源
这个“开源”可不是Open Source而是指抓“源头”开发网站服务器自身的潜力在现有条件不变的情况下尽量挖掘出更多的服务能力。
首先我们应该选用高性能的Web服务器最佳选择当然就是Nginx/OpenResty了尽量不要选择基于Java、Python、Ruby的其他服务器它们用来做后面的业务逻辑服务器更好。利用Nginx强大的反向代理能力实现“动静分离”动态页面交给Tomcat、Django、Rails图片、样式表等静态资源交给Nginx。
Nginx或者OpenResty自身也有很多配置参数可以用来进一步调优举几个例子比如说禁用负载均衡锁、增大连接池绑定CPU等等相关的资料有很多。
特别要说的是对于HTTP协议一定要**启用长连接**。在[第39讲](https://time.geekbang.org/column/article/126374)里你也看到了TCP和SSL建立新连接的成本是非常高的有可能会占到客户端总延迟的一半以上。长连接虽然不能优化连接握手但可以把成本“均摊”到多次请求里这样只有第一次请求会有延迟之后的请求就不会有连接延迟总体的延迟也就降低了。
另外在现代操作系统上都已经支持TCP的新特性“**TCP Fast Open**”Win10、iOS9、Linux 4.1它的效果类似TLS的“False Start”可以在初次握手的时候就传输数据也就是0-RTT所以我们应该尽可能在操作系统和Nginx里开启这个特性减少外网和内网里的握手延迟。
下面给出一个简短的Nginx配置示例启用了长连接等优化参数实现了动静分离。
```
server {
listen 80 deferred reuseport backlog=4096 fastopen=1024;
keepalive_timeout 60;
keepalive_requests 10000;
location ~* \.(png)$ {
root /var/images/png/;
}
location ~* \.(php)$ {
proxy_pass http://php_back_end;
}
}
```
## 节流
“节流”是指减少客户端和服务器之间收发的数据量,在有限的带宽里传输更多的内容。
“节流”最基本的做法就是使用HTTP协议内置的“数据压缩”编码不仅可以选择标准的gzip还可以积极尝试新的压缩算法br它有更好的压缩效果。
不过在数据压缩的时候应当注意选择适当的压缩率,不要追求最高压缩比,否则会耗费服务器的计算资源,增加响应时间,降低服务能力,反而会“得不偿失”。
gzip和br是通用的压缩算法对于HTTP协议传输的各种格式数据我们还可以有针对性地采用特殊的压缩方式。
HTML/CSS/JavaScript属于纯文本就可以采用特殊的“压缩”去掉源码里多余的空格、换行、注释等元素。这样“压缩”之后的文本虽然看起来很混乱对“人类”不友好但计算机仍然能够毫无障碍地阅读不影响浏览器上的运行效果。
图片在HTTP传输里占有非常高的比例虽然它本身已经被压缩过了不能被gzip、br处理但仍然有优化的空间。比如说去除图片里的拍摄时间、地点、机型等元数据适当降低分辨率缩小尺寸。图片的格式也很关键尽量选择高压缩率的格式有损格式应该用JPEG无损格式应该用Webp格式。
对于小文本或者小图片还有一种叫做“资源合并”Concatenation的优化方式就是把许多小资源合并成一个大资源用一个请求全下载到客户端然后客户端再用JavaScript、CSS切分后使用好处是节省了请求次数但缺点是处理比较麻烦。
刚才说的几种数据压缩针对的都是HTTP报文里的body在HTTP/1里没有办法可以压缩header但我们也可以采取一些手段来减少header的大小不必要的字段就尽量不发例如Server、X-Powered-By
网站经常会使用Cookie来记录用户的数据浏览器访问网站时每次都会带上Cookie冗余度很高。所以应当少使用Cookie减少Cookie记录的数据量总使用domain和path属性限定Cookie的作用域尽可能减少Cookie的传输。如果客户端是现代浏览器还可以使用HTML5里定义的Web Local Storage避免使用Cookie。
压缩之外,“节流”还有两个优化点,就是**域名**和**重定向**。
DNS解析域名会耗费不少的时间如果网站拥有多个域名那么域名解析获取IP地址就是一个不小的成本所以应当适当“收缩”域名限制在两三个左右减少解析完整域名所需的时间让客户端尽快从系统缓存里获取解析结果。
重定向引发的客户端延迟也很高它不仅增加了一次请求往返还有可能导致新域名的DNS解析是HTTP前端性能优化的“大忌”。除非必要应当尽量不使用重定向或者使用Web服务器的“内部重定向”。
## 缓存
在[第20讲](https://time.geekbang.org/column/article/106804)里我就说到了“缓存”它不仅是HTTP也是任何计算机系统性能优化的“法宝”把它和上面的“开源”“节流”搭配起来应用于传输链路就能够让HTTP的性能再上一个台阶。
在“第零公里”也就是网站系统内部可以使用Memcache、Redis、Varnish等专门的缓存服务把计算的中间结果和资源存储在内存或者硬盘里Web服务器首先检查缓存系统如果有数据就立即返回给客户端省去了访问后台服务的时间。
在“中间一公里”缓存更是性能优化的重要手段CDN的网络加速功能就是建立在缓存的基础之上的可以这么说如果没有缓存那就没有CDN。
利用好缓存功能的关键是理解它的工作原理(参见[第20讲](https://time.geekbang.org/column/article/106804)和[第22讲](https://time.geekbang.org/column/article/108313)为每个资源都添加ETag和Last-modified字段再用Cache-Control、Expires设置好缓存控制属性。
其中最基本的是max-age有效期标记资源可缓存的时间。对于图片、CSS等静态资源可以设置较长的时间比如一天或者一个月对于动态资源除非是实时性非常高也可以设置一个较短的时间比如1秒或者5秒。
这样一旦资源到达客户端,就会被缓存起来,在有效期内都不会再向服务器发送请求,也就是:“**没有请求的请求,才是最快的请求。**”
## HTTP/2
在“开源”“节流”和“缓存”这三大策略之外HTTP性能优化还有一个选择那就是把协议由HTTP/1升级到HTTP/2。
通过“飞翔篇”的学习你已经知道了HTTP/2的很多优点它消除了应用层的队头阻塞拥有头部压缩、二进制帧、多路复用、流量控制、服务器推送等许多新特性大幅度提升了HTTP的传输效率。
实际上这些特性也是在“开源”和“节流”这两点上做文章但因为这些都已经内置在了协议内所以只要换上HTTP/2网站就能够立刻获得显著的性能提升。
不过你要注意一些在HTTP/1里的优化手段到了HTTP/2里会有“反效果”。
对于HTTP/2来说一个域名使用一个TCP连接才能够获得最佳性能如果开多个域名就会浪费带宽和服务器资源也会降低HTTP/2的效率所以“域名收缩”在HTTP/2里是必须要做的。
“资源合并”在HTTP/1里减少了多次请求的成本但在HTTP/2里因为有头部压缩和多路复用传输小文件的成本很低所以合并就失去了意义。而且“资源合并”还有一个缺点就是降低了缓存的可用性只要一个小文件更新整个缓存就完全失效必须重新下载。
所以在现在的大带宽和CDN应用场景下应当尽量少用资源合并JavaScript、CSS图片合并数据内嵌让资源的粒度尽可能地小才能更好地发挥缓存的作用。
## 小结
1. 花钱购买硬件、软件或者服务可以直接提升网站的服务能力其中最有价值的是CDN
2. 不花钱也可以优化HTTP三个关键词是“开源”“节流”和“缓存”
3. 后端应该选用高性能的Web服务器开启长连接提升TCP的传输效率
4. 前端应该启用gzip、br压缩减小文本、图片的体积尽量少传不必要的头字段
5. 缓存是无论何时都不能忘记的性能优化利器应该总使用Etag或Last-modified字段标记资源
6. 升级到HTTP/2能够直接获得许多方面的性能提升但要留意一些HTTP/1的“反模式”。
到这里,专栏的全部课程就学完了,在这三个月的时间里你是否有了很多的收获呢?
接下来,就请在广阔的网络世界里去实践这些知识吧,祝你成功!
![unpreview](https://static001.geekbang.org/resource/image/7b/8a/7b2351d7175e815710de646d53d7958a.png)