尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Hey 压测报告引擎完整拆解:report.go 如何聚合百万条结果并绘制 10 桶直方图

Hey 压测报告引擎完整拆解:report.go 如何聚合百万条结果并绘制 10 桶直方图 Hey 压测报告引擎完整拆解report.go 如何聚合百万条结果并绘制 10 桶直方图【免费下载链接】heyHTTP load generator, ApacheBench (ab) replacement项目地址: https://gitcode.com/GitHub_Trending/he/heyhey是一款小巧的 HTTP 负载生成器HTTP load generator被称为 ApacheBenchab的现代替代品。每次压测结束它打印的那份漂亮的统计摘要——平均延迟、RPS、响应时间直方图、百分位延迟分布——都由报告引擎完成。本文带你拆解 requester/report.go 中的核心逻辑它如何以极低开销聚合最多 100 万条请求结果并用单指针扫描绘制出经典的 10 桶直方图。数据流水线一个 channel 连接压测与统计hey 的设计非常生产者—消费者生产者N 个并发 worker 通过 requester/requester.go 中的runWorker循环发请求每完成一次请求就构造一个result结构体包含总耗时、连接耗时、DNS 耗时、写请求、等首字节、读响应 6 个阶段的时间丢进结果通道消费者一个独立的 reporter 协程轮询通道流式聚合所有结果。结果通道在 Work.Init 中创建缓冲容量为min(C*1000, maxResult)maxResult 100 万既允许 worker 高速灌入数据又不会无限制膨胀。workers ──result──▶ results channel ──▶ runReporter(聚合) ──▶ finalize(打印报告)一条 report 结构体为百万条结果预分配内存report 结构体是整个报告引擎的核心持有 6 个阶段延迟切片connLats、dnsLats、reqLats、resLats、delayLats、总延迟切片lats、状态码切片以及一个错误分布 map。一个关键细节藏在 newReport 里const maxRes 1000000 // We report for max 1M results. cap : min(n, maxRes)所有切片在创建时就用cap请求数与 100 万取小预分配容量。这意味着 hey最多只统计前 100 万条结果——超出后不再追加明细但 RPS 等总量统计继续累加。这一上限是内存保护100 万 × 8 个float64切片 ≈ 64 MB可控且安全。流式聚合runReporter 逐条消费结果runReporter 是聚合主循环它for res : range r.results逐条消费通道数据逻辑分两支出错请求不进入延迟统计只在errorDistmap 中按错误文本计数最终展示在报告的 Error distribution 区块成功请求6 个阶段耗时累加到avgConn、avgDNS、avgReq、avgRes、avgDelay和avgTotal注意是累加而非求平均除法留给finalize若明细切片未达maxRes将本次各阶段耗时和状态码append到对应切片响应体大小contentLength累加到sizeTotal。整个循环只做 O(1) 操作没有任何排序或遍历——排序被推迟到所有数据到齐之后一次性进行这是吞吐量高的关键。finalize 与 snapshot一次排序多处复用压测结束或按 CtrlC后Work.Finish 关闭结果通道等 reporter 发完done信号再调用 finalizeRPS 总响应数 / 总时长注意这里用的是全部numRes不受 100 万上限影响各累计和除以样本数得到平均值。随后 snapshot 生成一份可打印的快照其中最重的操作是排序sort.Float64s(r.lats) r.fastest r.lats[0] r.slowest r.lats[len(r.lats)-1]6 组切片各自sort.Float64s升序排序后首元素即最快、尾元素即最慢直接取出填充Fastest/Slowest/ConnMax/...等字段。排序还带来两大副产品百分位延迟分布latencies 遍历已排序切片用整数运算i*100/len定位 10/25/50/75/90/95/99 百分位——单次线性扫描搞定 7 个分位数无需二分直方图因为数据有序分桶可以变成一次指针移动扫描见下节。状态码分布则在快照阶段用一个临时 map 统计出StatusCodeDist。10 桶直方图等宽分桶 单指针扫描直方图算法在 histogram只有 30 来行值得逐行品味第一步确定桶边界。固定 10 个桶桶宽bs (最慢 - 最快) / 10边界依次为最快 bs*i最后一个桶边界直接钉在最慢处保证最慢值必然落入最后一个桶。第二步单指针计数。因为lats已经升序排序桶索引bi只需单调递增for i : 0; i len(r.lats); { if r.lats[i] buckets[bi] { i counts[bi] // 落在当前桶 } else if bi len(buckets)-1 { bi // 越过桶边界前移 } }两个指针各走一遍数据总复杂度 O(n)比每条数据对每个桶做二分快了一个数量级。第三步输出 Bucket。每个桶记录Mark桶边界值、Count命中数和Frequency占比 命中数 / 样本总数。终端里那条柱子是怎么画出来的数据侧只产出数字渲染在 requester/print.go 的histogram模板函数中先找出所有桶里的最大计数max每个桶按(count*40 max/2) / max归一化成 0~40 的柱长加max/2是四舍五入避免零头桶显示不出来用strings.Repeat(barChar, barLen)重复常量barChar ■生成条形。于是你看到的经典输出长这样Response time histogram: 0.010 [1] |■ 0.020 [87] |████████████████████████ 0.030 [92] |██████████████████████████ ...整份摘要由 defaultTmpl 这个 text/template 模板驱动通过 print 渲染到 buffer 再写出若用-o csv参数则切换到csvTmpl输出 8 列逐条明细详见 print.go 文件头注释。关键文件索引文件作用requester/report.go报告引擎聚合、排序、分桶、百分位requester/print.go输出模板摘要与 CSV 两种格式requester/requester.go压测主体worker、httptrace 计时、结果通道hey.go命令行入口参数解析与调度requester/requester_test.go请求与报告的单元测试README.md安装与用法速查小结报告引擎的 4 个设计亮点生产者—消费者解耦worker 只管发请求聚合在独立协程流式完成互不阻塞100 万条上限maxRes预分配容量 截断明细内存恒定可控排序前置、扫描后置一次sort.Float64s最快/最慢、百分位、直方图全部 O(n) 顺手得到模板化输出text/template 自定义histogram函数换格式只需换模板。下次运行hey -n 1000000 -c 100 你的URL时再看那份响应时间直方图你应该能一眼认出它背后的 30 行代码了 【免费下载链接】heyHTTP load generator, ApacheBench (ab) replacement项目地址: https://gitcode.com/GitHub_Trending/he/hey创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表