目录
压测的目的就是通过压测(模拟真实用户的行为),测算出机器的性能(单台机器的 QPS),从而推算出系统在承受指定用户数(100W)时,需要多少机器能支撑得住。压测以后通过优化程序的性能或准备充足的机器,来保证用户的体验。
-
压力测试:强度测试,测试一个系统的最大抗压能力,在强负载(大数据、高并发)的情况下,测试系统所能承受的最大压力,预估系统的瓶颈
-
并发测试:通过模拟很多用户同一时刻访问系统或对系统某一个功能进行操作,来测试系统的性能,从中发现问题(并发读写、线程控制、资源争抢)
-
耐久性测试:通过对系统在大负荷的条件下长时间运行,测试系统、机器的长时间运行下的状况,从中发现问题(内存泄漏、数据库连接池不释放、资源不回收)
-
QPS:每秒钟处理请求数量 (req/sec 请求数/秒 一段时间内总请求数/请求时间)
-
TPS:每秒钟处理事务数量(一个事务可能包括多个请求)
1. Benchmark 基准性能测试
(1)基准测试
验证方法在串行或者并行执行时的基准表现,了解代码的性能情况:
- 平均耗时
- 并发性能
- 内存分配情况
(2)执行参数
-bench=. # 指定基准测试函数名称
-benchtime=3s # 每一轮运行3秒
-benchtime=300x # 运行300次
-cpu=2,4 # 指定GOMAXPROCS的数量,模拟多核。分别2核和4核运行一次测试
-benchmem # 显示堆内存分配情况,分配的越多越影响性能
-cpuprofile=cpu.pprof # 生成cpu.pprof文件以进行pprof分析
(3)一个简单的串行测试
func BenchmarkReverse(b *testing.B) {
for n := 0; n < b.N; n++ {
Reverse("abcdefg")
}
}
执行:
go test -v -run=none -bench=BenchmarkReverse
结果:
BenchmarkReverse-8 98738337 12.08 ns/op
GOMAXPROCS即cpu核数 执行次数 平均执行时间12.08ns
指定cpu核数执行:
go test -v -run=none -bench=BenchmarkReverse -cpu=2
结果:
BenchmarkReverse-2 100000000 11.53 ns/op
由于是串行执行所以cpu对结果没影响。
(4)并行测试
func BenchmarkReverse_Parallel(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Reverse("abcdefg")
}
})
}
执行:
go test -v -run=none -bench=BenchmarkReverse -cpu=2,4,8
结果:
BenchmarkReverse-2 100000000 11.59 ns/op
BenchmarkReverse-4 100000000 11.49 ns/op
BenchmarkReverse-8 100000000 11.49 ns/op
BenchmarkReverse_Parallel-2 198732458 5.972 ns/op
BenchmarkReverse_Parallel-4 350899080 3.703 ns/op
BenchmarkReverse_Parallel-8 468575274 2.682 ns/op
其并发数默认是GOMAXPROCS
可以看到,执行次数随着并发数增加而增加,平均执行时间随着并发数增加而减小
(5)查看内存分配
执行:
go test -v -run=none -bench=BenchmarkArrayReverse -benchmem
结果:
BenchmarkArrayReverse-8 10122477 117.9 ns/op 120 B/op 4 allocs/op
8核数运行 执行次数 平均运行时间 平均每次执行占用内存 平均每次执行分配内存的次数
2. pprof
-
CPU Profiling:CPU 分析
-
Memory Profiling:内存分析
-
Block Profiling:阻塞分析,分析 goroutine 阻塞等待同步(包括定时器通道)的情况
-
Mutex Profiling:互斥锁分析,分析互斥锁的竞争情况
-
工具型:普通代码性能分析, runtime/pprof,github.com/pkg/profile (封装了runtime/pprof)
-
服务型:web服务器性能分析,net/http/pprof
brew install graphviz
普通代码性能分析
(1)CPU分析
import "github.com/pkg/profile"
func main() {
// 开启cpu监控
defer profile.Start(profile.CPUProfile).Stop()
// 业务逻辑
do()
}
运行 go run main.go 将生成文件cpu.pprof 到临时目录
输出文件位置:
2023/12/21 16:07:38 profile: cpu profiling enabled, /var/folders/1d/xxx/cpu.pprof
可以在浏览器查看分析:
go tool pprof -http=:9999 /xxx/cpu.pprof
或者命令行查看:
go tool pprof /xxx/cpu.pprof
(pprof) top // 查看分析情况
(pprof) top --cum // 按累计消耗cum排序
(2)内存分析
defer profile.Start(profile.MemProfile, profile.MemProfileRate(1)).Stop()
(3)阻塞、互斥锁、goroutine分析
- 阻塞分析:
用于了解程序在等待操作系统或网络调用时所花费的时间
defer profile.Start(profile.BlockProfile).Stop()
- 互斥锁分析
用于了解程序中哪些地方有竞争条件(mutexes)或死锁
defer profile.Start(profile.MutexProfile).Stop()
- goroutine分析
用于了解程序中当前运行和停止的 Goroutine 的数量
defer profile.Start(profile.GoroutineProfile).Stop()
(4)Benchmark生成pprof
go test -v -run=none -bench=BenchmarkReverse -cpuprofile=cpu.pprof
将在目录下生成cpu.pprof
可以进行cpu分析
go tool pprof -http=:9999 cpu.pprof
web服务性能分析
(1)在go原生http框架使用pprof
import (
"fmt"
"net/http"
_ "net/http/pprof"
)
func HelloWorld(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello world")
}
func main() {
http.HandleFunc("/", HelloWorld)
err := http.ListenAndServe(":9210", nil)
if err != nil {
fmt.Println(err)
}
}
启动服务后直接访问pprof: http://127.0.0.1:9210/debug/pprof/
(2)在gin框架使用pprof
import (
"fmt"
"net/http"
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
pprof.Register(r)
web := r.Group("/golang/web")
ginMain(web)
if err := r.Run(":9210"); err != nil {
panic(err)
}
}
func ginMain(r *gin.RouterGroup) {
ginGroup := r.Group("/gin") //gin框架前缀
{
ginGroup.GET("/", func(c *gin.Context) {
fmt.Println("hello Gin")
c.String(http.StatusOK, "欢迎来到三体世界")
})
}
}
启动服务后直接访问pprof: http://127.0.0.1:9210/debug/pprof/
(3)使用火焰图分析cpu性能
// 安装go-torch
go install github.com/uber/go-torch
// 安装flamegraph
cd $GOOT/pkg/mod/github.com/uber/go-torch // go-torch安装位置
git clone https://github.com/brendangregg/FlameGraph.git
cp FlameGraph/flamegraph.pl /usr/local/bin
采集数据,监控一段时间:
go-torch -u http://127.0.0.1:9210 -t 60
-u 为pprof监控的url,-t为采集数据的时间
监控完成会生成.svg文件,用浏览器打开分析
(4)分析内存性能
curl -s http://127.0.0.1:9210/debug/pprof/heap > t1.heap
过一段时间:
curl -s http://127.0.0.1:9210/debug/pprof/heap > t2.heap
比较差异:
go tool pprof --http :9999 --base t1.heap t2.heap
用浏览器打开:9999 分析
3. abtest
ab 属于一个轻量级的压测工具,结果不会特别准确,可以用作参考。
(1)安装
sudo apachectl -v
sudo apachectl start // 启动apache
打开浏览器,输入http://localhost测试是否正常
(2)命令参数
-n requests #执行的请求数
-c concurrency #请求并发数
-s timeout #指定每个请求的超时时间,默认30s
-k #启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求。默认不启用
-r #请求错误时不退出
-T content-type #post或put请求
-H attribute #header请求头
-p postfile #post请求携带的body文件
-u putfile #put请求携带的data文件
(3)执行
对baidu请求100次,并发数3
ab -n 100 -c 3 https://www.baidu.com/
输出:
Concurrency Level: 3 // 并发数
Time taken for tests: 7.217 seconds // 总耗时
Complete requests: 100 // 请求成功数
Failed requests: 0 // 请求失败数
Total transferred: 136096 bytes
HTML transferred: 22700 bytes
Requests per second: 13.86 [#/sec] (mean) // qps, 每秒处理的请求数
Time per request: 216.520 [ms] (mean)
Time per request: 72.173 [ms] (mean, across all concurrent requests)
Transfer rate: 18.41 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 130 158 12.5 158 193
Processing: 38 52 18.1 48 217
Waiting: 38 52 18.1 48 217
Total: 178 210 21.9 207 369
Percentage of the requests served within a certain time (ms)
50% 207 // 50%的请求在207ms内返回
66% 215
75% 219
80% 224
90% 229
95% 234
98% 256
99% 369
100% 369 (longest request)
如何执行一个post请求:
ab -n 100 -c 10 -T "application/json" -H "Content-Type: application/json" -p ./req.json http://localhost:8088/api/hello