目的
提到压测这两个字的概念,可能很多人,第一脑海里就是找到峰值,做好资源申请以及优化。记得在《成为极少数》的这本书里看过一句这样话,大概是意思是:很多时候,做一件事情,把目标明确了,也许我们就成功了一半,后续就是无限围绕目标做无限的接近和自我约束。如果我们把目标更明确的话,这样就能更好全链路压测以分析到自己的服务。因此笔者认为压测主要目的可以细化到这几个点:
探知系统峰值大小
服务优系统化提供可靠的数据支撑
了解上下游服务的强依赖关系以及其服务承载能力
全链路限流熔断设计
输出服务治理和保障的方案
资源采购以及成本优化
服务监控和告警阈值设计
压测方案
生产环境压测
首先需要明确一点,如果测试环境的节点配置以及数据存储层的配置不一样的话,在测试环境的压测意义并不大,在测试环境的压测除了提供一下服务的代码优化的数据支撑外,其他数据的参考价值并不大。既然要在生产环境压测,我们首先需要考考虑两个点:
压测的时候不会影响到线上服务正常运行
这里笔者在工作中,通常采用用户数据量较少的时候(凌晨),对单台节点进行压测,这样就可以保障最小限度的影响线上用户;当然,如果时间和资源允许的情况下,可以搭建一套副本服务,但是一般由于依赖了其他的服务,尤其是跨部门,推进其他部门一起搭建的一套压测环境的时候,是很难推进的。
压测的数据不影响到线上的数据存储
数据隔离能力是全链路压测的核心基础。由于压测的数据大部分都是伪造的假数据,如果这些数据写入缓存以及数据库,对于线上查询以及缓存命中会产生很大的影响,尤其是对于存储有限的缓存中,压测会导致大量的有效热数据被淘汰,而缓存了一些无效的数据。,针对这样的问题,笔者采取的方案很类似 AB 测的方案;
request.headers.set('flow_type', 'test'); //设置灰度压测参数
复制代码
// 在cookie中种入压测标示
Cookie cookie = new Cookie("flow_type","test");
复制代码
具体方案如下:
采取上述的方案,我们就可以做到了压测的大量无效数据不对线上的缓存,数据库以及日志造成过多的影响
压测安全保障
由于压测过程中,我们不断在试探服务的水位,如果存存在下游的服务话,我们需要考虑到下游服务的承载能力,这样我们就需要大致了解下游服务的上限以及做好熔断降级。
当达到容量瓶颈或出现预期外情况时,从施压端到被压端都可以自动熔断。以最大程度避免风险隐患,尤其是对下游服务安全,一旦压测打挂下游服务的话,在工作中也许就是事故。对于降级的组件,多数公司都会自己实现一套,如果开源的话:Hystrix 和 Sentinel。好像 Hystrix 官方已经放弃维护。
针对熔断器是否生效,笔者建议在测试环境,先进行验证,确保生产环境限流器有效。
流量存储预估
在压测中,我们需要对服务的最高流量进行预估,方可知道大概需要多少节点资源,这样也尽可能的节约成本,避免盲目的扩容;
请求量级预估
一般我们按照一天流量的峰值一般会 50%的流量集中在 2 小时区间,最高的峰值按 5 倍冗余,所以我们峰值的每秒请求是:
峰值 QPS =(Total*50%)/(60*60*2)*5
事物量级预估
以订单为例,我们按照一般峰值的 20%的流量才会进入真正的购买阶段,所以我们可以预估 TPS 的请求峰值在是:
峰值 TPS = 峰值 QPS*20%
压测链路
提到链路压测,也许很多人有疑问,压测不是都是从客户端请求到服务的入口这个链路全程链路压测,为什么还要做非全链路压测。
笔者认为一个服务的水位往往取决于你系统服务最短的那块短板。为了更好的找到目前整个系统的服务的瓶颈,我们更需要对于微服务的 PRC 接口做单链路压测,在单链路压测的提供数据,我们能更好的对当前瓶颈做优化;譬如如果依赖的下游服务存在瓶颈,我们是否可以同步转异步的方式调用,或者如果数据的强一致性不高,可以采用缓存的方式;
压测工具选型
由于笔者本身仅仅接触了 2 类压力测试工具:
AB
安装
yum -y install httpd-tools
复制代码
常用命令参数解释
-n: 标识请求的总数.
-c: 标识请求的总用户 (如果请求的总数是 1000,请求的总用户是 10,那么平均每个用户执行 100 次请求)
-t: 限制请求的超时时间, 单位是秒.
更多命令行可以查看帮助
ab -help
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
-B address Address to bind to when making outgoing connections
-p postfile File containing data to POST. Remember also to set -T
-u putfile File containing data to PUT. Remember also to set -T
-T content-type Content-type header to use for POST/PUT data, eg.
'application/x-www-form-urlencoded'
Default is 'text/plain'
-v verbosity How much troubleshooting info to print
-w Print out results in HTML tables
-i Use HEAD instead of GET
-x attributes String to insert as table attributes
-y attributes String to insert as tr attributes
-z attributes String to insert as td or th attributes
-C attribute Add cookie, eg. 'Apache=1234'. (repeatable)
-H attribute Add Arbitrary header line, eg. 'Accept-Encoding: gzip'
Inserted after all normal header lines. (repeatable)
-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
-V Print version number and exit
-k Use HTTP KeepAlive feature
-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.
-e filename Output CSV file with percentages served
-r Don't exit on socket receive errors.
-m method Method name
-h Display usage information (this message)
-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)
复制代码
命令事例
ab -n100 -c 10 http://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: 80
Document Path: /
Document Length: 292117 bytes
Concurrency Level: 1
Time taken for tests: 0.133 seconds
Complete requests: 5
Failed requests: 3
(Connect: 0, Receive: 0, Length: 3, Exceptions: 0)
Write errors: 0
Total transferred: 1466673 bytes
HTML transferred: 1460553 bytes
Requests per second: 37.53 [#/sec] (mean)
Time per request: 26.644 [ms] (mean)
Time per request: 26.644 [ms] (mean, across all concurrent requests)
Transfer rate: 10751.53 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 3 3 0.4 4 4
Processing: 14 23 14.1 18 48
Waiting: 5 13 13.7 7 37
Total: 17 27 14.3 22 52
ERROR: The median and mean for the initial connection time are more than twice the standard
deviation apart. These results are NOT reliable.
Percentage of the requests served within a certain time (ms)
50% 21
66% 23
75% 23
80% 52
90% 52
95% 52
98% 52
99% 52
100% 52 (longest request)
复制代码
下面对常用的重要指标做一些解释
##并发请求数
Concurrency Level: 1
##整个测试持续的时间
Time taken for tests: 0.133 seconds
##完成的请求数
Complete requests: 5
##失败的请求数
Failed requests: 0
##整个场景中的网络传输量
Total transferred: 1466673 bytes
##整个场景中的HTML内容传输量
HTML transferred: 1460553 bytes
##吞吐率,大家最关心的指标之一,相当于 LR 中的每秒事务数,后面括号中的 mean 表示这是一个平均值
Requests per second: 37.53 [#/sec] (mean)
##用户平均请求等待时间,大家最关心的指标之二,相当于 LR 中的平均事务响应时间,后面括号中的 mean 表示这是一个平均值
Time per request: 26.644 [ms] (mean)
##服务器平均请求处理时间,大家最关心的指标之三
Time per request: 26.644 [ms] (mean, across all concurrent requests)
##平均每秒网络上的流量,可以帮助排除是否存在网络流量过大导致响应时间延长的问题
Transfer rate: 10751.53 [Kbytes/sec] received
##服务处理请求的SLA
Percentage of the requests served within a certain time (ms)
## 这里我们一般关注 TP99和TP90即可
99% 52 ##99%的请求在52ms处理完成
90% 52 ##90%的请求在52ms处理完成
复制代码
总结
总体来看 ab 压测工具基本能满足所以的 http 请求的压测数据,另外使用起来比较简单。当然 ab 存在的问题就是功能相对较少,具体会在下面于 wrk 对比后表哥罗列。
wrk
安装
git clone https://github.com/wg/wrk.git wrk
cd wrk
#本身是c写的,所以需要本地编译
make
# 把生成的wrk移到一个PATH目录下面, 比如
sudo cp wrk /usr/local/bin
复制代码
常用参数说明
-c:总的连接数(每个线程处理的连接数=总连接数/线程数)
-d:测试的持续时间,如2s(2second),2m(2minute),2h(hour),默认为s
-t:需要执行的线程总数,默认为2,一般线程数不宜过多. 核数的2到4倍足够了. 多了反而因为线程切换过多造成效率降低
-s:执行Lua脚本,这里写lua脚本的路径和名称,后面会给出案例
-H:需要添加的头信息,注意header的语法,举例,-H “token: abcdef”
这里很重要!这里就可以直接在header里面加染色体!!!!
—timeout:超时的时间
—latency:显示延迟统计信息
复制代码
命令事例
./wrk -t5 -c100 -d30s --latency http://www.baidu.com
复制代码
压测报告
Running 30s test @ http://www.baidu.com
5 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 599.14ms 236.89ms 1.97s 73.37%
Req/Sec 34.18 19.57 120.00 69.15%
Latency Distribution
50% 548.32ms
75% 715.09ms
90% 920.64ms
99% 1.33s
4607 requests in 30.10s, 1.26GB read
Socket errors: connect 0, read 0, write 0, timeout 101
Requests/sec: 153.07
Transfer/sec: 43.04MB
复制代码
重要指标分析
平均值 标准差 最大值 正负一个标准差占比
线程状态 Thread Stats Avg Stdev Max +/- Stdev
响应时间 Latency 168.45ms 265.72ms 1.48s 87.68%
每线程每秒完成请求数Req/Sec 25.78 26.22 120.00 86.55%
#SLA参数 TP99和TP90
Latency Distribution
90% 920.64ms
99% 1.33s
Requests/sec: 153.07 ##每秒请求数
Transfer/sec: 43.04MB ## 每秒传输数据
复制代码
整体上看 wrk 的结果相比 ab 内容更清晰简单
wrk 额外支持每一个请求的参数可以不一样,具体通过 luna 脚本实现,下面是一个 post 请求例子:
test_post.luna 脚本
wrk.method = "POST"
wrk.body = "test wrk post"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
复制代码
运行测试用例
./wrk -t5 -c5 -d5s --latency http://www.baidu.com -s test_post.lua
复制代码
基于 luan 脚本如何使用,笔者还是刚入门,后续会做一个 luna 的复杂的用法
ab vs wrk
简单对比两者,发现其实基本的核心指标数据都能输出,但是因为 wrk 可以借助 luna 的脚本,可以更灵活的控制每次请求的参数,尤其对于缓存命中之类的压力测试的时候,就更新灵活使用。这里还有一个很重要的区别就是 ab 是单线程的模式。
压测过程中,如果我们会发现两种工具中:cpu 的利用率 wrk 明显比 ab 要多,对比如下:
当我们的机器是多核的配置,ab 的压测数据会因为 cpu 的利用率而导致机器负载一直上不去,而输出了假数据,误以为服务系统已经达到了瓶颈。
综上来看,wrk 的压测相比 ab 的可用性更高,如果是压测中,公司没有自研的话,这里推进 wrk(基于 jmeter 由于受限于 Java 语言项目,这里就不做过多分析)
压测策略
也许很多人开始不知道怎么压测,不知道如果设置线程数和并发数,不知道如何找到系统的瓶颈,这里可以分享一下笔者的经验:
寻找最大线程数:
寻找 QPS 峰值:
总结展望
除此之外,在大多数时候如果要在压测过程中完全模拟真实业务场景,还需要做大量的功能调研与用户使用调研,尽可能实现场景的真实覆盖,只有越接近真实,才能尽早挖掘出系统的瓶颈和准确评估系统的性能指标。
评论