身为前端的你,是否会有这样的烦恼:随着访问用户的成倍增加,站点变得越来越脆弱。任何的访问过慢或崩溃都将是一场灾难。

这就对我们工程师提出了更高的要求,要保障网站的「可访问性」和「稳定性」都维持在一个较高水平。那么,是时候了解了解 Web 性能测试了!

一、情景再现

有一个大型推广活动来了,类似与抢火车票、淘宝双十一,你能否回答 Boss 的如下问题?
1.我们的网站是否能扛住如此的高并发?
2.服务器单机 QPS 是多少?
3.如果站点扛不住,扩容的话,需要几台?

一连串的问题,如果你招架不住,不妨仔细阅读本文

二、什么是性能测试?

要回答上面的问题,需要我们有一些知识储备。不着急,循序渐进,各个击破。

一般来说「性能测试」包括压力测试、负载测试、容量测试三种主要测试类型。

1.压力测试 StressTest
压力测试可以测试网站在某个特定的持续的压力下运行的稳定性。

2.负载测试 LoadTest
负载测试是为了检验系统在给定负载下是否能达到预期性能指标。

3.容量测试 CapabilityTest
容量测试针对数据库而言,是在数据库中有较大数量的数据记录情况下对系统进行的测试。

内容比较多,为了专注聚焦,我们本节主要来看一下压力测试。

三、压力测试

压力测试是通过不断向被测系统施加压力,测试系统在压力情况下的性能表现。主要考察当前软硬件环境下系统所能承受的最大负荷并帮助开发人员找出系统瓶颈所在。我们可以模拟巨大的流量请求以查看应用程序在峰值使用情况以及服务器状况。

有效的压力测试将应用以下这些关键条件:重复,并发,量级,随机变化。

需要注意的是:压力测试并不会报告是什么导致了问题。它只会报告这有了问题,例如:查询页面在并发 1000 个用户使用时变慢下来,但它不会显示什么导致了变慢。

捕获到的性能统计数据例如 CPU 和内存使用量只是强调了潜在的问题区域,但并不会指出实际的根源在应用程序的什么地方。

更多的概念可以查看:为什么要进行压力测试?

四、核心指标

了解了上述压力测试之后,我们先不着急进行网站压测,补充几个可以让你事半功倍的核心指标:

1.什么是 TPS
Transactions Per Second 的缩写,每秒处理的事务数目。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数,最终利用这些信息作出的评估分。

一个事务可能对应多个请求,这与数据库的事务操作极其相似。

2.什么是 QPS
Queries Per Second 的缩写,每秒能处理查询数目,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。

需要注意的是:虽然名义上是查询的意思,但实际上,现在习惯于对单一接口服务的处理能力用 QPS 进行表述(即使它并不是查询操作)。

3.什么是 RT
响应时间,处理一次请求所需要的平均处理时间。我们一般会关注 90th 请求的的处理时间,因为可能因网络情况出现极端情况,长尾数据会对我们产生干扰。

4.系统 CPU 利用率
如果系统的 CPU 使用率已经很高,说明我们的系统是个计算度很复杂的系统,这时候如果 QPS 已经上不去了,就需要赶紧扩容,通过增加机器分担计算的方式来提高系统的吞吐量。

5.系统内存
如果 CPU 使用率一般,但是系统的 QPS 上不去,说明我们的机器并没有忙于计算,而是受到其他资源的限制,如内存、I/O。这时候首先看下内存是不是已经不够了,如果内存不够了,那就赶紧扩容了。

五、QPS 如何计算?

QPS 并没有准确的计算公式,但是实际压测中我们完全可以按照如下模型进行估算:

原理:每天 80% 的访问集中在 20% 的时间里,这 20% 时间叫做「峰值时间」。

公式:( 总 PV 80% ) / ( 每天秒数 20% ) = 峰值时间每秒请求数(QPS)
机器:峰值时间每秒 QPS / 单台机器的 QPS = 需要的机器

问:每天 300w PV 的在单台机器上,这台机器需要多少 QPS
答:( 3000000 * 0.8 ) / (86400 * 0.2 ) = 139 (QPS)

问:如果一台机器的 QPS58 ,需要几台机器来支持?
答:139 / 58 = 3

具体的计算公式可以参考这篇文章:峰值 QPS 和机器计算公式

六、推荐工具

压测工具有很多,JMeterLoadRunnerWebLoadNeoLoadLoadsterTcpCopyABWebBench 等等,恐怕一时间无法说完。但是论起上手能力,就要说说我们的主角 wrk 了。

wrk 是一款针对 Http 协议的基准测试工具,它能够在单机多核 CPU 的条件下,使用系统自带的高性能 I/O 机制,如 EpollKqueue 等,通过多线程和事件模式,对目标机器产生大量的负载。

有多容易,我们不妨试试看?

1.安装

1
2
3
git clone https://github.com/wg/wrk.git  
cd wrk
make

注意使用 ./wrk 命令启动。

2.基本使用

1
wrk -t12 -c400 -d30s http://127.0.0.1:8080/jartto

参数说明:
-cHTTP 连接数,每一个线程处理 N = 连接数/线程数
-d:持续时间,2s2m2h
-t:总的线程数
-s:脚本,可以是 Lua 脚本
-H:增加 HTTP header,例如:User-Agent: jartto
--latency:输出时间统计的细节
--timeout:超时时间

3.输出
上面我们使用 12 线程,保持打开 400Http 连接,执行 30s。脚本运行完毕会输出:

1
2
3
4
5
6
7
8
Running 30s test @ http://127.0.0.1:8080/jartto
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 635.91us 0.89ms 12.92ms 93.69%
Req/Sec 56.20k 8.07k 62.00k 86.54%
22464657 requests in 30.00s, 17.76GB read
Requests/sec: 748868.53
Transfer/sec: 606.33MB

输出说明:
Latency:响应时间
Req/Sec:每个线程每秒钟的完成的请求数
Avg:平均
Max:最大
Stdev:标准差
+/- Stdev: 正负一个标准差占比

标准差大说明样本离散程度高,系统性能波动大。

在压测过程中,一般线程数不宜过多,CPU 核数的 2-4 倍就可以了。 太多反而因为线程切换过多造成效率降低, 因为 wrk 不是使用每个连接一个线程的模型, 而是通过异步网络 I/O 提升并发量。

所以网络通信不会阻塞线程执行,这也是 wrk 可以用很少的线程模拟大量网路连接的原因。

七、高级定制

到这里,相信文章开头提出的问题,你已经可以很好的回答了。我们不妨继续升级,来一些高级定制。可能很多童鞋注意到了上面文档中提到的 -s 参数了,我们先看看官方文档:

1
2
An optional LuaJIT script can perform HTTP request generation, response processing, 
and custom reporting.

LuaJIT 脚本可以执行 HTTP 请求生成,响应处理和自定义报告。这里是 Lua 的一些案例。鉴于篇幅过长,本节我们先了解到这里,精彩部分我们就留到下一篇继续探讨吧!

文章最后,打个小广告吧。如果你想搭上在线教育的快车,快速成长,不妨加入我们。一起成长,一起学习,一起挑战更多有趣的事情,「跟谁学-高途课堂」欢迎你,请将简历私我~