oha:带实时 TUI、支持 HTTP/3 的 Rust 压测工具

压测
Rust
HTTP
TUI
开源
性能
2026/10/15
·

阅读时间: 大约 9 分钟

oha:带实时 TUI、支持 HTTP/3 的 Rust 压测工具

oha 实时 TUI:压测过程中动态刷新的吞吐与延迟曲线

压测工具并不少见——本博客之前就写过 Go 生态的 vegeta。oha(读作おはよう)的存在价值不在”又一个发压工具”,而在三个老工具没做好的点上:实时 TUI 仪表盘、对 HTTP/2 乃至 HTTP/3 的一等支持、以及为避免测量失真而内置的延迟校正。它由 hatoo 用 Rust 编写,异步运行时用 tokio,TUI 用 ratatui,明确宣称灵感来自 rakyll/hey。

一、它和 hey / vegeta 到底差在哪

oha 与 hey / vegeta 的关键差异(本文依据 oha README 整理)

很多人知道 hey 但没用透。oha 在兼容 hey 默认参数的同时,把现代 HTTP 语义补齐了:

  • HTTP/2 是一等公民:-p 控制 HTTP/2 上单连接的并行请求数,总并发是 c × p;
  • HTTP/3:通过 --features http3 开启(基于 Hyper 团队的 H3 库);
  • 实时 TUI:压测过程中屏幕上动态画吞吐和延迟直方图,默认 16fps,可用 --fps 调;vegeta 要靠事后 plot 出图,hey 则根本没有交互界面;
  • 多种输出:text / json / csv / quiet,JSON schema 还单独定义在 schema.json,方便接后续分析。

二、被低估的两个”真实压测”开关

oha README 里 Tips 一节其实是它最有价值的部分——作者直接给了一条”更接近真实用户”的推荐命令:

oha <-z 或 -n> -c <并发连接数> -q <QPS> --latency-correction --disable-keepalive <目标>

两个开关各有讲究:

  • --disable-keepalive:真实用户不会拿同一个 TCP 连接反复请求同一个 URL。默认开着 keep-alive 压出来的延迟,低估了真实建连开销;
  • --latency-correction:这是专门对抗 Coordinated Omission Problem(协同遗漏)的。当压测端自己成为瓶颈、发不出去请求时,被漏掉的请求会让统计出来的延迟偏乐观;开启后校正这个偏差。注意它只在设了 -q(限速)时才生效。

这里有个和 hey 的语义差异必须说清楚:oha 的 -q 是全局总 QPS,而 hey 的 -q 是每个 worker 各自的 QPS。从 hey 迁过来的人如果照抄参数,实际压力会差好几倍。

三、Rust/tokio 带来的工程细节

  • --no-tui 更快:因为不开实时采集就省掉了聚合开销;README 进一步指出,当 --no-tui 且既没设 -q 也没设 --burst-delay 时,路径最快;
  • PGO 构建:官方提供 Profile-Guided Optimization 的产物(cargo-pgo),把压测机自身开销再压低;
  • 并发模型:默认 tokio worker 线程数等于物理 CPU 核数,可用 --worker-threads 覆盖;
  • 动态流量:--rand-regex-url 用 rand_regex 按正则生成 URL(如 http://127.0.0.1/[a-z][a-z][0-9]),--urls-from-file 从文件读一组 URL 随机打——后者特别适合拿 access log 还原真实流量分布。

四、关键参数与边界

维度官方描述
默认-n 200 请求、-c 50 连接
HTTP 版本0.9/1.0/1.1/2 稳定;3 为实验特性
限速-q 全局 QPS;--burst-delay/--burst-rate 突发
输出text / json / csv / quiet
签名内置 AWS SigV4(--aws-sigv4)
运行时Rust + tokio,PGO 可选

五、官方自曝的局限(重要)

作者没有回避问题,README 里写得很直白:

  1. HTTP/3 仍是实验特性:官方原话是”只要 H3 库还在实验阶段,oha 的 HTTP/3 就保持实验状态”,且目前依赖 rustls 做 TLS;
  2. HTTP/2 下不支持重定向(-r)、也不支持 --disable-keepalive——这两个语义在 HTTP/2 多路复用模型里本就不适用;
  3. 动态 scheme/host/port 配合 keep-alive 目前工作不正常,--rand-regex-url 场景要注意;
  4. 作者自谦:“我是 tokio 新手,请求调度还有优化空间”——性能上限不必吹得太满。

输出侧也值得一提:默认 text 是一份人类可读的统计摘要,而 --output-format json 会吐结构化结果,其 schema 被单独固化在仓库的 schema.json 里。这意味着你可以把 oha 的结果喂给后续脚本做趋势对比,或用 csv 格式把每个请求的耗时落表再离线分析;--db-url 甚至能把成功请求直接写进一个 sqlite 文件。再加上 --stats-success-breakdown 可以按状态码把成功/失败拆开算延迟直方图——这些都是把”压测”从一次性命令变成可积累实验数据的配套能力,也是它比 hey 这种”跑完打印一段就结束”的工具更适合反复用的原因。

六、客观分析:优势与局限

优势:

  1. 实时可视:边压边看 TUI,定位”是吞吐上不去还是延迟飘了”比事后出图快;
  2. 现代协议覆盖:HTTP/2 调 -p、实验性 HTTP/3,是老 Go 工具没有的;
  3. 测量方法论自觉:延迟校正、关 keep-alive、限速语义,说明作者懂压测失真;
  4. Rust 单二进制分发:brew/winget/pacman/Docker 都有,压测机上不用装运行时。

局限:

  1. HTTP/3 不能当生产依据:实验特性,测出来的 HTTP/3 数字别直接写进结论;
  2. TUI 本身有开销:要极致施压时得 --no-tui;
  3. 不做分布式压测:oha 是单机发压,要打超大规模还得叠加 vegeta 那种多机编排或 k6。

七、适合谁

  • 想在终端里边压边看曲线、又需要测 HTTP/2 服务的工程师;
  • 对”压测数字是否可信”敏感、想要延迟校正的人;
  • 想尝鲜 HTTP/3 端点性能的人。如果你要的是可复现的分布式基准、或者已经在 vegeta/k6 流水线里跑顺了,oha 更适合作为本地快速冒烟和实时观察的补充,而非替代。

参考来源