观察网站性能

这篇文章最后更新的时间在六个月之前,文章所叙述的内容可能已经失效,请谨慎参考!

ab

一般的使用命令

./ab -c 10 -n 1000 http://www.baidu.com/
./ab --enable ssl -c 10 -n 1000 https://www.baidu.com/
./abs -c 10 -n 1000 https://www.baidu.com/

输出的解释

Server Software:        BWS/1.1 # 响应的服务器类型
Server Hostname:        www.baidu.com # 请求的 URL 主机名
Server Port:            443 # 请求端口
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-AES128-GCM-SHA256,2048,128 # https 的版本和密码套件

Document Path:          / # 请求路径
Document Length:        227 bytes # HTTP响应数据的正文长度

Concurrency Level:      10 # 并发用户数,就是 -c 参数的值
Time taken for tests:   21.376 seconds  # 所有这些请求被处理完成所花费的总时间 单位秒
Complete requests:      1000 # 总请求数量,就是 -n 参数的值
Failed requests:        0 # 表示失败的请求数量
Total transferred:      1081951 bytes # 所有请求的响应数据长度总和。包括每个 HTTP 响应数据的头信息和正文数据的长度
HTML transferred:       227000 bytes # 所有请求的响应数据中正文数据的总和,也就是减去了 Total transferred 中 HTTP 响应数据中的头信息的长度
Requests per second:    46.78 [#/sec] (mean) # 吞吐量,计算公式: Complete requests/Time taken for tests  总请求数/处理完成这些请求数所花费的时间
Time per request:       213.762 [ms] (mean) # 用户平均请求等待时间,计算公式: Time token for tests/(Complete requests/Concurrency Level)。处理完成所有请求数所花费的时间/(总请求数/并发用户数)
Time per request:       21.376 [ms] (mean, across all concurrent requests) # 服务器平均请求等待时间,计算公式: Time taken for tests/Complete requests,正好是吞吐率的倒数。也可以这么统计: Time per request/Concurrency Level
Transfer rate:          49.43 [Kbytes/sec] received # 表示这些请求在单位时间内从服务器获取的数据长度,计算公式: Total trnasferred/ Time taken for tests,这个统计很好的说明服务器的处理能力达到极限时,其出口宽带的需求量。

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       31  132 203.5     85    1204 # Connect 建立 tcp 连接的耗时
Processing:     0   81 150.7     55    1141 # Processing 总耗时减去 Connect
Waiting:        0   53 122.5     35    1103 # Waiting 客户端发送完请求信息的最后一个字节 到 接收响应信息的的第一个字节 的耗时
Total:         85  213 250.9    145    1304 # Total 总的耗时,从建立连接到关闭连接的耗时

# min 最小值, mean 平均值, [+/-sd] 标准差, median 中位数, max 最大值

Percentage of the requests served within a certain time (ms)
  50%    145 # 50% 的请求在 145ms 内返回
  66%    154
  75%    160
  80%    165
  90%    192
  95%   1133
  98%   1186 # 98% 的请求在 1186ms 内返回
  99%   1235
 100%   1304 (longest request)

ab 更详细的用法

ab 请求时设置 cookie

./ab -c 10 -n 1000 \
-C "name=ball;age=99;sex=male" \
http://localhsot/

./ab -c 10 -n 1000 \
-H "Cookie: name=ball;age=36" \
http://localhsot/

ab 发送 post 或 put

./ab -c 10 -n 1000 \
-p 'post.txt' -T 'application/x-www-form-urlencoded' \
http://localhsot/

./ab -c 10 -n 1000 \
-u 'put.txt' -T 'application/x-www-form-urlencoded' \
http://localhsot/

如果发送的内容是 application/x-www-form-urlencoded ,那么 post.txt 或 put.txt 里的内容也要经过编码

ab 发送文件和普通的 post 或 put 是一样的

./ab -c 10 -n 1000 \
-p 'post.txt' -T 'multipart/form-data; boundary=----WebKitFormBoundaryRO0YA4pq9oCgwTkt' \
http://localhsot/

post.txt 文件的内容

------WebKitFormBoundaryRO0YA4pq9oCgwTkt
Content-Disposition: form-data; name="fileUpload"; filename="test.png"
Content-Type: image/png
iVBORw0KGg.............................................
------WebKitFormBoundaryRO0YA4pq9oCgwTkt--

实质上就是手工实现 rfc 1867 1521 1522 这几个标准

ab 只能进行一些简单的压力测试,一些更详细的测试还是要用 jmeter

curl

一般的使用命令

curl -o /dev/null -s -w %{time_namelookup}::%{time_connect}::%{time_starttransfer}::%{time_total}::%{speed_download}"\n" "https://www.baidu.com"

命令解释

-o: 把 curl 返回的 html js 写到 /dev/null
-s: 去掉所有状态
-w: 按照后面的格式输出
time_namelookup: DNS 解析域名 www.baidu.com 的时间
time_commect: client 和 server 端建立 TCP 连接的时间, 包括前一项的时间
time_starttransfer: 从 client 发出请求到 web 的 server 响应第一个字节的时间, 包括前二项的时间
time_total: client 发出请求到 web 的 server 发送会所有的相应数据的时间, 包括前三项的时间
speed_download: 下载速度 单位 byte/s

这是一段根据上面 curl 命令写成的,可以连续执行的,能显示多次执行平均值的 bash 脚本

# TEST_COUTE=10
# TEST_URL="https://www.baidu.com"
# ./testwebsite.sh 10 "https://www.baidu.com"

TEST_COUTE=$1
TEST_URL=$2

echo "TEST_COUTE" $TEST_COUTE
echo "TEST_URL" $TEST_URL

time_namelookup=0
time_commect=0
time_starttransfer=0
time_total=0
speed_download=0

echo "time_namelookup::time_commect::time_starttransfer::time_total::speed_download"
for ((i=1;i<=$TEST_COUTE;i++))
do
    ans=$(curl -o /dev/null -s -w %{time_namelookup}::%{time_connect}::%{time_starttransfer}::%{time_total}::%{speed_download}"\n" $TEST_URL)
    echo $ans

    temp=`echo $ans | awk -v FS='::' '{printf ("%.6f\n", $1)}'`
    time_namelookup=`echo $temp $time_namelookup | awk '{printf ("%.6f\n", $1+$2)}'`

    temp=`echo $ans | awk -v FS='::' '{printf ("%.6f\n", $2)}'`
    time_commect=`echo $temp $time_commect | awk '{printf ("%.6f\n", $1+$2)}'`

    temp=`echo $ans | awk -v FS='::' '{printf ("%.6f\n", $3)}'`
    time_starttransfer=`echo $temp $time_starttransfer | awk '{printf ("%.6f\n", $1+$2)}'`

    temp=`echo $ans | awk -v FS='::' '{printf ("%.6f\n", $4)}'`
    time_total=`echo $temp $time_total | awk '{printf ("%.6f\n", $1+$2)}'`

    temp=`echo $ans | awk -v FS='::' '{printf ("%.6f\n", $5)}'`
    speed_download=`echo $temp $speed_download | awk '{printf ("%.6f\n", $1+$2)}'`
done
echo "total"
echo $time_namelookup"::"$time_commect"::"$time_starttransfer"::"$time_total"::"$speed_download
echo "mean"
echo `echo $TEST_COUTE $time_namelookup | awk '{printf ("%.6f\n", $2/$1)}'`"::"\
`echo $TEST_COUTE $time_commect | awk '{printf ("%.6f\n", $2/$1)}'`"::"\
`echo $TEST_COUTE $time_starttransfer | awk '{printf ("%.6f\n", $2/$1)}'`"::"\
`echo $TEST_COUTE $time_total | awk '{printf ("%.6f\n", $2/$1)}'`"::"\
`echo $TEST_COUTE $speed_download | awk '{printf ("%.6f\n", $2/$1)}'`

这是上面那段脚本的运行结果 ./testwebsite.sh 10 "https://www.baidu.com"

TEST_COUTE 10
TEST_URL https://www.baidu.com
time_namelookup::time_commect::time_starttransfer::time_total::speed_download
0.005223::0.032470::0.075645::0.075783::32573.000
0.004661::0.010493::0.050055::0.050138::48860.000
0.004319::0.011194::0.051169::0.051273::47901.000
0.004192::0.012334::0.051118::0.051183::47901.000
0.004367::0.011130::0.050391::0.050472::48860.000
0.004902::0.011672::0.048436::0.048614::50895.000
0.004449::0.010758::0.045324::0.045450::54288.000
0.004305::0.011931::0.050933::0.050999::48860.000
0.004828::0.012194::0.052479::0.052609::46980.000
0.004216::0.009486::0.134916::0.134998::18231.000
total
0.045462::0.133662::0.610466::0.611519::445349.000000
mean
0.004546::0.013366::0.061047::0.061152::44534.900000

运行结果的解释

这样的脚本并不能测试并发

lighthouse

一个是浏览器自带的 lighthouse (基于 chromium 的浏览器才有)。 一个是谷歌在线的 lighthouse https://developers.google.com/speed/pagespeed/insights/ 。 还有一个 chromium 的插件,但实际上和开发者工具里的 lighthouse 是一样的。

评分一共有五部分

一般情况下,只需要关注这三部分即可,分数越高越好

一般情况下,如果低于这个分数就要优化

浏览器开发者工具

相关文档

请求列表里有一个 时间 的列,但这个时间一般会包含队列等待,dns解释,stl握手。

从后端的角度来看,大部分情况下只需要关注,请求详情里的这三个参数

  1. Request sent 请求第一个字节发出前到最后一个字节发出后的时间,也就是上传时间
  2. Waiting 请求发出后,到收到响应的第一个字节所花费的时间 (Time To First Byte)
  3. Content Download 收到响应的第一个字节,到接受完最后一个字节的时间,就是下载时间

其它

其它工具

查找问题

curl -i -v -L www.baidu.com
# -i 输出 http 头
# -v 输出通信的整个过程,用于调试
# -L 让 HTTP 请求跟随服务器的重定向。curl 默认不跟随重定向。
# dns 查询
nslookup www.baidu.com
# dns 反查
nslookup -qt=ptr 14.215.177.38
ping www.baidu.com
telnet 127.0.0.1 80
# 如果端口没有开放,会提示连接失败
curl --no-buffer --connect-timeout 30 -i -v telnet://127.0.0.1:80
# 如果输出 connected 表示端口有开启
# linux 用 traceroute
traceroute www.baidu.com
# windows 用 tracert
tracert www.baidu.com

网站性能的一些准则