关注系统压力测试
发布于: 2020 年 07 月 21 日
进行系统压力测试用以评估接口的性能。在性能测试的过程中,主要关注以下压测指标:
并发数(concurrent -- N):同时发出请求的数量。
吞吐量(throughput -- QPS/TPS):每秒完成的请求数。
响应时间(response time -- MS/S):每个请求消耗的时间,通常关注,99%的响应时间;最长响应时间。
同时,测试过程应该监控一些指标:
CPU utilities:CPU使用率
CPU load: CPU load
Memory: 系统内存使用量
Network throughput: 网络吞吐率。
一个典型的压测指标:
图: 压测的吞吐率throughput
图:压测的响应时间
从吞吐率来看,随着并发用户的增加,系统吞吐率逐步升高,到达顶点C之后开始下降;到达D点系统崩溃,无法继续提供服务。
从响应时间来看,随着并发用户的增加,系统响应时间逐步缓慢提高,并发达到C点之后,系统响应时间增幅加大,到D点系统奔溃。
从图可以总结:
每个系统都有一个最大负载点C,在用户并发达到最大负载点之前,系统吞吐率随着并发增加而增加。
并发越大,响应时间越长。
一个健康的在线系统应该工作在B点左右,以保障系统有一定的负载,同时有一定的buffer, 不至于由于流量的波动冲垮系统。
写一个简单的性能测试工具:
package mainimport ( "flag" "fmt" "net/http" "sort" "sync" "time")var concurrent intvar url stringvar count intfunc 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 []*ReqResultfunc (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 statisticfunc 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.371495191sresponse time min=17ms max=69msResponse 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.989321msresponse time min=19ms max=256msResponse 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.46164msresponse time min=32ms max=73msResponse 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
划线
评论
复制
发布于: 2020 年 07 月 21 日阅读数: 62
麻辣
关注
还未添加个人签名 2018.10.13 加入
还未添加个人简介
评论