<audio id="audio" title="39 | HTTP性能优化面面观（上）" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/8d/55/8d022162cc6c4652d1f6f73562edf155.mp3"></audio>

“透视HTTP协议”这个专栏已经陪伴了你近三个月的时间，在最后的这两讲里，我将把散落在前面各个章节的零散知识点整合起来，做一个总结，和你一起聊聊HTTP的性能优化。

由于HTTPS（SSL/TLS）的优化已经在[第28讲](https://time.geekbang.org/column/article/111287)里介绍的比较详细了，所以这次就暂时略过不谈，你可以课后再找机会复习。

既然要做性能优化，那么，我们就需要知道：什么是性能？它都有哪些指标，又应该如何度量，进而采取哪些手段去优化？

“性能”其实是一个复杂的概念。不同的人、不同的应用场景都会对它有不同的定义。对于HTTP来说，它又是一个非常复杂的系统，里面有非常多的角色，所以很难用一两个简单的词就能把性能描述清楚。

还是从HTTP最基本的“请求-应答”模型来着手吧。在这个模型里有两个角色：客户端和服务器，还有中间的传输链路，考查性能就可以看这三个部分。

<img src="https://static001.geekbang.org/resource/image/3a/62/3a8ab1e3ace62d184adc2dc595d32f62.png" alt="unpreview">

## HTTP服务器

我们先来看看服务器，它一般运行在Linux操作系统上，用Apache、Nginx等Web服务器软件对外提供服务，所以，性能的含义就是它的服务能力，也就是尽可能多、尽可能快地处理用户的请求。

衡量服务器性能的主要指标有三个：**吞吐量**（requests per second）、**并发数**（concurrency）和**响应时间**（time per request）。

吞吐量就是我们常说的RPS，每秒的请求次数，也有叫TPS、QPS，它是服务器最基本的性能指标，RPS越高就说明服务器的性能越好。

并发数反映的是服务器的负载能力，也就是服务器能够同时支持的客户端数量，当然也是越多越好，能够服务更多的用户。

响应时间反映的是服务器的处理能力，也就是快慢程度，响应时间越短，单位时间内服务器就能够给越多的用户提供服务，提高吞吐量和并发数。

除了上面的三个基本性能指标，服务器还要考虑CPU、内存、硬盘和网卡等系统资源的占用程度，利用率过高或者过低都可能有问题。

在HTTP多年的发展过程中，已经出现了很多成熟的工具来测量这些服务器的性能指标，开源的、商业的、命令行的、图形化的都有。

在Linux上，最常用的性能测试工具可能就是ab（Apache Bench）了，比如，下面的命令指定了并发数100，总共发送10000个请求：

```
ab -c 100 -n 10000 'http://www.xxx.com'

```

系统资源监控方面，Linux自带的工具也非常多，常用的有uptime、top、vmstat、netstat、sar等等，可能你比我还要熟悉，我就列几个简单的例子吧：

```
top             #查看CPU和内存占用情况
vmstat  2       #每2秒检查一次系统状态
sar -n DEV 2    #看所有网卡的流量，定时2秒检查

```

理解了这些性能指标，我们就知道了服务器的性能优化方向：合理利用系统资源，提高服务器的吞吐量和并发数，降低响应时间。

## HTTP客户端

看完了服务器的性能指标，我们再来看看如何度量客户端的性能。

客户端是信息的消费者，一切数据都要通过网络从服务器获取，所以它最基本的性能指标就是“**延迟**”（latency）。

之前在讲HTTP/2的时候就简单介绍过延迟。所谓的“延迟”其实就是“等待”，等待数据到达客户端时所花费的时间。但因为HTTP的传输链路很复杂，所以延迟的原因也就多种多样。

首先，我们必须谨记有一个“不可逾越”的障碍——光速，因为地理距离而导致的延迟是无法克服的，访问数千公里外的网站显然会有更大的延迟。

其次，第二个因素是带宽，它又包括接入互联网时的电缆、WiFi、4G和运营商内部网络、运营商之间网络的各种带宽，每一处都有可能成为数据传输的瓶颈，降低传输速度，增加延迟。

第三个因素是DNS查询，如果域名在本地没有缓存，就必须向DNS系统发起查询，引发一连串的网络通信成本，而在获取IP地址之前客户端只能等待，无法访问网站。

第四个因素是TCP握手，你应该对它比较熟悉了吧，必须要经过SYN、SYN/ACK、ACK三个包之后才能建立连接，它带来的延迟由光速和带宽共同决定。

建立TCP连接之后，就是正常的数据收发了，后面还有解析HTML、执行JavaScript、排版渲染等等，这些也会耗费一些时间。不过它们已经不属于HTTP了，所以不在今天的讨论范围之内。

之前讲HTTPS时介绍过一个专门的网站“[SSLLabs](https://www.ssllabs.com/)”，而对于HTTP性能优化，也有一个专门的测试网站“[WebPageTest](https://www.webpagetest.org)”。它的特点是在世界各地建立了很多的测试点，可以任意选择地理位置、机型、操作系统和浏览器发起测试，非常方便，用法也很简单。

网站测试的最终结果是一个直观的“瀑布图”（Waterfall Chart），清晰地列出了页面中所有资源加载的先后顺序和时间消耗，比如下图就是对GitHub首页的一次测试。

<img src="https://static001.geekbang.org/resource/image/5c/f4/5cd2a91b4466ee63f48bc049ba61b9f4.png" alt="">

Chrome等浏览器自带的开发者工具也可以很好地观察客户端延迟指标，面板左边有每个URI具体消耗的时间，面板的右边也是类似的瀑布图。

点击某个URI，在Timing页里会显示出一个小型的“瀑布图”，是这个资源消耗时间的详细分解，延迟的原因都列的清清楚楚，比如下面的这张图：

<img src="https://static001.geekbang.org/resource/image/d7/a2/d77ee484b62910b8eedce0ecddb305a2.png" alt="">

图里面的这些指标都是什么含义呢？我给你解释一下：

- 因为有“队头阻塞”，浏览器对每个域名最多开6个并发连接（HTTP/1.1），当页面里链接很多的时候就必须排队等待（Queued、Queueing），这里它就等待了1.62秒，然后才被浏览器正式处理；
- 浏览器要预先分配资源，调度连接，花费了11.56毫秒（Stalled）;
- 连接前必须要解析域名，这里因为有本地缓存，所以只消耗了0.41毫秒（DNS Lookup）；
- 与网站服务器建立连接的成本很高，总共花费了270.87毫秒，其中有134.89毫秒用于TLS握手，那么TCP握手的时间就是135.98毫秒（Initial connection、SSL）；
- 实际发送数据非常快，只用了0.11毫秒（Request sent）；
- 之后就是等待服务器的响应，专有名词叫TTFB（Time To First Byte），也就是“首字节响应时间”，里面包括了服务器的处理时间和网络传输时间，花了124.2毫秒；
- 接收数据也是非常快的，用了3.58毫秒（Content Dowload）。

从这张图你可以看到，一次HTTP“请求-响应”的过程中延迟的时间是非常惊人的，总时间415.04毫秒里占了差不多99%。

所以，客户端HTTP性能优化的关键就是：降低延迟。

## HTTP传输链路

以HTTP基本的“请求-应答”模型为出发点，刚才我们得到了HTTP性能优化的一些指标，现在，我们来把视角放大到“真实的世界”，看看客户端和服务器之间的传输链路，它也是影响HTTP性能的关键。

还记得[第8讲](https://time.geekbang.org/column/article/100502)里的互联网示意图吗？我把它略微改了一下，划分出了几个区域，这就是所谓的“**第一公里**”“**中间一公里**”和“**最后一公里**”（在英语原文中是mile，英里）。

<img src="https://static001.geekbang.org/resource/image/50/32/5011b2998d2a0c58c87e31000d551732.png" alt="">

“第一公里”是指网站的出口，也就是服务器接入互联网的传输线路，它的带宽直接决定了网站对外的服务能力，也就是吞吐量等指标。显然，优化性能应该在这“第一公里”加大投入，尽量购买大带宽，接入更多的运营商网络。

“中间一公里”就是由许多小网络组成的实际的互联网，其实它远不止“一公里”，而是非常非常庞大和复杂的网络，地理距离、网络互通都严重影响了传输速度。好在这里面有一个HTTP的“好帮手”——CDN，它可以帮助网站跨越“千山万水”，让这段距离看起来真的就好像只有“一公里”。

“最后一公里”是用户访问互联网的入口，对于固网用户就是光纤、网线，对于移动用户就是WiFi、基站。以前它是客户端性能的主要瓶颈，延迟大带宽小，但随着近几年4G和高速宽带的普及，“最后一公里”的情况已经好了很多，不再是制约性能的主要因素了。

除了这“三公里”，我个人认为还有一个“第零公里”， 就是网站内部的Web服务系统。它其实也是一个小型的网络（当然也可能会非常大），中间的数据处理、传输会导致延迟，增加服务器的响应时间，也是一个不可忽视的优化点。

在上面整个互联网传输链路中，末端的“最后一公里”我们是无法控制的，所以我们只能在“第零公里”“第一公里”和“中间一公里”这几个部分下功夫，增加带宽降低延迟，优化传输速度。

## 小结

1. 性能优化是一个复杂的概念，在HTTP里可以分解为服务器性能优化、客户端性能优化和传输链路优化；
1. 服务器有三个主要的性能指标：吞吐量、并发数和响应时间，此外还需要考虑资源利用率；
1. 客户端的基本性能指标是延迟，影响因素有地理距离、带宽、DNS查询、TCP握手等；
1. 从服务器到客户端的传输链路可以分为三个部分，我们能够优化的是前两个部分，也就是“第一公里”和“中间一公里”；
1. 有很多工具可以测量这些指标，服务器端有ab、top、sar等，客户端可以使用测试网站，浏览器的开发者工具。

## 课下作业

1. 你有HTTP性能优化的经验吗？常用的有哪些方法？
1. 你是怎么理解客户端的“延迟”的？应该怎样降低延迟？

欢迎你把自己的学习体会写在留言区，与我和其他同学一起讨论。如果你觉得有所收获，也欢迎把文章分享给你的朋友。

<img src="https://static001.geekbang.org/resource/image/fb/32/fbc85df2c908cb8fa6bffde6ea989732.png" alt="unpreview">

<img src="https://static001.geekbang.org/resource/image/56/63/56d766fc04654a31536f554b8bde7b63.jpg" alt="unpreview">
