0%

Mac下ab压测node实验

Node.js是一个开源与跨平台的JavaScript运行时环境,一个可用于几乎任何项目的流行工具。Node.js在浏览器外运行V8 JavaScript引擎(Google Chrome 的内核)。

一、概念

      ab命令是apache模拟多线程并发请求以测试web服务器负载压力,如httpd、nginx、lighthttp、IIS等。考虑到宽带网络延迟等问题,一般建议在内网使用一台专门压测的机器对其他机器进行测试,提高数据的准确性。

需要注意的是ab进行的一切测试都是基于HTTP

在Mac下直接输入ab -h可查看其用法,官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Usage: ab [options] [http[s]://]hostname[:port]/path
Options are:
-n requests Number of requests to perform,此次压力测试总请求次数。
-c concurrency Number of multiple requests to make at a time,压力测试的并发数
-t timelimit Seconds to max. to spend on benchmarking,等待响应的最大时间(单位:秒)
This implies -n 50000
-s timeout Seconds to max. wait for each response
Default is 30 seconds
-b windowsize Size of TCP send/receive buffer, in bytes,TCP发送/接收的缓冲大小(单位:字节)。
-B address Address to bind to when making outgoing connections
-p postfile File containing data to POST. Remember also to set -T,发送POST请求时需要上传的文件,需要同时设置-T参数。
-u putfile File containing data to PUT. Remember also to set -T,发送PUT请求时需要上传的文件,需要同时设置-T参数。
-T content-type Content-type header to use for POST/PUT data, eg.
'application/x-www-form-urlencoded'
Default is 'text/plain',用于设置Content-Type请求头信息,例如:application/x-www-form-urlencoded,默认值为text/plain。
-v verbosity How much troubleshooting info to print,打印帮助信息的冗余级别。
-w Print out results in HTML tables,以HTML表格形式打印结果。
-i Use HEAD instead of GET,使用HEAD请求代替GET请求。
-x attributes String to insert as table attributes,插入字符串作为table标签的属性。
-y attributes String to insert as tr attributes,插入字符串作为tr标签的属性。
-z attributes String to insert as td or th attributes,插入字符串作为td标签的属性。
-C attribute Add cookie, eg. 'Apache=1234'. (repeatable),添加cookie信息,例如:"Apache=1234"(可以重复该参数选项以添加多个)。
-H attribute Add Arbitrary header line, eg. 'Accept-Encoding: gzip'
Inserted after all normal header lines. (repeatable),添加任意的请求头,例如:"Accept-Encoding: gzip",请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个)。
-A attribute Add Basic WWW Authentication, the attributes,添加一个基本的网络认证信息,用户名和密码之间用英文冒号隔开。
are a colon separated username and password.
-P attribute Add Basic Proxy Authentication, the attributes,添加一个基本的代理认证信息,用户名和密码之间用英文冒号隔开。
are a colon separated username and password.
-X proxy:port Proxyserver and port number to use,指定使用的代理服务器和端口号,例如:"126.10.10.3:88"。
-V Print version number and exit,打印版本号并退出。
-k Use HTTP KeepAlive feature,使用HTTP的KeepAlive特性。
-d Do not show percentiles served table.不显示百分比。
-S Do not show confidence estimators and warnings.不显示预估和警告信息。
-q Do not show progress when doing more than 150 requests
-l Accept variable document length (use this for dynamic pages)
-g filename Output collected data to gnuplot format file.输出结果信息到gnuplot格式的文件中。
-e filename Output CSV file with percentages served 输出结果信息到CSV格式的文件中。
-r Don't exit on socket receive errors.指定接收到错误信息时不退出程序。
-m method Method name
-h Display usage information (this message)显示用法信息,其实就是ab -help。
-I Disable TLS Server Name Indication (SNI) extension
-Z ciphersuite Specify SSL/TLS cipher suite (See openssl ciphers)
-f protocol Specify SSL/TLS protocol
(TLS1, TLS1.1, TLS1.2 or ALL)
-E certfile Specify optional client certificate chain and private key

二、实战

  1. 安装环境(默认情况下Mac自带ab)
    • 安装brew,传送门
    • 下载httpd源码包,传送门,移动至/usr/local/src
    • 安装httpd依赖
      • brew install pcre apr apr-util
    • 安装httpd服务
      • cd /usr/local/src
      • sudo tar -zxvf httpd-2.4.46.tar.gz
      • cd httpd-2.4.46
      • sudo ./configure –prefix=/usr/local/httpd-2.4.46 –with-apr=/usr/local/Cellar/apr/1.7.0 –with-apr-util=/usr/local/Cellar/apr-util/1.6.1_3
      • sudo make && sudo make install
  2. ab的简单使用
    • 模拟100个用户发起100次请求:ab -n 100 -c 100 http://baidu.com/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking baidu.com (be patient).....done


Server Software: Apache # 模拟请求的web服务器信息
Server Hostname: baidu.com # 模拟请求中的主机部分名称
Server Port: 80 # 模拟请求中的服务器监听端口

Document Path: /index.html
Document Length: 7387 bytes # http响应数据的正文长度。

Concurrency Level: 100 # 并发级别,即并发数,模拟请求中-c参数指定的数量
Time taken for tests: 1.482 seconds # 总共花费的时间
Complete requests: 100 # 总共发起的请求数量,模拟请求中-n参数指定的数量
Failed requests: 12 # 失败的请求数量,通过该数值和Complete requests相除可以计算请求的失败率,作为测试结果的重要参考。
(Connect: 0, Receive: 0, Length: 12, Exceptions: 0)
Total transferred: 676808 bytes # 总共传输的数据量(从被测服务器接收到的总数据量),包括index.html的文本内容和请求头信息,等于
Document Length * (Complete requests - Failed requests)

HTML transferred: 650056 bytes # 从服务器接收到的index.html文件的总大小,等于Document Length * Complete requests
Requests per second: 67.50 [#/sec] (mean) # 平均每秒完成的请求数即QPS,是一个平均值,等于Complete requests/Time taken for tests
Time per request: 1481.567 [ms] (mean) # 用户平均请求等待时间,是从用户角度计算完成一个请求所需要的时间,等于
Time taken for tests / (Complete requests / Concurrency Level),约等于下一项乘以并发数
Time per request: 14.816 [ms] (mean, across all concurrent requests) # 服务器平均请求处理时间,是从服务器角度计算完成一个请求的时间,等于
Time taken for tests / Complete requests,也等于Time per request / Concurrency Level
Transfer rate: 446.11 [Kbytes/sec] received # 网络传输速度(对于大文件的请求测试,这个值很容易成为系统瓶颈所在),等于
Total transferred / Time taken for tests

# 以下数据是针对第一个Time per request进行细分和统计,一个请求的响应时间可以分成三个部分:
网络链接(Connect)
系统处理(Processing)
等待(Waiting)

其中Total并不等于前三行数据相加,因为前三行的数据并不是在同一个请求中采集到的,可能某个请求的网络延迟最短,但是系统处理时间是最长的,所以Total是从整个请求所需要的时间的角度来统计的。

表中:
min表示最小值
mean表示平均值;
[+/-sd]表示标准差(Standard Deviation),也称均方差(mean square error),表示数据的离散程度,数值越大表示数据越分散,系统响应时间越不稳定;
median表示中位数;
max表示最大值。

Connection Times (ms)
min mean[+/-sd] median max
Connect: 17 29 7.9 26 46
Processing: 22 412 323.0 346 1368
Waiting: 0 144 210.3 71 1361
Total: 39 441 323.5 372 1394

# 以下数据是对此次并发请求的一个总结,第一行表示50%的请求都是在372ms内完成的,以此类推。
Percentage of the requests served within a certain time (ms)
50% 372
66% 560
75% 766
80% 783
90% 893
95% 964
98% 1029
99% 1394
100% 1394 (longest request)
  1. node

实验一:创建基于node的http服务

  • server.js,内容见下方
  • 运行此node服务node server.js
  • 模拟请求10000次,并发数依次10、100、1000等增加ab -n 10000 -c 10 http://localhost:3000/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const http = require('http');

let port = process.env.port | 3000

http.createServer(app).listen(port, () => {
console.log(`server is listening ${port}`)
})

let num = 0;
function app(req, res) {
console.log(`第${num++}次访问`)
res.end(getdata().toString())
}

function getdata() {
let size = 1 * 1024
let arr = new Array(size)
for (let i = 0; i < arr.length; i++) {
arr[i] = 1
}
return arr;
}

实验二:基于mongodb查询测试

  • 安装mongose模块npm install mongose
  • server.js,内容见下方
  • 运行此node服务node server.js
  • 模拟请求10000次,并发数依次10、100、1000等增加ab -n 10000 -c 10 http://localhost:3000/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const http = require('http');

let port = process.env.port | 3000

http.createServer(app).listen(port, () => {
console.log(`server is listening ${port}`)
})

let num = 0;
function app(req, res) {
console.log(`第${num++}次访问`)
getDataFromDb(res)
}

function getdata() {
let size = 1 * 1024
let arr = new Array(size)
for (let i = 0; i < arr.length; i++) {
arr[i] = 1
}
return arr;
}

function getDataFromDb(res){
let data = Blog.findOne({},(err,result) => {
res.end(result.toString())
})
}

const mongoose = require("mongoose")
mongoose.connect('mongodb://localhost:27017/study', {useNewUrlParser: true, useUnifiedTopology: true });

const Schema = mongoose.Schema;
const blogSchema = new Schema({
title: String,
body: []
});
const Blog = mongoose.model('Blog', blogSchema);
let obj = {title:"tim",body:getdata()}
const post = new Blog(obj);
post.save()
  1. 遇到的问题

问题1:socket: Too many open files (24)

查看系统用户所有限制值:ulimit -a

设置可打开的文件描述符:ulimit -n 1000

问题2:Mac下设置ulimit过大时会提示ulimit: setrlimit failed: invalid argument

查看系统最大设置数:sysctl kern.maxfilessysctl kern.maxfilesperproc

1
2
3
4
5
6
7
8
9
-t: cpu time (seconds)              unlimited
-f: file size (blocks) unlimited
-d: data seg size (kbytes) unlimited
-s: stack size (kbytes) 8192
-c: core file size (blocks) 0
-v: address space (kbytes) unlimited
-l: locked-in-memory size (kbytes) unlimited
-u: processes 1392
-n: file descriptors 256

问题3:apr_socket_recv: Connection reset by peer (54)

这个报错一般是由于使用的MacOSX默认自带的ab限制了并发数导致的,可以通过下载最新版的httpd源码包重新编译,运行编译好的ab

  1. 一些概念
    • 吞吐率(Requests per second):服务器并发处理能力的量化描述,单位是reqs/s,指的是某个并发用户数下单位时间内处理的请求数。
      • 某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐率。
      • 计算公式:总请求数 / 处理完成这些请求数所花费的时间,即Request per second = Complete requests / Time taken for tests
    • 并发连接数(The number of concurrent connections):某个时刻服务器所接受的请求数目,简单的理解就是一个会话。
    • 并发用户数(The number of concurrent users,Concurrency Level):一个用户可能同时会产生多个会话(并发连接数),即并发连接数 >= 并发用户数
    • 用户平均请求等待时间(Time per request)
      • 计算公式:处理完成所有请求数所花费的时间 / (总请求数 / 并发用户数),即 Time per request = Time taken for tests / ( Complete requests / Concurrency Level)
    • 服务器平均请求等待时间(Time per request: across all concurrent requests)
    • 计算公式:处理完成所有请求数所花费的时间 / 总请求数,即Time taken for / testsComplete requests
    • 可以看到,它是吞吐率的倒数。
    • 同时,它也等于用户平均请求等待时间/并发用户数,即 Time per request / Concurrency Level

三、参考

  1. ab
  2. node中文网