3. 压测工具选型:wrk、hey、vegeta、ghz(gRPC)、自研压测框架对比
在尾延迟诊断场景中,压测工具的选择直接影响测试结果的准确性和可复现性。不同的工具在并发模型、协议支持、统计输出、资源开销等方面存在显著差异。本章对主流压测工具进行系统性对比,帮助你在不同场景下做出合理选型。
3.1 工具概览与核心定位
以下表格从协议支持、并发模型、统计能力、适用场景四个维度对五类工具进行横向对比:
| 工具 | 协议支持 | 并发模型 | 延迟统计 | 典型场景 |
|---|---|---|---|---|
| wrk | HTTP/1.1, HTTPS | 多线程 + epoll/kqueue | 平均值、标准差、百分位 | 快速吞吐测试、短连接压测 |
| hey | HTTP/1.1, HTTPS | goroutine + 连接池 | 平均值、百分位、直方图 | 简单功能验证、小规模压测 |
| vegeta | HTTP/1.1, HTTPS | 固定速率 + 攻击器 | 百分位、延迟分布、实时报告 | 恒定速率压测、SLA验证 |
| ghz | gRPC (HTTP/2) | goroutine + 流式连接 | 百分位、延迟分布、错误码 | gRPC服务压测、流式接口 |
| 自研框架 | 任意协议 | 可定制 | 全量记录、自定义分位 | 复杂场景、协议定制、持续集成 |
选型建议: 如果仅需快速验证 HTTP 接口的吞吐能力,wrk 是最轻量的选择;若需要精确控制请求速率并输出百分位延迟,vegeta 更合适;gRPC 场景下 ghz 是事实标准;当需要模拟复杂业务逻辑或自定义协议时,自研框架是唯一选项。
3.2 工具深度对比
3.2.1 wrk:高性能 HTTP 压测标杆
wrk 使用 C 语言编写,基于多线程和 epoll/kqueue 事件驱动模型,能够在单机上产生极高的并发压力。其核心优势在于:
- 极低资源开销: 单线程可管理数万个连接,适合大规模并发场景。
- Lua 脚本扩展: 支持自定义请求构造、响应处理、延迟记录。
- 实时统计输出: 测试过程中实时显示延迟平均值和标准差。
典型用法示例:
# 30秒压测,16个线程,100个连接
wrk -t16 -c100 -d30s --latency http://target:8080/api
# 使用Lua脚本自定义请求
wrk -t4 -c50 -d10s -s custom.lua http://target:8080/api
注意: wrk 默认使用 HTTP/1.1 长连接,且不支持 HTTP/2。在测试 gRPC 或 HTTP/2 服务时,wrk 无法直接使用。此外,wrk 的百分位统计仅输出 p50、p75、p90、p99,缺少 p999 和 p9999 等尾延迟关键指标。
3.2.2 hey:Go 生态的轻量压测工具
hey 由 Go 语言编写,利用 goroutine 实现并发,安装简单,适合快速验证。其特点包括:
- 零依赖: 单二进制文件,无需安装运行时。
- 内置直方图: 输出延迟分布直方图,便于直观观察延迟分布。
- 支持自定义 Header 和 Body: 通过命令行参数灵活构造请求。
典型用法:
# 100个并发,总共发送1000个请求
hey -n 1000 -c 100 -h2 http://target:8080/api
# 输出详细延迟分布
hey -n 5000 -c 50 -o csv http://target:8080/api
对比要点: hey 的并发模型基于 goroutine,在极高并发(>10000)下性能不如 wrk 的 epoll 模型。但 hey 的安装便捷性和直方图输出使其在开发调试阶段非常实用。
3.2.3 vegeta:恒定速率压测与 SLA 验证
vegeta 的设计理念是“恒定攻击速率”,而非“最大并发”。它通过攻击器(attacker)以固定速率发送请求,适合模拟真实用户流量。核心特性:
- 速率控制: 精确控制每秒请求数(RPS),支持线性/指数递增。
- 实时报告: 支持终端实时显示延迟百分位和吞吐量。
- 结果导出: 支持 JSON、CSV、直方图等多种输出格式。
典型用法:
# 以每秒500请求的速率压测30秒
echo "GET http://target:8080/api" | vegeta attack -rate=500 -duration=30s | vegeta report
# 输出百分位延迟报告
echo "GET http://target:8080/api" | vegeta attack -rate=1000 -duration=60s | vegeta report -type=text
尾延迟诊断优势: vegeta 的 report 命令默认输出 p50、p90、p95、p99,且支持通过
-percentiles 参数自定义分位点,非常适合尾延迟分析。
3.2.4 ghz:gRPC 压测专用工具
ghz 是专为 gRPC 服务设计的压测工具,支持一元调用、服务端流、客户端流和双向流四种模式。其关键能力:
- Protobuf 原生支持: 直接读取 .proto 文件构造请求。
- 流式压测: 支持 gRPC 流式接口的持续压测。
- 元数据注入: 支持自定义 gRPC metadata 和超时设置。
典型用法:
# 一元调用压测,100个并发,持续30秒
ghz --insecure \
--proto ./api.proto \
--call mypackage.MyService.UnaryCall \
-d '{"name": "test"}' \
-c 100 -z 30s \
target:50051
# 输出详细延迟分布
ghz --insecure \
--proto ./api.proto \
--call mypackage.MyService.UnaryCall \
-d '{"name": "test"}' \
-c 50 -n 10000 \
--format=pretty \
target:50051
注意: ghz 默认使用 HTTP/2 连接,且支持连接复用。在测试流式接口时,需注意并发数(-c)和连接数(-cpus)的合理配置,避免客户端成为瓶颈。
3.2.5 自研压测框架:应对复杂场景的终极方案
当现有工具无法满足以下需求时,自研压测框架成为必要选择:
- 自定义协议: 如 WebSocket、MQTT、私有 TCP/UDP 协议。
- 复杂业务逻辑: 需要模拟多步骤事务、条件分支、状态依赖。
- 全量延迟记录: 需要记录每次请求的完整时间戳,用于离线分析。
- 分布式压测: 需要多节点协同压测,汇总结果。
一个典型的 Go 自研压测框架结构如下:
// 核心压测引擎示例
type LoadTester struct {
client *http.Client
rate int // 目标RPS
duration time.Duration // 压测时长
results chan *Result // 结果通道
stopCh chan struct{} // 停止信号
}
func (lt *LoadTester) Run() {
ticker := time.NewTicker(time.Second / time.Duration(lt.rate))
defer ticker.Stop()
for {
select {
case <-ticker.C:
go lt.sendRequest()
case <-lt.stopCh:
return
}
}
}
func (lt *LoadTester) sendRequest() {
start := time.Now()
resp, err := lt.client.Get("http://target:8080/api")
latency := time.Since(start)
lt.results <- &Result{
Latency: latency,
Error: err,
Status: resp.StatusCode,
}
}
自研框架优势: 可以精确控制请求发送时机(如泊松分布)、记录每次请求的完整链路信息、支持动态调整压测参数、与 CI/CD 流水线深度集成。但代价是开发成本和维护成本较高。
3.3 工具选型决策流程
以下 SVG 流程图展示了在不同场景下的工具选型决策路径:
3.4 尾延迟诊断场景下的工具选择建议
针对尾延迟诊断这一核心目标,不同工具在延迟精度和统计能力上存在差异:
| 需求场景 | 推荐工具 | 关键配置 | 尾延迟指标 |
|---|---|---|---|
| HTTP 服务尾延迟初筛 | wrk + Lua 脚本 | --latency 开启百分位输出 | p99, p999 |
| gRPC 服务尾延迟分析 | ghz | --format=pretty 输出详细分布 | p99, p999, p9999 |
| SLA 验证(固定速率) | vegeta | -rate 精确控制 RPS | p95, p99, 最大延迟 |
| 全量延迟分布采集 | 自研框架 | 记录每次请求的纳秒级时间戳 | 任意分位点 |
| CI/CD 集成压测 | vegeta / 自研框架 | 输出 JSON 格式结果 | p99 阈值断言 |
核心原则: 尾延迟诊断要求工具能够记录高精度(微秒级)的延迟数据,并支持输出 p999 甚至 p9999 级别的百分位。wrk 和 hey 默认不输出 p999,需要通过脚本或二次开发实现;vegeta 和 ghz 原生支持自定义分位点;自研框架则可以做到全量记录,无精度损失。
3.5 工具选型总结
以下 SVG 图展示了各工具在“易用性”与“灵活性”两个维度上的定位: