现在在工作中开始搞 Go 了,重构了一个工具,查了一波如何做性能测试,就当记个笔记。

首先搜索了一下如何给 HTTP server 做压力测试,看了看 wrk 。

wrk 是一个简单的 HTTP server 性能测试工具,使用方式比较简单,只需要安装后命令行跑一跑就可以对 HTTP server 进行压力测试。

wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html

这条命令是跑一个 benchmark,持续 30s,用 12 个 thread,保持 400 个 HTTP 连接。

不仅如此,wrk 还支持写 lua 脚本自定义请求。

-- example HTTP POST script which demonstrates setting the

-- HTTP method, body, and adding a header

wrk.method = "POST"

wrk.body = "foo=bar&baz=quux"

wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

我当时需要使用的 method 是 PUT,直接无脑换上也是可以使用,写起来很简单。

使用了一下,感觉作为一个普通的性能测试工具是可以的,但是不符合我的使用场景,我所做的工具是开一个 HTTP server,一个 websocket server,HTTP server 负责接收数据,websocket server 负责把接收到的发给订阅的 client。所以仅凭 HTTP server 能扛得住请求是不够的,需要验证到底消息有没有走通。所以 wrk 这条路可行,但是要定制更多的 script。

2.  Go 的 Benchmark 工具

Go 有自己的 unit test 和 Benchmark 的工具,见 https://golang.org/pkg/testing/

看了看使用方法,虽然是 Benchmark 工具,但是测试数据的准备、函数的调用方式和结果的判定基本上还是需要自己来定制一下。于是粗略地写了几个函数,分别用于启动 HTTP server 和 websocket server,准备测试数据,发送消息和接收消息。写了一个 BenchmarkHTTP 来大概检测了一下是否可以调用这几个函数来判断是否可行,嗯可行。

3. Go 的 profiling 工具

在第二步走通了测试方法,粗略地检测了一下性能,让人很遗憾地发现大概只有 1500 的 QPS。于是想了一下是不是 go 有 profiling 工具检查一下到底是谁用的时间长。找了找还真有 https://golang.org/pkg/net/http/pprof/ 。另外还有 runtime 的 pprof https://golang.org/pkg/runtime/pprof/ 。

具体做法也很简单

import _ "net/http/pprof"

go func() {

log.Println(http.ListenAndServe("localhost:6060", nil))

}()

看 heap 的使用情况

30s 内 CPU 的使用情况

收集 5s 内的 trace

在经过分析和 review 代码的时候,发现 map 的所有操作都没有加锁这一隐患,于是加锁,调整测试代码,再跑,QPS 终于到了一个令人信服的结果。