《架构师训练营》第七周命题作业

发布于: 2020 年 07 月 18 日

1、性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?

  • 压测初期,系统资源在可以接受的范围内,此时系统响应时间会相对比较稳定不会随并发压力的增加而增加,吞吐量会随并发数的增加而增加。

  • 持续增加并发压力,到达系统资源使用的临界值,系统响应时间会逐渐变长,吞吐量逐渐边少,直至系统崩溃。

2、压测工具

2.1 代码实现

使用 go 语言开发,程序设计思路如下:

  • 使用 goruntine 模拟并发请求,用一个 goruntine 等待其他并发的处理结果,通过 channel 将请求结果发送到负责处理结果的 goruntine 统计、处理。

request

request 用来发送请求,只关心请求有没有成功。

func request(url string) error {
response, err := http.Get(url)
defer func() {
if response != nil && response.Body != nil {
_ = response.Body.Close()
}
}()
if err != nil {
return err
}
if response.StatusCode != http.StatusOK {
return errors.New(fmt.Sprintf("Error response code: %d", response.StatusCode))
}
return nil
}
runner

runner 用来顺序执行指定个数的请求,并将结果通过 channel 发送出去

type Response struct {
label string
elapsed int64
err error
}
func runner(count int, url string, resChan chan Response, wg *sync.WaitGroup, label string) {
for i := 0; i < count; i++ {
start := time.Now()
err := request(url)
elapsed := time.Since(start)
resChan <- Response{
elapsed: elapsed.Milliseconds(),
err: err,
label: fmt.Sprintf("%s-%d", label, i),
}
}
wg.Done()
}
receiver

receiver 用来接收、统计请求结果

func receiver(recvChan chan Response) {
var (
resArr []Response
totalCount, successCount, failedCount int
totalTime, _95TotalTime int64
)
for {
totalCount++
res, ok := <-recvChan
if !ok {
break
}
if res.err != nil {
failedCount++
} else {
successCount++
}
totalTime += res.elapsed
log.Printf("[%s\t%d\t]\tResponse takes %dms", res.label, totalCount, res.elapsed)
resArr = append(resArr, res)
}
log.Printf("Toal success count: %d, failed count: %d", successCount, failedCount)
log.Printf("Average time: %dms", totalTime/int64(totalCount))
sort.Slice(resArr, func(i, j int) bool {
return resArr[i].elapsed < resArr[j].elapsed
})
_95Count := totalCount * 95 / 100
for i := 0; i < _95Count; i++ {
_95TotalTime += resArr[i].elapsed
}
log.Printf("95%% average time: %dms", _95TotalTime/int64(_95Count))
}
LoadRun

LoadRun 用来启动测试

func LoadRun(currency, count int, url string) {
wg := sync.WaitGroup{}
wg.Add(currency)
resChan := make(chan Response, 10)
for i := 0; i < currency; i++ {
label := fmt.Sprintf("goroutine-%d", i)
go runner(count, url, resChan, &wg, label)
}
go receiver(resChan)
wg.Wait()
close(resChan)
time.Sleep(time.Second)
}

2.2 测试结果

// https://www.baidu.com
2020/07/18 14:30:34 Toal success count: 1000, failed count: 0
2020/07/18 14:30:34 Average time: 344ms
2020/07/18 14:30:34 95% average time: 333ms
// https://www.163.com
2020/07/18 14:45:34 Toal success count: 0, failed count: 1000
2020/07/18 14:45:34 Average time: 374ms
2020/07/18 14:45:34 95% average time: 361ms
// https://www.qq.com
2020/07/18 14:47:12 Toal success count: 1000, failed count: 0
2020/07/18 14:47:12 Average time: 375ms
2020/07/18 14:47:12 95% average time: 334ms
// https://www.taobao.com
2020/07/18 14:49:08 Toal success count: 1000, failed count: 0
2020/07/18 14:49:08 Average time: 838ms
2020/07/18 14:49:08 95% average time: 793ms

用户头像

关注

还未添加个人签名 2018.06.14 加入

还未添加个人简介

评论

发布
暂无评论
《架构师训练营》第七周命题作业