压测前必须修改三个默认配置:client.Timeout设为≤5s防goroutine泄漏;MaxIdleConns与MaxIdleConnsPerHost至少设为200避免频繁建连;ulimit -n调至65536防止too many open files。

用 hey 或 wrk 压测前必须改掉的三个默认配置
直接 hey -c 100 -n 10000 http://localhost:8080 得到的数字,大概率不是服务极限,而是你本地 HTTP 客户端或系统资源先崩了。关键要动三处:http.Client 超时、连接池、系统 ulimit。
-
Timeout必须设:不设就卡在 DNS 或 TLS 握手,goroutine泄漏;建议总超时 ≤ 5s,比如client.Timeout = 5 * time.Second -
MaxIdleConns和MaxIdleConnsPerHost至少设为 200:默认是 2 和 2,压到 100 并发时连接反复建连,net/http: request canceled大量出现 -
ulimit -n提到 65536:否则too many open files在几百并发就报,和代码无关
别用 for i := 0; i
这跑出来的是“瞬时并发峰值”,不是“稳定 QPS”。100 个 goroutine 同时发请求,测的是你本机网络栈和 TCP 连接建立能力,不是服务吞吐。
- 用
time.Ticker控节奏:每100ms发一次,就是 10 QPS;精度比time.Sleep高,还能自动补偿单次请求耗时波动 - 推荐“生产者-消费者”模型:一个 ticker goroutine 往
chan struct{}写信号,N 个 worker 从 channel 读并执行http.Do();chan struct{}零内存开销,比传*http.Request更轻 - 务必用
sync.WaitGroup等所有请求完成:否则主 goroutine 提前退出,结果统计直接丢数
压测中 pprof 采样必须盯住这两个函数
QPS 上不去,90% 不是业务逻辑慢,而是调度或锁卡死。pprof 不看这两项,等于没采。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
-
runtime.findrunnable占比 >15% → goroutine 调度开销过大,常见于每请求启几十个 goroutine 且没控速,或 channel 阻塞严重 -
sync.runtime_SemacquireMutex高频出现 → 锁争用,比如热路径上对全局map加了sync.RWMutex却用了Lock()而非RUnlock() - 采样时间 ≥30 秒:
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30;太短抓不到间歇性热点
Redis LIST 做队列压测时,LPUSH+BRPOP 结果虚高的真相
单独压生产者或消费者能跑到 1w+ QPS,但两者一起跑就掉到 5000 QPS——这不是 Redis 瓶颈,是客户端阻塞模型和资源争抢导致的。
立即学习“go语言免费学习笔记(深入)”;
-
BRPOP是阻塞命令,每个 goroutine 占一个连接、一个 socket、一个 goroutine 栈;高并发下 fd 和内存先吃紧 - 消费者带业务逻辑(如写 MySQL)时,
BRPOP调用频次被迫拉低,list 积压又拖慢后续LPUSH(Redis 单线程,大 list 的 push/pop 开销上升) - 别用默认
redigo连接池(MaxIdle=3):实际并发卡在几十级;改用go-redis+ pipeline,失败重试和 context 超时更稳
真实极限 QPS 往往卡在连接复用、goroutine 调度或锁竞争上,而不是代码里那几行业务逻辑。调参和 profile 必须同步做,光看日志说“慢”,不采 profile 就动手改,基本是在蒙。

















