Go 压测工具 hey 使用教程:安装、参数详解与实战案例
前言
在日常后端开发工作中,接口的性能到底怎么样,往往不能靠主观感觉来判断。当你上线了一个新的 API,或者对某个接口做了优化,怎么快速验证它在高并发下的表现?这时候就需要一款趁手的压测工具。
hey 是一款用 Go 语言编写的轻量级 HTTP 压力测试工具。相比老牌的 ab(ApacheBench),hey 的安装更简单,对 HTTP/2 的支持也更好,而且输出结果非常直观,特别适合开发者在本地或 CI/CD 流程中快速做接口性能验证。
这篇文章将从安装开始,逐一讲解 hey 的全部参数含义,再通过真实的测试输出带你理解每一项指标的意义,最后给出多种常见压测场景的命令示例,方便你直接拿来用。
hey 的安装方式
hey 是一个纯 Go 编写的命令行程序,安装方式非常简洁。确保你的机器上已经安装了 Go 环境(建议 Go 1.17 及以上版本),然后执行以下命令即可完成安装:
go install github.com/rakyll/hey@latest安装完成后,在终端输入 hey 就能看到帮助信息,说明安装成功。
如果你使用的是较老的 Go 版本,也可以通过
go get -u github.com/rakyll/hey来安装,但推荐使用go install的方式,这是 Go 官方目前更推荐的做法。
安装完毕后,建议确认 $GOPATH/bin 已经加入到你的系统 PATH 环境变量中,否则可能会出现 command not found 的提示。
参数详解
hey 提供了丰富的参数来满足不同的测试需求,下面逐个说明每个参数的含义和用法:
| 参数 | 说明 | 默认值 |
|---|---|---|
-n |
总请求数,即本次压测一共发送多少个请求 | 200 |
-c |
并发数,同时发起请求的客户端数量。注意总请求数不能小于并发数 | 50 |
-q |
速率限制,每秒发送的请求数(QPS)。不设置则不做限制,压满为止 | 无限制 |
-z |
持续时间模式,指定压测运行的时长,比如 -z 10s 表示持续 10 秒。设定此参数后 -n 会被忽略 |
无 |
-o |
输出格式。默认打印摘要,设为 csv 则输出逗号分隔的详细数据,方便做进一步分析 |
摘要 |
-m |
HTTP 请求方法,支持 GET、POST、PUT、DELETE、HEAD、OPTIONS | GET |
-H |
自定义请求头,可多次使用来添加多个 Header | 无 |
-t |
单个请求的超时时间(秒),设为 0 表示不限制 | 20 |
-A |
设置 HTTP Accept 头 | 无 |
-d |
请求体内容,直接写在命令行中 | 无 |
-D |
从文件中读取请求体,例如 -D ./payload.json |
无 |
-T |
Content-Type 请求头 | text/html |
-a |
HTTP Basic 认证,格式为 用户名:密码 |
无 |
-x |
HTTP 代理地址,格式为 host:port |
无 |
-h2 |
启用 HTTP/2 协议 | 关闭 |
-host |
自定义 HTTP Host 头 | 无 |
-disable-compression |
禁用 gzip 压缩 | 关闭 |
-disable-keepalive |
禁用 keep-alive,每次请求都建立新的 TCP 连接 | 关闭 |
-disable-redirects |
禁用自动跟随 HTTP 重定向 | 关闭 |
-cpus |
指定使用的 CPU 核心数 | 当前机器全部核心 |
压测结果解读
理解测试输出是做好性能分析的关键。下面通过一个实际的压测输出,逐段讲解每个部分的含义。
假设我们执行了以下命令,向目标地址发起 2000 个请求,并发数为 50:
hey -n 2000 -c 50 https://example.com/api/health输出结果大致如下:
Summary 摘要部分
Summary:
Total: 0.5153 secs
Slowest: 0.0770 secs
Fastest: 0.0067 secs
Average: 0.0097 secs
Requests/sec: 3880.9152
Total data: 454000 bytes
Size/request: 227 bytes- Total:整个压测从开始到结束的总耗时
- Slowest / Fastest:所有请求中响应最慢和最快的那一个所花的时间
- Average:所有请求的平均响应时间,这是最常关注的指标之一
- Requests/sec:QPS,即每秒处理的请求数,数值越高代表服务吞吐能力越强
- Total data:所有响应的数据总量
- Size/request:每个请求的平均响应体大小
Response time histogram 响应时间直方图
Response time histogram:
0.007 [1] |
0.014 [1940] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.021 [4] |
0.028 [0] |
0.035 [0] |
0.042 [1] |
0.049 [0] |
0.056 [5] |
0.063 [26] |■
0.070 [22] |
0.077 [1] |直方图用柱状图的形式展示了请求响应时间的分布情况。上面的结果表明绝大多数请求(1940 个)都在 0.007 到 0.014 秒之间完成了,说明服务整体响应非常稳定。只有少量请求落在了 0.056 秒以上的区间,这些通常是建立连接初期或网络波动带来的毛刺。
Latency distribution 时延分布
Latency distribution:
10% in 0.0073 secs
25% in 0.0077 secs
50% in 0.0081 secs
75% in 0.0088 secs
90% in 0.0093 secs
95% in 0.0106 secs
99% in 0.0634 secs时延分布是做性能评估最重要的参考之一。它告诉你在所有请求中,各个百分位的响应时间是多少:
- P50(中位数):50% 的请求在 0.0081 秒内完成,这代表了"大多数用户"的真实体验
- P90:90% 的请求在 0.0093 秒内完成
- P99(TP99):99% 的请求在 0.0634 秒内完成。TP99 是衡量服务稳定性的关键指标——如果 TP99 偏高,说明存在少量请求响应缓慢,可能需要排查慢查询、GC 停顿等问题
Details 各阶段耗时明细
Details (average, fastest, slowest):
DNS+dialup: 0.0010 secs, 0.0067 secs, 0.0770 secs
DNS-lookup: 0.0001 secs, 0.0000 secs, 0.0076 secs
req write: 0.0000 secs, 0.0000 secs, 0.0008 secs
resp wait: 0.0083 secs, 0.0066 secs, 0.0769 secs
resp read: 0.0001 secs, 0.0000 secs, 0.0029 secs这部分把一个完整的 HTTP 请求拆分成了五个阶段,分别展示平均值、最快和最慢的耗时:
- DNS+dialup:DNS 解析加上 TCP 建立连接的时间
- DNS-lookup:单独的 DNS 解析时间
- req write:把请求数据写入连接的时间
- resp wait:发出请求后等待服务端响应的时间,这个通常是占比最大的部分
- resp read:读取响应数据的时间
如果发现 resp wait 特别长,基本可以确定瓶颈在服务端;如果 DNS+dialup 偏高,可以考虑使用 -disable-keepalive 来观察是否是连接复用的问题。
Status code distribution 状态码分布
Status code distribution:
[200] 2000 responses展示了各个 HTTP 状态码的请求数量。正常情况下应该全部是 200。如果出现大量 5xx,说明服务端在高并发下出了问题;如果出现 429,说明触发了限流策略。
实战场景示例
下面整理了日常工作中几种最常用的压测场景及对应命令,可以根据实际需求直接使用或稍作调整。
场景一:按时长压测 GET 接口
并发 2 个客户端,持续压测 5 秒:
hey -z 5s -c 2 https://example.com/api/health这种方式适合想观察"一段时间内服务表现如何"的场景,不用事先计算要发多少请求。
场景二:按请求总数压测 GET 接口
发送 2000 次请求,50 个并发:
hey -n 2000 -c 50 https://example.com/api/health适合想精确控制请求量的场景,比如测完之后直接看"这 2000 个请求的整体分布"。
场景三:指定 Host 头压测
当目标服务器没有绑定域名,或者需要绕过 DNS 直接用 IP 访问时,可以手动指定 Host 头:
hey -z 5s -c 2 -cpus 2 -host "api.example.com" https://192.168.1.100:8080这在测试灰度环境、内网服务时非常实用。
场景四:带自定义 Header 的请求
需要传递认证信息、自定义标识等 Header 时,用 -H 参数:
hey -z 5s -q 128 -H "Authorization: Bearer your-token" -H "X-Request-Source: stress-test" https://example.com/api/data这里同时用了 -q 128 做了 QPS 限速,避免把测试环境打挂。
场景五:POST 请求压测
发送 POST 请求,带上表单数据:
hey -z 5s -c 50 -m POST -T "application/x-www-form-urlencoded" -d "username=testuser&password=123456" https://example.com/api/login如果请求体是 JSON 格式,调整 -T 和 -d 即可:
hey -z 5s -c 50 -m POST -T "application/json" -d '{"username":"testuser","password":"123456"}' https://example.com/api/login场景六:从文件读取请求体
当请求体比较复杂,直接写在命令行里不方便时,可以把内容放到文件中:
hey -z 5s -c 20 -m POST -T "application/json" -D ./request_body.json https://example.com/api/order场景七:通过代理发起请求
某些测试环境需要通过代理才能访问,或者想用代理来隐藏来源 IP:
hey -z 5s -c 10 -x "http://127.0.0.1:8001" https://example.com/api/test场景八:启用 HTTP/2 压测
如果目标服务支持 HTTP/2,可以用 -h2 参数开启,测试在 HTTP/2 协议下的性能表现:
hey -z 5s -c 20 -h2 https://example.com/api/healthhey 与其他压测工具的对比
市面上常见的压测工具还有不少,简单做个对比方便大家选择:
| 工具 | 语言 | 特点 | 适用场景 |
|---|---|---|---|
| hey | Go | 轻量、安装简单、结果直观、支持 HTTP/2 | 开发者快速验证接口性能 |
| ab | C | Apache 自带,历史悠久 | 简单的 HTTP/1.1 测试 |
| wrk | C | 性能极高,支持 Lua 脚本 | 需要极致压力的场景 |
| Locust | Python | 支持分布式、可编程场景模拟 | 复杂的用户行为模拟 |
| JMeter | Java | GUI 操作、功能全面、插件丰富 | 企业级全链路压测 |
| go-stress-testing | Go | 支持 WebSocket,适合大规模连接测试 | 长连接、WebSocket 压测 |
对于大多数日常的 HTTP 接口性能验证,hey 已经完全够用了。如果需要更复杂的场景编排,可以考虑 Locust 或 JMeter;如果追求更高的压力上限,wrk 是不错的选择。
压测时的注意事项
在实际使用 hey 做压测时,有几个容易踩的坑需要留意:
-
不要直接压生产环境。听起来是常识,但确实有人这么做过。压测应该在测试或预发布环境进行,避免对线上用户造成影响。
-
注意并发数和总请求数的关系。
-c的值不能大于-n,否则 hey 会报错。一般来说,并发数设为预期峰值的 1.5 到 2 倍就够了。 -
关注 TP99 而不只是平均值。平均响应时间看着很漂亮,但如果 TP99 很高,说明有少部分请求体验很差。线上用户感知到的往往是那些慢请求。
-
多次测试取稳定值。单次压测结果容易受网络波动、服务冷启动等因素影响。建议至少跑 3 次,取结果稳定后的数据。
-
考虑是否禁用 keep-alive。默认情况下 hey 会复用 TCP 连接,这接近真实的浏览器行为。但如果你想模拟大量新用户同时涌入的场景,加上
-disable-keepalive会更贴近实际。
常见问题
Q1:hey 支持 Windows 系统吗?
支持。hey 是用 Go 编写的跨平台工具,在 Windows、macOS 和 Linux 上都可以正常使用。Windows 上安装方式相同,用 go install github.com/rakyll/hey@latest 即可。
Q2:执行 hey 命令提示 “command not found” 怎么办?
大概率是 $GOPATH/bin 没有加入系统的 PATH 环境变量。可以执行 export PATH=$PATH:$(go env GOPATH)/bin,或者将这行添加到你的 shell 配置文件(.bashrc 或 .zshrc)中。
Q3:-n 和 -z 可以同时使用吗?
可以同时写,但当 -z 被指定时,-n 会被忽略。hey 会以持续时间为准,到时间后自动停止。
Q4:压测过程中出现大量超时或报错,是什么原因?
常见原因有几种:目标服务本身扛不住这么大的并发、网络带宽不够、服务端有限流或防火墙策略。可以先降低 -c 并发数,逐步增加来定位瓶颈所在。
Q5:hey 能测试 WebSocket 接口吗?
不能。hey 只支持标准的 HTTP/HTTPS 请求。如果需要做 WebSocket 或长连接的压测,可以看看 go-stress-testing 这个工具,它支持 WebSocket 协议的压力测试。
Q6:怎么把压测结果保存下来做对比分析?
使用 -o csv 参数,hey 会把每个请求的详细数据以 CSV 格式输出。你可以重定向到文件里,然后用 Excel 或者 Python 脚本来做对比分析:
hey -n 1000 -c 20 -o csv https://example.com/api/health > result.csv总结
hey 作为一款用 Go 编写的 HTTP 压测工具,最大的优势在于简洁高效——安装只需一条命令,使用也足够直观。对于日常开发中的接口性能验证、上线前的快速压测、以及 CI/CD 流程中的自动化性能回归,hey 都是一个非常实用的选择。
掌握 hey 的核心在于三点:理解各个参数的含义、能够正确解读输出结果中的关键指标(特别是 TP99 和 QPS),以及根据不同的测试场景灵活组合参数。只要把这三点搞清楚,基本上就能覆盖绝大多数日常压测需求了。
如果大家在使用 hey 做压测的过程中遇到了什么问题,或者有其他好用的压测技巧想分享,欢迎在评论区一起交流讨论~~~
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!
本文原文链接: https://fiveyoboy.com/articles/golang-hey-benchmark-tool-tutorial/
备用原文链接: https://blog.fiveyoboy.com/articles/golang-hey-benchmark-tool-tutorial/