news 2026/10/3 7:36:10

Hey压测工具result结构体深度解析:6个延迟字段如何读懂一次请求的一生

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Hey压测工具result结构体深度解析:6个延迟字段如何读懂一次请求的一生

Hey压测工具result结构体深度解析:6个延迟字段如何读懂一次请求的一生

【免费下载链接】heyHTTP load generator, ApacheBench (ab) replacement项目地址: https://gitcode.com/GitHub_Trending/he/hey

跑完一次 hey 压测,屏幕上会刷出平均延迟、P99、resp wait 等一串数字,这些数字到底从哪来?答案就藏在 hey 压测工具里一个小小的result结构体中——它的 6 个延迟字段,完整记录了一次请求从发出到收到的全部旅程。本文带你逐层拆解 result 结构体:它如何诞生、6 个延迟字段如何测量,以及如何用它快速定位性能瓶颈。

先认识 hey:一个极快的 HTTP 压测工具

hey 是用 Go 编写的轻量级 HTTP 压测工具,可以看作 ApacheBench(ab)的现代替代。它的核心能力:

  • 两个参数定压测规模:总请求数-n、并发数-c
  • 实时统计:响应时间直方图、10%~99% 分位数分布、状态码分布
  • 两种输出:默认人类可读的 Summary,或用-o csv导出每个请求的明细

上手只需一条命令(更多用法见 README.md):

hey -n 1000 -c 100 https://example.com

result 结构体:一次请求的完整"病历"

hey 每发出一个请求,就会生成一条result记录,定义非常精炼,位于 requester/requester.go:

type result struct { err error statusCode int offset time.Duration duration time.Duration connDuration time.Duration // connection setup(DNS lookup + Dial up) duration dnsDuration time.Duration // dns lookup duration reqDuration time.Duration // request "write" duration resDuration time.Duration // response "read" duration delayDuration time.Duration // delay between response and request contentLength int64 }

这些字段可以分成三组来看:

字段归属通俗解释
err、statusCode、contentLength请求元信息这次请求成功了吗?返回什么状态码?响应多大?
offset时间标记请求开始时,压测已经运行了多久?
duration延迟字段 1整次请求的端到端总耗时
connDuration延迟字段 2建立连接(DNS + TCP)花了多久
dnsDuration延迟字段 3DNS 解析花了多久
reqDuration延迟字段 4发送请求体(写入)花了多久
delayDuration延迟字段 5写完请求后,等多久才收到第一个响应字节
resDuration延迟字段 6从首个字节到读完整个响应体花了多久

上面 6 个延迟字段就是本文的"主角",而offset更像一枚时间戳,标记请求的出生时刻。所有时间都以压测进程启动为零点,取时工具函数now()见 requester/now_other.go。

6 个延迟字段怎么测出来的:httptrace 钩子

hey 并不靠"猜"来得到这些耗时。秘密在makeRequest里的一组 httptrace 钩子:标准库的httptrace.ClientTrace会在 HTTP 请求的每个关键节点触发回调,hey 在每个节点精确记一次时钟。

回调钩子覆盖阶段记录的字段
DNSStart→DNSDoneDNS 解析前 → 后dnsDuration
GetConn→GotConn申请连接前 → 后(仅新建连接)connDuration
GotConn→WroteRequest连接就绪 → 请求写完reqDuration
WroteRequest→GotFirstResponseByte请求写完 → 收到首字节delayDuration
GotFirstResponseByte→ 读完响应首字节 → 响应体读完resDuration

一个请求的完整生命周期,可以想象成一条直线时间轴:

开始 (offset) ├─ DNS 解析 (dnsDuration) ─┐ ├─ TCP 建连 (connDuration) ─┘ 仅新建连接时发生 ├─ 写请求 (reqDuration) ├─ 等待服务器处理 + 首字节 (delayDuration) ← 最关键 └─ 读响应体 (resDuration) 结束 (duration ≈ 以上全部相加)

几个值得注意的细节:

  • 复用连接时connDuration为 0:keep-alive 下大多数请求复用同一条 TCP 连接,建连耗时只出现在新连接上,这正是判断连接复用是否生效的依据
  • dnsDuration是connDuration的子集:新建连接时,DNS 时间包含在建连时间内
  • delayDuration代表"服务器时间":请求已发出,剩下的等待基本就是服务端在处理,是排查接口性能最关键的字段
  • duration是端到端总耗时:复用连接时约等于 req + delay + res 三项之和

从单条记录到统计报告:Summary 里的 Details 区块

每条result是"一个人的病历",而 reporter 会把它们逐条累加:对 6 个延迟字段同时记录总和(算平均值)和逐条明细(算最快/最慢与分位数)。压测结束后,finalize 除以样本数得到均值,明细排序后得到各阶段的最大最小值。

Summary 输出中的 Details 区块正是这份统计的体现,每行格式为"平均、最快、最慢":

Details (average, fastest, slowest): DNS+dialup: 0.0123 secs, 0.0456 secs, 0.0000 secs DNS-lookup: 0.0045 secs, 0.0123 secs, 0.0000 secs req write: 0.0001 secs, 0.0003 secs, 0.0001 secs resp wait: 0.0345 secs, 0.2100 secs, 0.0089 secs resp read: 0.0056 secs, 0.0321 secs, 0.0012 secs

5 行对应 5 个阶段字段,端到端总耗时duration则体现在 Summary 的 Average / Fastest / Slowest、响应时间直方图和分位数分布中。完整输出模板见 requester/print.go。

报告行对应字段偏高说明什么
DNS+dialupconnDuration建连慢:DNS 慢、离服务器远、新连接多
DNS-lookupdnsDurationDNS 解析是瓶颈:无缓存、DNS 服务器远
req writereqDuration请求体过大(大 body / 上传)
resp waitdelayDuration服务器处理慢——最该优先排查
resp readresDuration响应体过大或下行链路慢

CSV 模式:逐条查看每个请求的一生

想更精细地分析——比如找出哪个请求是"黑天鹅"——可以用-o csv把每个请求输出为一行 CSV,8 列与 result 字段一一对应,列定义说明就在 requester/print.go 的文件头部注释中:

hey -n 200 -c 20 -o csv https://example.com
CSV 列对应字段
response-timeduration
DNS+dialupconnDuration
DNSdnsDuration
Request-writereqDuration
Response-delaydelayDuration
Response-readresDuration
status-codestatusCode
offsetoffset

配合offset列,还能回答更多问题:慢请求是开头并发洪峰造成的,还是中途某次服务器抖动?这正是"逐请求数据"的价值所在。

三个实战排障场景

用 6 个延迟字段,可以快速回答三个高频问题:

场景一:接口慢,是客户端还是服务器的问题?看resp wait(delayDuration)。若它占duration的大头,说明服务端处理慢,去查 SQL、下游依赖、GC;若它很小但resp read大,则是响应体问题(体积过大、未开压缩)。

场景二:为什么压测结果比线上明显慢?看DNS+dialup(connDuration)。偏大说明新连接多,可能是压测机离目标远、连接池没生效,或误开了-disable-keepalive——关掉再对比一次即可验证。

场景三:结果稳不稳,有没有偶发尖刺?看 fastest 与 slowest 的差距。fastest 10ms 而 slowest 500ms,说明问题不是"整体慢",而是"尾延迟高";再配合 CSV 的offset列,就能定位尖刺发生的时刻。

总结

hey 的 result 结构体 虽小,却是整个压测工具的数据骨架:

  • 6 个延迟字段:duration、connDuration、dnsDuration、reqDuration、delayDuration、resDuration
  • 采集机制:httptrace 钩子在每个阶段打精确时间戳
  • 汇总输出:reporter 将逐条记录累加为平均值、最值、分位数与直方图
  • 两种视角:Summary 看整体趋势,CSV 模式看单请求明细

下次压测报告里 resp wait 飙高时,你就不只是看到一串数字,而是清楚地知道:该去查服务器了。

【免费下载链接】heyHTTP load generator, ApacheBench (ab) replacement项目地址: https://gitcode.com/GitHub_Trending/he/hey

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 7:36:02

GESP四级考试全攻略:从备考规划到考场实战避坑指南

3月GESP四级考完,我从机房出来先长出了一口气。这次参加四级认证不完全是为了自己,我带的班里这一轮有十几个孩子要冲四级,不亲自上考场把题目和时间压力都体验一遍,我心里实在没底。所以从寒假算起,我用了大约两个月时…

作者头像 李华
网站建设 2026/10/3 7:35:39

【Embedded Development】【高级MCU篇】基于野火STM32H750XBH6_Pro开发板的高级MCU开发学习之1点亮led

前言 开这个篇章是为了学习补全高级MCU下的一些高级外设功能和MCU怎么和外部的Flash和外部SDRAM怎么更好的搭配使用起来。 一、简介 1.1 浏览硬件资源布局和软件资源需求 11. H750PRO资料目录内容及底板介绍 — [野火]STM32开发板必读说明 文档 二、工程实践 2.1 打开STM3…

作者头像 李华
网站建设 2026/10/3 7:33:33

突破烟雾迷障!一层分子膜,暗电流砍半:APTES 界面工程让 PbS 量子点“看穿”

在自动驾驶与工业安全监测的感知层,短波红外(SWIR,1.0–2.5 μm)成像技术正展现出超越可见光方案的独特优势:雾霾、烟尘对短波红外的散射远弱于可见光,这意味着车辆或监控设备能够在恶劣大气条件下“看穿”烟雾,识别被遮蔽的目标。然而,这一愿景的落地长期受制于探测器…

作者头像 李华
网站建设 2026/10/3 7:33:25

对比实测:3大招聘平台的搜索系统性能

2026年招聘行业早已告别单纯的岗位、简历数量竞争,底层搜索引擎的技术能力,直接决定求职者投递效率和企业招聘精准度。结合近两年行业使用反馈和平台公开技术迭代资料来看,主流招聘平台分为关键词检索、语义向量检索两类技术路线,…

作者头像 李华