结论:别自己手写压测工具,除非需定制逻辑(如会话状态、jwt刷新);日常压测优先用vegeta或hey——vegeta适合ci回归、基线比对(支持-ramp、json输入、plot图表),hey适合快速摸底、现场排查(p90/p99直方图清晰、启动快);二者均须加-disable-keepalive以防掩盖服务端time_wait问题。

直接说结论:别自己手写压测工具,除非你明确需要定制逻辑(比如带会话状态、JWT刷新、条件分支)。日常压测优先用 vegeta 或 hey;真要写 Go 代码,核心不是起多少 goroutine,而是控住 http.Transport 和 context,否则本地先崩。
vegeta 和 hey 怎么选?看输出和场景
二者都是命令行工具,但定位不同:
-
vegeta支持-ramp(阶梯加压)、JSON 输入、vegeta plot生成图表、导出 CSV/JSON 报告——适合 CI 回归、基线比对、API 链路测试 -
hey输出更直观:P90/P99 延迟直方图、失败率分布、连接复用统计清晰——适合快速摸底、现场排查、验证修复效果 - 都必须加
-disable-keepalive,否则服务端TIME_WAIT和 accept 队列问题会被掩盖
手写 Go 压测脚本最常踩的三个资源坑
自己起 goroutine 看似灵活,但不设限就容易卡死或报错:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
-
DNS 缓存:默认http.DefaultTransport会缓存 DNS,换 IP 后请求失败;解决:提前预热或禁用:http.DefaultTransport.(*http.Transport).DialContext = fastDialer -
连接池耗尽:默认MaxIdleConnsPerHost = 2,并发稍高就排队等连接;必须显式设为 ≥1000:MaxIdleConns: 1000, MaxIdleConnsPerHost: 1000 -
本地端口耗尽:Linux 默认临时端口范围是32768–65535,压测超 2 万并发前得调大:sysctl -w net.ipv4.ip_local_port_range="1024 65535"
goroutine 控制:别硬开,用 worker pool + semaphore
直接 for i := 0; i 是危险操作。真实压测要模拟稳定 QPS,而不是瞬间打满:
- 用
golang.org/x/sync/semaphore控并发数,比如sem := semaphore.NewWeighted(50) - 每个 goroutine 内循环发请求,但每次发前
sem.Acquire(ctx, 1),发完sem.Release(1) - 用
time.Ticker控节奏(如每秒 100 请求 →tick := time.NewTicker(10 * time.Millisecond)),别用time.Sleep - 每个请求必须带
context.WithTimeout(ctx, 5*time.Second),防止失败请求 hang 住 goroutine
真正难的不是并发数,而是让每个请求都走通、不卡在 DNS、不耗尽连接、不拖垮本地网络栈。压测前先跑通 pprof,看 goroutine 数、GC 频率、阻塞点——这些比 QPS 数字更能说明问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










