关注系统压力测试

用户头像
麻辣
关注
发布于: 2020 年 07 月 21 日

进行系统压力测试用以评估接口的性能。在性能测试的过程中,主要关注以下压测指标:

  1. 并发数(concurrent -- N):同时发出请求的数量。

  2. 吞吐量(throughput -- QPS/TPS):每秒完成的请求数。

  3. 响应时间(response time -- MS/S):每个请求消耗的时间,通常关注,99%的响应时间;最长响应时间。

同时,测试过程应该监控一些指标:

CPU utilities:CPU使用率

CPU load: CPU load

Memory: 系统内存使用量

Network throughput: 网络吞吐率。



一个典型的压测指标:

图: 压测的吞吐率throughput

图:压测的响应时间



从吞吐率来看,随着并发用户的增加,系统吞吐率逐步升高,到达顶点C之后开始下降;到达D点系统崩溃,无法继续提供服务。

从响应时间来看,随着并发用户的增加,系统响应时间逐步缓慢提高,并发达到C点之后,系统响应时间增幅加大,到D点系统奔溃。



从图可以总结:

  1. 每个系统都有一个最大负载点C,在用户并发达到最大负载点之前,系统吞吐率随着并发增加而增加。

  2. 并发越大,响应时间越长。

一个健康的在线系统应该工作在B点左右,以保障系统有一定的负载,同时有一定的buffer, 不至于由于流量的波动冲垮系统。



写一个简单的性能测试工具:



package main
import (
"flag"
"fmt"
"net/http"
"sort"
"sync"
"time"
)
var concurrent int
var url string
var count int
func init() {
flag.IntVar(&concurrent, "c", 1, "the concurrent value, default=1")
flag.StringVar(&url, "url", "", "the url, can not be empty")
flag.IntVar(&count, "n", 100, "how many requests to send totally, default=100")
flag.Parse()
}
type ReqResult struct {
code int
err error
duration time.Duration
}
func (s *ReqResult) String() string {
return s.duration.Round(time.Millisecond).String()
}
func request(url string, wg *sync.WaitGroup, reader chan struct{}, resultCollector chan *ReqResult) {
defer wg.Done()
client := http.Client{}
client.Timeout = 10 * time.Second
for range reader {
s := time.Now()
if res, err := client.Get(url); err != nil {
resultCollector <- &ReqResult{duration: time.Now().Sub(s), code: 0, err: err}
} else {
resultCollector <- &ReqResult{duration: time.Now().Sub(s), code: res.StatusCode, err: err}
}
//<-time.After(10 * time.Millisecond)
//resultCollector <- &ReqResult{duration: time.Now().Sub(s), code: 200, err: nil}
}
}
func doStatistic(result *[]*ReqResult, reader chan *ReqResult, wg *sync.WaitGroup) {
defer wg.Done()
for r := range reader {
*result = append(*result, r)
}
}
func withDuration(do func()) time.Duration {
s := time.Now()
do()
return time.Now().Sub(s)
}
func main() {
result := make([]*ReqResult, 0, count)
dispatch := make(chan struct{}, concurrent)
resultCollector := make(chan *ReqResult, concurrent)
// start a statistic thread.
//start workers according to concurrent.
wg2 := sync.WaitGroup{}
wg2.Add(1)
go doStatistic(&result, resultCollector, &wg2)
wg := sync.WaitGroup{}
for i := 0; i < concurrent; i++ {
wg.Add(1)
go request(url, &wg, dispatch, resultCollector)
}
//set time used all
timeAll := withDuration(func() {
for i:=0; i < count; i++ {
dispatch <- struct{}{}
}
close(dispatch)
//wait all thread complete
wg.Wait()
})
close(resultCollector)
wg2.Wait()
// print stats
printStats(result, timeAll)
}
type SortType []*ReqResult
func (s SortType) Less(i int, j int) bool {return s[i].duration < s[j].duration}
func (s SortType) Len() int { return len(s) }
func (s SortType) Swap(i int, j int) {
s[i], s[j] = s[j], s[i]
}
// print last statistic
func printStats(result []*ReqResult, timeAll time.Duration) {
nerr := 0
for _, v := range result {
if v.err != nil || v.code != 200 {
nerr ++
}
}
sort.Sort(SortType(result))
fmt.Printf("\n request count = %d", len(result))
fmt.Printf("\n error count = %d\n", nerr)
fmt.Printf("\n throughput = %d used time = %s\n", int64(len(result)*1000)/timeAll.Milliseconds(), timeAll)
fmt.Printf("\nresponse time min=%s max=%s\n", result[0].duration.Round(time.Millisecond), result[len(result) - 1].duration.Round(time.Millisecond))
for i := 1; i < 10; i++ {
idx := (len(result) - 1) * i * 10 / 100
v := result[idx]
for ;idx < len(result) - 2; {
if result[idx+1].duration.Round(time.Millisecond) > v.duration.Round(time.Millisecond) {
break
}
v = result[idx]
idx ++
}
fmt.Printf("Response time %3d%% ====== %s \n", (idx+1)*100/len(result), v)
i = (idx+1) / 10
}
fmt.Printf("Response time %3d%% ====== %s \n", 99, result[(len(result)-1) * 99/100 ])
fmt.Printf("Response time %3d%% ====== %s \n", 100, result[len(result)-1])
}



运行结果

go run . -url http://www.baidu.com -n 100 -c 2
request count = 100
error count = 0
throughput = 72 used time = 1.371495191s
response time min=17ms max=69ms
Response time 16% ====== 22ms
Response time 22% ====== 23ms
Response time 33% ====== 24ms
Response time 47% ====== 25ms
Response time 58% ====== 26ms
Response time 71% ====== 27ms
Response time 80% ====== 28ms
Response time 90% ====== 32ms
Response time 99% ====== 46ms
Response time 100% ====== 69ms
MPRdeMacBook-Pro:performancetool develper$ go run . -url http://www.baidu.com -n 100 -c 8
request count = 100
error count = 0
throughput = 153 used time = 652.989321ms
response time min=19ms max=256ms
Response time 13% ====== 35ms
Response time 25% ====== 40ms
Response time 30% ====== 41ms
Response time 42% ====== 43ms
Response time 50% ====== 46ms
Response time 65% ====== 49ms
Response time 71% ====== 51ms
Response time 81% ====== 54ms
Response time 92% ====== 61ms
Response time 99% ====== 113ms
Response time 100% ====== 256ms
go run . -url http://www.baidu.com -n 100 -c 5
request count = 100
error count = 0
throughput = 102 used time = 975.46164ms
response time min=32ms max=73ms
Response time 11% ====== 38ms
Response time 21% ====== 41ms
Response time 30% ====== 43ms
Response time 45% ====== 45ms
Response time 50% ====== 46ms
Response time 60% ====== 49ms
Response time 71% ====== 53ms
Response time 81% ====== 55ms
Response time 91% ====== 59ms
Response time 99% ====== 72ms
Response time 100% ====== 73ms



用户头像

麻辣

关注

还未添加个人签名 2018.10.13 加入

还未添加个人简介

评论

发布
暂无评论
关注系统压力测试