本文介绍压测是什么,解释压测的专属名词,教你们如何压测。介绍市面上的常见压测工具(ab、locust、Jmeter、go实现的压测工具、云压测),对比这些压测工具,教你们如何选择一款适合本身的压测工具,本文还有两个压测实战项目:html
go 实现的压测工具,每一个用户用一个协程的方式模拟,最大限度的利用CPU资源python
参数说明:linux
-c
表示并发数ios
-n
每一个并发执行请求的次数,总请求的次数 = 并发数 * 每一个并发执行请求的次数git
-u
须要压测的地址github
# clone 项目
git clone https://github.com/link1st/go-stress-testing.git
# 进入项目目录
cd go-stress-testing
# 运行
go run main.go -c 1 -n 100 -u https://www.baidu.com/
复制代码
执行之后,终端每秒钟都会输出一次结果,压测完成之后输出执行的压测结果golang
压测结果展现:web
─────┬───────┬───────┬───────┬────────┬────────┬────────┬────────┬────────
耗时│ 并发数 │ 成功数│ 失败数 │ qps │最长耗时 │最短耗时│平均耗时 │ 错误码
─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────
1s│ 1│ 8│ 0│ 8.09│ 133.16│ 110.98│ 123.56│200:8
2s│ 1│ 15│ 0│ 8.02│ 138.74│ 110.98│ 124.61│200:15
3s│ 1│ 23│ 0│ 7.80│ 220.43│ 110.98│ 128.18│200:23
4s│ 1│ 31│ 0│ 7.83│ 220.43│ 110.23│ 127.67│200:31
5s│ 1│ 39│ 0│ 7.81│ 220.43│ 110.23│ 128.03│200:39
6s│ 1│ 46│ 0│ 7.72│ 220.43│ 110.23│ 129.59│200:46
7s│ 1│ 54│ 0│ 7.79│ 220.43│ 110.23│ 128.42│200:54
8s│ 1│ 62│ 0│ 7.81│ 220.43│ 110.23│ 128.09│200:62
9s│ 1│ 70│ 0│ 7.79│ 220.43│ 110.23│ 128.33│200:70
10s│ 1│ 78│ 0│ 7.82│ 220.43│ 106.47│ 127.85│200:78
11s│ 1│ 84│ 0│ 7.64│ 371.02│ 106.47│ 130.96│200:84
12s│ 1│ 91│ 0│ 7.63│ 371.02│ 106.47│ 131.02│200:91
13s│ 1│ 99│ 0│ 7.66│ 371.02│ 106.47│ 130.54│200:99
13s│ 1│ 100│ 0│ 7.66│ 371.02│ 106.47│ 130.52│200:100
************************* 结果 stat ****************************
处理协程数量: 1
请求总数: 100 总请求时间: 13.055 秒 successNum: 100 failureNum: 0
************************* 结果 end ****************************
复制代码
参数解释:chrome
耗时: 程序运行耗时。程序每秒钟输出一次压测结果shell
并发数: 并发数,启动的协程数
成功数: 压测中,请求成功的数量
失败数: 压测中,请求失败的数量
qps: 当前压测的QPS(每秒钟处理请求数量)
最长耗时: 压测中,单个请求最长的响应时长
最短耗时: 压测中,单个请求最短的响应时长
平均耗时: 压测中,单个请求平均的响应时长
错误码: 压测中,接口返回的 code码:返回次数的集合
压测,即压力测试,是确立系统稳定性的一种测试方法,一般在系统正常运做范围以外进行,以考察其功能极限和隐患。
主要检测服务器的承受能力,包括用户承受能力(多少用户同时玩基本不影响质量)、流量承受等。
压测类型 | 解释 |
---|---|
压力测试(Stress Testing) | 也称之为强度测试,测试一个系统的最大抗压能力,在强负载(大数据、高并发)的状况下,测试系统所能承受的最大压力,预估系统的瓶颈 |
并发测试(Concurrency Testing) | 经过模拟不少用户同一时刻访问系统或对系统某一个功能进行操做,来测试系统的性能,从中发现问题(并发读写、线程控制、资源争抢) |
耐久性测试(Configuration Testing) | 经过对系统在大负荷的条件下长时间运行,测试系统、机器的长时间运行下的情况,从中发现问题(内存泄漏、数据库链接池不释放、资源不回收) |
压测名词 | 解释 |
---|---|
并发(Concurrency) | 指一个处理器同时处理多个任务的能力(逻辑上处理的能力) |
并行(Parallel) | 多个处理器或者是多核的处理器同时处理多个不一样的任务(物理上同时执行) |
QPS(每秒钟查询数量 Query Per Second) | 服务器每秒钟处理请求数量 (req/sec 请求数/秒 一段时间内总请求数/请求时间) |
事务(Transactions) | 是用户一次或者是几回请求的集合 |
TPS(每秒钟处理事务数量 Transaction Per Second) | 服务器每秒钟处理事务数量(一个事务可能包括多个请求) |
请求成功数(Request Success Number) | 在一次压测中,请求成功的数量 |
请求失败数(Request Failures Number) | 在一次压测中,请求失败的数量 |
错误率(Error Rate) | 在压测中,请求成功的数量与请求失败数量的比率 |
最大响应时间(Max Response Time) | 在一次事务中,从发出请求或指令系统作出的反映(响应)的最大时间 |
最少响应时间(Mininum Response Time) | 在一次事务中,从发出请求或指令系统作出的反映(响应)的最少时间 |
平均响应时间(Average Response Time) | 在一次事务中,从发出请求或指令系统作出的反映(响应)的平均时间 |
机器性能 | 解释 |
---|---|
CUP利用率(CPU Usage) | CUP 利用率分用户态、系统态和空闲态,CPU利用率是指:CPU执行非系统空闲进程的时间与CPU总执行时间的比率 |
内存使用率(Memory usage) | 内存使用率指的是此进程所开销的内存。 |
IO(Disk input/ output) | 磁盘的读写包速率 |
网卡负载(Network Load) | 网卡的进出带宽,包量 |
访问 | 解释 |
---|---|
PV(页面浏览量 Page View) | 用户每打开1个网站页面,记录1个PV。用户屡次打开同一页面,PV值累计屡次 |
UV(网站独立访客 Unique Visitor) | 经过互联网访问、流量网站的天然人。1天内相同访客屡次访问网站,只计算为1个独立访客 |
压测咱们须要有目的性的压测,此次压测咱们须要达到什么目标(如:单台机器的性能为100QPS?网站能同时知足100W人同时在线)
能够经过如下计算方法来进行计算:
压测原则:天天80%的访问量集中在20%的时间里,这20%的时间就叫作峰值
公式: ( 总PV数80% ) / ( 天天的秒数20% ) = 峰值时间每秒钟请求数(QPS)
机器: 峰值时间每秒钟请求数(QPS) / 单台机器的QPS = 须要的机器的数量
假设:网站天天的用户数(100W),天天的用户的访问量约为3000W PV,这台机器的须要多少QPS?
( 30000000*0.8 ) / (86400 * 0.2) ≈ 1389 (QPS)
1389 / 69 ≈ 20
ApacheBench 是 Apache服务器自带的一个web压力测试工具,简称ab。ab又是一个命令行工具,对发起负载的本机要求很低,根据ab命令能够建立不少的并发访问线程,模拟多个访问者同时对某一URL地址进行访问,所以能够用来测试目标服务器的负载压力。总的来讲ab工具小巧简单,上手学习较快,能够提供须要的基本性能指标,可是没有图形化结果,不能监控。
ab属于一个轻量级的压测工具,结果不会特别准确,能够用做参考。
# 在linux环境安装
sudo yum -y install httpd
复制代码
Usage: ab [options] [http[s]://]hostname[:port]/path
用法:ab [选项] 地址
选项:
Options are:
-n requests #执行的请求数,即一共发起多少请求。
-c concurrency #请求并发数。
-s timeout #指定每一个请求的超时时间,默认是30秒。
-k #启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求。默认时,不启用KeepAlive功能。
复制代码
# 使用ab压测工具,对百度的连接 请求100次,并发数1
ab -n 100 -c 1 https://www.baidu.com/
复制代码
压测结果
~ >ab -n 100 -c 1 https://www.baidu.com/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking www.baidu.com (be patient).....done
Server Software: BWS/1.1
Server Hostname: www.baidu.com
Server Port: 443
SSL/TLS Protocol: TLSv1.2,ECDHE-RSA-AES128-GCM-SHA256,2048,128
Document Path: /
Document Length: 227 bytes
Concurrency Level: 1
Time taken for tests: 9.430 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 89300 bytes
HTML transferred: 22700 bytes
Requests per second: 10.60 [#/sec] (mean)
Time per request: 94.301 [ms] (mean)
Time per request: 94.301 [ms] (mean, across all concurrent requests)
Transfer rate: 9.25 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 54 70 16.5 69 180
Processing: 18 24 12.0 23 140
Waiting: 18 24 12.0 23 139
Total: 72 94 20.5 93 203
Percentage of the requests served within a certain time (ms)
50% 93
66% 99
75% 101
80% 102
90% 108
95% 122
98% 196
99% 203
100% 203 (longest request)
复制代码
主要关注的测试指标
Concurrency Level
并发请求数
Time taken for tests
整个测试时间
Complete requests
完成请求个数
Failed requests
失败个数
Requests per second
吞吐量,指的是某个并发用户下单位时间内处理的请求数。等效于QPS,其实能够看做同一个统计方式,只是叫法不一样而已。
Time per request
用户平均请求等待时间
Time per request
服务器处理时间
是很是简单易用、分布式、python开发的压力测试工具。有图形化界面,支持将压测数据导出。
# pip3 安装locust
pip3 install locust
# 查看是否安装成功
locust -h
# 运行 Locust 分布在多个进程/机器库
pip3 install pyzmq
# webSocket 压测库
pip3 install websocket-client
复制代码
编写压测脚本 test.py
from locust import HttpLocust, TaskSet, task
# 定义用户行为
class UserBehavior(TaskSet):
@task
def baidu_index(self):
self.client.get("/")
class WebsiteUser(HttpLocust):
task_set = UserBehavior # 指向一个定义的用户行为类
min_wait = 3000 # 执行事务之间用户等待时间的下界(单位:毫秒)
max_wait = 6000 # 执行事务之间用户等待时间的上界(单位:毫秒)
复制代码
locust -f test.py --host=https://www.baidu.com
复制代码
访问 http://localhost:8089 进入压测首页
Number of users to simulate 模拟用户数
Hatch rate (users spawned/second) 每秒钟增长用户数
点击 "Start swarming" 进入压测页面
压测界面右上角有:被压测的地址、当前状态、RPS、失败率、开始或重启按钮
性能测试参数
Type
请求的类型,例如GET/POST
Name
请求的路径
Request
当前请求的数量
Fails
当前请求失败的数量
Median
中间值,单位毫秒,请求响应时间的中间值
Average
平均值,单位毫秒,请求的平均响应时间
Min
请求的最小服务器响应时间,单位毫秒
Max
请求的最大服务器响应时间,单位毫秒
Average size
单个请求的大小,单位字节
Current RPS
表明吞吐量(Requests Per Second的缩写),指的是某个并发用户数下单位时间内处理的请求数。等效于QPS,其实能够看做同一个统计方式,只是叫法不一样而已。
Apache JMeter是Apache组织开发的基于Java的压力测试工具。用于对软件作压力测试,它最初被设计用于Web应用测试,但后来扩展到其余测试领域。 JMeter可以对应用程序作功能/回归测试,经过建立带有断言的脚原本验证你的程序返回了你指望的结果。
访问 jmeter-plugins.org/install/Ins… 下载解压之后便可使用
JMeter的功能过于强大,这里暂时不介绍用法,能够查询相关文档使用(参考文献中有推荐的教程文档)
顾名思义就是将压测脚本部署在云端,经过云端对对咱们的应用进行全方位压测,只须要配置压测的参数,无需准备实体机,云端自动给咱们分配须要压测的云主机,对被压测目标进行压测。
云压测的优点:
固然了云压测是一款商业产品,在使用的时候天然仍是须要收费的,并且价格仍是比较昂贵的~
PTS(Performance Testing Service)是面向全部技术背景人员的云化测试工具。有别于传统工具的繁复,PTS以互联网化的交互,提供性能测试、API调试和监测等多种能力。自研和适配开源的功能均可以轻松模拟任意体量的用户访问业务的场景,任务随时发起,免去繁琐的搭建和维护成本。更是紧密结合监控、流控等兄弟产品提供一站式高可用能力,高效检验和管理业务性能。
阿里云一样仍是支持渗透测试,经过模拟黑客对业务系统进行全面深刻的安全测试。
经过建立虚拟机器人模拟多用户的并发场景,提供一整套完整的服务器压测解决方案
go-stress-testing 是go语言实现的简单压测工具,源码开源、支持二次开发,能够压测http、webSocket请求,使用协程模拟单个用户,能够更高效的利用CPU资源。
Usage of ./go_stress_testing_mac:
-c uint
并发数 (default 1)
-d string
调试模式 (default "false")
-n uint
请求总数 (default 1)
-p string
curl文件路径
-u string
请求地址
-v string
验证方法 http 支持:statusCode、json webSocket支持:json (default "statusCode")
复制代码
-n
是单个用户请求的次数,请求总次数 = -c
* -n
, 这里考虑的是模拟用户行为,因此这个是每一个用户请求的次数
使用示例:
# 查看用法
go run main.go
# 使用请求百度页面
go run main.go -c 1 -n 100 -u https://www.baidu.com/
# 使用debug模式请求百度页面
go run main.go -c 1 -n 1 -d true -u https://www.baidu.com/
# 使用 curl文件(文件在curl目录下) 的方式请求
go run main.go -c 1 -n 1 -p curl/baidu.curl.txt
# 压测webSocket链接
go run main.go -c 10 -n 10 -u ws://127.0.0.1:8089/acc
复制代码
curl是Linux在命令行下的工做的文件传输工具,是一款很强大的http命令行工具。
使用curl文件能够压测使用非GET的请求,支持设置http请求的 method、cookies、header、body等参数
chrome 浏览器生成 curl文件,打开开发者模式(快捷键F12),如图所示,生成 curl 在终端执行命令
生成内容粘贴到项目目录下的curl/baidu.curl.txt文件中,执行下面命令就能够从curl.txt文件中读取须要压测的内容进行压测了
# 使用 curl文件(文件在curl目录下) 的方式请求
go run main.go -c 1 -n 1 -p curl/baidu.curl.txt
复制代码
具体需求能够查看项目源码
项目目录结构
|____main.go // main函数,获取命令行参数
|____server // 处理程序目录
| |____dispose.go // 压测启动,注册验证器、启动统计函数、启动协程进行压测
| |____statistics // 统计目录
| | |____statistics.go // 接收压测统计结果并处理
| |____golink // 创建链接目录
| | |____http_link.go // http创建链接
| | |____websocket_link.go // webSocket创建链接
| |____client // 请求数据客户端目录
| | |____http_client.go // http客户端
| | |____websocket_client.go // webSocket客户端
| |____verify // 对返回数据校验目录
| | |____http_verify.go // http返回数据校验
| | |____websokcet_verify.go // webSocket返回数据校验
|____heper // 通用函数目录
| |____heper.go // 通用函数
|____model // 模型目录
| |____request_model.go // 请求数据模型
| |____curl_model.go // curl文件解析
|____vendor // 项目依赖目录
复制代码
这里使用go-stress-testing对go server进行压测(部署在同一台机器上),并统计压测结果
CPU: 4核 (Intel Xeon(Cascade Lake) Platinum 8269 2.5 GHz/3.2 GHz)
内存: 16G 硬盘: 20G SSD 系统: CentOS 7.6
go version: go1.12.9 linux/amd64
package main
import (
"log"
"net/http"
)
const (
httpPort = "8088"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU() - 1)
hello := func(w http.ResponseWriter, req *http.Request) {
data := "Hello, World!"
w.Header().Add("Server", "golang")
w.Write([]byte(data))
return
}
http.HandleFunc("/", hello)
err := http.ListenAndServe(":"+httpPort, nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
复制代码
./go_stress_testing_linux -c 100 -n 10000 -u http://127.0.0.1:8088/
复制代码
并发数 | go_stress_testing QPS |
---|---|
1 | 6394.86 |
4 | 16909.36 |
10 | 18456.81 |
20 | 19490.50 |
30 | 19947.47 |
50 | 19922.56 |
80 | 19155.33 |
100 | 18336.46 |
200 | 16813.86 |
从压测的结果上看:效果还不错,压测QPS有接近2W
- | ab | locust | Jmeter | go-stress-testing | 云压测 |
---|---|---|---|---|---|
实现语言 | C | Python | Java | Golang | - |
UI界面 | 无 | 有 | 有 | 无 | 无 |
优点 | 使用简单,上手简单 | 支持分布式、压测数据支持导出 | 插件丰富,支持生成HTML报告 | 项目开源,使用简单,没有依赖,支持webSocket压测 | 更加真实的模拟用户,支持更高的压测力度 |
这个世界上没有最好的,只有最适合的,工具千千万,选择一款适合你的才是最重要的
在实际使用中有各类场景,选择工具的时候就须要考虑这些:
明确你的目的,须要作什么压测、压测的目标是什么?
使用的工具你是否熟悉,你愿意花多大的成本了解它?
你是为了测试仍是想了解其中的原理?
工具是否能支持你须要压测的场景
以前写了一篇文章,基于websocket单台机器支持百万链接分布式聊天(IM)系统(不了解这个项目能够查看上一篇或搜索一下文章),这里咱们要实现单台机器支持100W链接的压测
目标:
说明:
gowebsocket 分布式聊天(IM)系统:
因为本身手上没有本身的服务器,因此须要临时购买的云服务器
压测服务器:
16台(稍后解释为何须要16台机器)
CPU: 2核 内存: 8G 硬盘: 20G 系统: CentOS 7.6
被压测服务:
1台
CPU: 4核 内存: 32G 硬盘: 20G SSD 系统: CentOS 7.6
被压测服务器须要保持100W长链接,客户和服务器端是经过socket通信的,每一个链接须要创建一个socket,程序须要保持100W长链接就须要单个程序能打开100W个文件句柄
# 查看系统默认的值
ulimit -n
# 设置最大打开文件数
ulimit -n 1040000
复制代码
这里设置的要超过100W,程序除了有100W链接还有其它资源链接(数据库、资源等链接),这里设置为 104W
centOS 7.6 上述设置不生效,须要手动修改配置文件
vim /etc/security/limits.conf
这里须要把硬限制和软限制、root用户和全部用户都设置为 1040000
core 是限制内核文件的大小,这里设置为 unlimited
# 添加一下参数
root soft nofile 1040000
root hard nofile 1040000
root soft nofile 1040000
root hard nproc 1040000
root soft core unlimited
root hard core unlimited
* soft nofile 1040000
* hard nofile 1040000
* soft nofile 1040000
* hard nproc 1040000
* soft core unlimited
* hard core unlimited
复制代码
注意:
/proc/sys/fs/file-max
表示系统级别的可以打开的文件句柄的数量,不能小于limits中设置的值
若是file-max的值小于limits设置的值会致使系统重启之后没法登陆
# file-max 设置的值参考
cat /proc/sys/fs/file-max
12553500
复制代码
修改之后重启服务器,ulimit -n
查看配置是否生效
因为linux端口的范围是 0~65535(2^16-1)
这个和操做系统无关,无论linux是32位的仍是64位的
这个数字是因为tcp协议决定的,tcp协议头部表示端口只有16位,因此最大值只有65535(若是每台机器多几个虚拟ip就能突破这个限制)
1024如下是系统保留端口,因此能使用的1024到65535
若是须要100W长链接,每台机器有 65535-1024 个端口, 100W / (65535-1024) ≈ 15.5,因此这里须要16台服务器
vim /etc/sysctl.conf
在文件末尾添加net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_mem = 786432 2097152 3145728
net.ipv4.tcp_rmem = 4096 4096 16777216
net.ipv4.tcp_wmem = 4096 4096 16777216
复制代码
配置解释:
ip_local_port_range
表示TCP/UDP协议容许使用的本地端口号 范围:1024~65000tcp_mem
肯定TCP栈应该如何反映内存使用,每一个值的单位都是内存页(一般是4KB)。第一个值是内存使用的下限;第二个值是内存压力模式开始对缓冲区使用应用压力的上限;第三个值是内存使用的上限。在这个层次上能够将报文丢弃,从而减小对内存的使用。对于较大的BDP能够增大这些值(注意,其单位是内存页而不是字节)tcp_rmem
为自动调优定义socket使用的内存。第一个值是为socket接收缓冲区分配的最少字节数;第二个值是默认值(该值会被rmem_default覆盖),缓冲区在系统负载不重的状况下能够增加到这个值;第三个值是接收缓冲区空间的最大字节数(该值会被rmem_max覆盖)。tcp_wmem
为自动调优定义socket使用的内存。第一个值是为socket发送缓冲区分配的最少字节数;第二个值是默认值(该值会被wmem_default覆盖),缓冲区在系统负载不重的状况下能够增加到这个值;第三个值是发送缓冲区空间的最大字节数(该值会被wmem_max覆盖)。在被压测服务器上启动Server服务(gowebsocket)
查看被压测服务器的内网端口
登陆上16台压测服务器,这里我提早把须要优化的系统作成了镜像,申请机器的时候就能够直接使用这个镜像(参数已经调好)
./go_stress_testing_linux -c 62500 -n 1 -u ws://192.168.0.74:443/acc
复制代码
62500*16 = 100W
正好能够达到咱们的要求
创建链接之后,-n 1
发送一个ping的消息给服务器,收到响应之后保持链接不中断
经过 gowebsocket服务器的http接口,实时查询链接数和项目启动的协程数
压测过程当中查看系统状态
# linux 命令
ps # 查看进程内存、cup使用状况
iostat # 查看系统IO状况
nload # 查看网络流量状况
/proc/pid/status # 查看进程状态
复制代码
压测之后,查看链接数到100W,而后保持10分钟观察系统是否正常
观察之后,系统运行正常、CPU、内存、I/O 都正常,打开页面都正常
压测完成之后的数据
查看goWebSocket链接数统计,能够看到 clientsLen链接数为100W,goroutine数量2000008个,每一个链接两个goroutine加上项目启动默认的8个。这里能够看到链接数知足了100W
从压测服务上查看链接数是否达到了要求,压测完成的统计数据并发数为62500,是每一个客户端链接的数量,总链接数: 62500*16=100W
,
链接数 | 内存 |
---|---|
10000 | 281M |
100000 | 2.7g |
200000 | 5.4g |
500000 | 13.1g |
1000000 | 25.8g |
100W链接时的查看内存详细数据:
cat /proc/pid/status
VmSize: 27133804 kB
复制代码
27133804/1000000≈27.1
100W链接,占用了25.8g的内存,粗略计算了一下,一个链接占用了27.1Kb的内存,因为goWebSocket项目每一个用户链接起了两个协程处理用户的读写事件,因此内存占用稍微多一点
若是须要如何减小内存使用能够参考 @Roy11568780 大佬给的解决方案
传统的golang中是采用的一个goroutine循环read的方法对应每个socket。实际百万链路场景中这是巨大的资源浪费,优化的原理也不是什么新东西,golang中同样也可使用epoll的,把fd拿到epoll中,检测到事件而后在协程池里面去读就好了,看状况读写分别10-20的协程goroutine池应该就足够了
至此,压测已经所有完成,单台机器支持100W链接已经知足~
到这里压测总算完成,本次压测花费16元巨款。
单台机器支持100W链接是实测是知足的,可是实际业务比较复杂,仍是须要持续优化~
本文经过介绍什么是压测,在什么状况下须要压测,经过单台机器100W长链接的压测实战了解Linux内核的参数的调优。若是以为现有的压测工具不适用,能够本身实现或者是改形成属于本身的本身的工具。
基于websocket单台机器支持百万链接分布式聊天(IM)系统
github 搜:link1st 查看项目 go-stress-testing