y-http-bench
纯标准库、零依赖的 HTTP 压测命令行工具
技术栈
- Go(纯标准库)
- 单文件
- 交叉编译
- CLI
概览
y-http-bench 是一个用 Go 纯标准库写的 HTTP 压测(benchmark)工具:单文件、零依赖、开箱即用。编译出来就是一个可执行文件,不需要装任何运行时,也没有第三方库。
它面向的是「快速知道一个接口能扛多少」这个场景 —— 固定请求数、固定时长、或固定 QPS 三种压测方式任选,结束后直接给出延迟分位数报告。
快速开始
# 固定请求数:20000 次请求,100 并发
y-http-bench -url https://example.com -c 100 -n 20000
# 固定时长:50 并发压 30 秒
y-http-bench -url https://example.com -c 50 -d 30s
# 限速:稳定 1000 QPS 打 1 分钟
y-http-bench -url https://api.test/users -c 50 -d 1m -qps 1000
# POST 接口:自定义请求头 + 请求体
y-http-bench -url https://api.test/login -m POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer xxx" \
-body '{"user":"tom","pwd":"123"}' -c 20 -n 5000
# 从文件读请求体 + 导出原始延迟数据用于画图
y-http-bench -url https://api.test/order -m POST \
-body-file ./payload.json -c 30 -d 20s -dump-latency latency.csv
-n 和 -d 至少要指定一个(否则测试不会结束);两者同时给定时,先到达的条件触发结束。运行中按 Ctrl+C 会停止压测,并基于已采集的样本照常输出报告。
参数
| 参数 | 默认值 | 说明 |
|---|---|---|
-url |
无(必填) | 目标 URL |
-m |
GET |
HTTP 方法 |
-c |
10 |
并发数 |
-n |
0 |
总请求数,0 表示不限(配合 -d) |
-d |
0 |
压测时长,如 10s / 2m,0 表示不限(配合 -n) |
-qps |
0 |
全局限速(请求/秒),0 表示不限速 |
-timeout |
10s |
单次请求超时 |
-H |
无 | 自定义请求头,可重复传入 |
-body |
空 | 请求体字符串 |
-body-file |
空 | 从文件读取请求体 |
-keepalive |
true |
是否复用连接,置为 false 可模拟短连接(每次握手) |
-insecure |
false |
跳过 TLS 证书校验(自签证书场景) |
-dump-latency |
空 | 把每次请求延迟流式导出为 CSV(列:latency_ms,status,bytes,error),不占额外内存 |
-v |
false |
打印全部错误分类(默认最多显示 5 类) |
输出说明
压测过程中每 500ms 刷新一行实时进度(耗时 / 已完成 / 实时 QPS / 失败数);结束后输出报告:
- 概览:总请求数、失败数、成功率、平均 QPS、吞吐量(设了
-qps时额外显示目标 QPS 与速率达成率) - 延迟分布:Min / Avg / P50 / P90 / P95 / P99 / P99.9 / Max(毫秒,读取完响应体为止)
- 状态码分布
- 错误分布(网络层错误按类型聚合)
延迟口径:只统计拿到响应的请求(含 4xx/5xx),网络层错误只计入失败数与错误分布;设了 -qps 时,计时起点是请求的「理想发出时刻」,排队等待时间也算进延迟。
实现要点
- 限速器不用
time.Ticker:Windows 上 ticker 最小间隔受系统定时器精度限制(约 15.6ms),会把吞吐死死卡在 60~90 req/s(实测设定 5000 只跑出 88)。这里改用「绝对时间表」调度:第 n 个请求的理想发出时刻 =start + n×interval,只依赖time.Now()计算等待时间。实测 200 / 1000 / 5000 三档分别跑出 188 / 985 / 4982 req/s - 延迟从「理想发出时刻」起算(coordinated omission 修正):被限速器推迟、或上一批请求把 worker 拖慢所积累的排队时间都会计入延迟,否则高负载下 P99 会明显偏乐观(wrk2 的 fixed-rate 模式同理)
- 延迟统计用直方图,不保留全量样本:对数线性分桶,1024 桶/量级共 32 个量级(固定 256KB,与请求量无关),相对误差上限约 0.1%;分位数取桶中点并夹到
[Min, Max]之间 -dump-latency流式落盘:合并样本时顺手写进bufio.Writer,不把全量样本留在内存里- 显式开启 HTTP/2:手写
http.Transport时 Go 不会自动启用 HTTP/2,需要ForceAttemptHTTP2: true - 表头按显示宽度对齐:中文在终端占 2 个显示列,用
padRight/displayWidth自己补空格,避免中文表头把表格挤错位
已知局限
- 仍是闭环(closed-loop)压测:每个 worker 必须等上一次响应读完才发下一次。设了
-qps时排队时间会被补进延迟,但真要「按固定速率发出、不被服务端拖慢」需要开环模型 - 单机单进程,没有多 URL / 多阶段场景、爬坡、think time、断言与 SLA 阈值判定,也不支持分布式
- 每请求一次分配(
Request.Clone+ 新建 Body reader),极限吞吐下不如 wrk 这类 epoll + 复用缓冲的实现 - 客户端侧指标没有拆分统计:连接复用次数、DNS / TCP / TLS 各阶段耗时都没有单独列出
压测注意事项
- 压的是被测服务,不是本机网络:尽量在与被测机同机房/内网的中立机器上跑
- 先区分瓶颈在哪一方 —— 观察被测机 CPU、GC、连接池是否打满
- 关注 P99 / P99.9 而不是平均值,平均值容易被大量快请求掩盖长尾
- Windows 下临时端口回收较慢,短连接高压场景可能出现
connectex拒绝,属被测端或系统限制
许可
最近更新