目录

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/health

hey 与其他压测工具的对比

市面上常见的压测工具还有不少,简单做个对比方便大家选择:

工具 语言 特点 适用场景
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 做压测时,有几个容易踩的坑需要留意:

  1. 不要直接压生产环境。听起来是常识,但确实有人这么做过。压测应该在测试或预发布环境进行,避免对线上用户造成影响。

  2. 注意并发数和总请求数的关系-c 的值不能大于 -n,否则 hey 会报错。一般来说,并发数设为预期峰值的 1.5 到 2 倍就够了。

  3. 关注 TP99 而不只是平均值。平均响应时间看着很漂亮,但如果 TP99 很高,说明有少部分请求体验很差。线上用户感知到的往往是那些慢请求。

  4. 多次测试取稳定值。单次压测结果容易受网络波动、服务冷启动等因素影响。建议至少跑 3 次,取结果稳定后的数据。

  5. 考虑是否禁用 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/