Golang微服务如何进行压测_微服务压力测试方法

14次阅读

微服务压测需分层隔离、控制变量、复现真实链路;单接口基准测试(go test -bench)仅验证handler逻辑,须禁用日志、mock外部依赖;真实链路压测应使用vegeta或wrk并禁用连接复用;gRPC压测推荐ghz;必须边压边采pprof数据,三次压测取中位数且每次清缓存、重启服务、GC两次。

Golang微服务如何进行压测_微服务压力测试方法

微服务压测不能只看单个接口吞吐量,必须分层隔离、控制变量、复现真实链路——否则你压的不是服务,是运气。

go test -bench 测单个 handler,但别信它能代表线上表现

内置基准测试适合验证 http handler 逻辑是否高效,比如 http.HandlerFunc 内部无锁计算、无阻塞 IO。但它跑在内存网络(httptest.NewRecorder + httptest.NewRequest)上,绕过了 TCP 、TLS、反向代理、连接池等真实瓶颈点。

  • 务必调用 b.ResetTimer(),否则初始化开销(如路由注册、中间件构造)会污染结果
  • 禁用日志:在 Benchmark 函数开头加 log.SetOutput(io.Discard),否则 log.printf 会显著拖慢延迟
  • 避免依赖外部状态:数据库redis、gRPC 调用必须 mock,否则结果不可控也不可复现
func BenchmarkUserHandler(b *testing.B) { 	log.SetOutput(io.Discard) 	req := httptest.NewRequest("GET", "/api/user/123", nil) 	w := httptest.NewRecorder() 	b.ResetTimer() 	for i := 0; i < b.N; i++ { 		userHandler(w, req) // 纯内存处理 	} }

vegetawrk 压真实 HTTP 接口,但要关掉连接复用

真实链路压测必须走完整网络,且禁用客户端连接复用(DisableKeepAlives: true),否则会掩盖服务端连接池、TIME_WaiT、accept 队列溢出等问题。

  • wrk 启动命令示例:wrk -c 200 -d 30s -t 4 --timeout 5s -H "Connection: close" http://localhost:8080/api/users
  • vegeta 更适合带 body 和 header 的场景,例如:echo "POST http://localhost:8080/api/login" | vegeta attack -body login.json -header "Content-Type: application/json" -rate 100 -duration 30s -timeout 5s | vegeta report
  • 所有工具压测机与服务端必须物理或网络隔离,避免 CPU/网卡争抢

压 gRPC 微服务?别手写 goroutine,用 ghzgrpc-go 自带 benchmark 模式

gRPC 压测难点在于连接管理、流控、Metadata 透传和 TLS 握手开销。手写 goroutine 容易误用 grpc.Dial(每 goroutine 新建连接 → 打爆服务端 fd)、忽略 WithBlock() 导致阻塞、或漏设 WithTimeout 造成统计失真。

立即学习go语言免费学习笔记(深入)”;

  • 推荐 ghz:支持 QPS 控制、并发连接数、自定义 metadata,输出含 P90/P99 延迟和错误码分布
  • 若需深度定制(如模拟 Token 过期重试),才用 Go client + sync.WaitGroup + semaphore 控制并发,且每个 goroutine 复用同一个 *grpc.ClientConn
  • 服务端必须开启 grpc.StatsHandler 并暴露 /debug/requests,否则无法区分是网络抖动还是服务内部卡顿

压测中采集 pprof 数据,但别等压完再抓——要边压边采

一次压测不配合 profile,等于没压。CPU、goroutine、block、mutex 四类 profile 必须在压测峰值时实时采集,否则火焰图里全是“平地”,看不出热点

  • 启动服务时加:import _ "net/http/pprof",并监听 :6060(不要和业务端口混用)
  • 压测中执行:curl "http://localhost:6060/debug/pprof/profile?seconds=30" > cpu.pprof(注意是 30 秒持续采样,不是快照)
  • 同时采集 goroutine:curl "http://localhost:6060/debug/pprof/goroutine?debug=2" > gr.txt,看是否有 goroutine 泄漏
  • 关键陷阱:压测前没调 debug.FreeOSMemory()、没清 redis 缓存、没重启服务——这些都会让第二轮压测数据完全不可比

最常被跳过的一步:三次压测取中位数,且每次之间清空服务端所有缓存、关闭所有连接、GC 两次。否则你以为优化了 20%,其实只是上次压测残留的 page cache 在帮忙。

text=ZqhQzanResources