用 warp 压测 S3 兼容存储,十分钟跑出一份可复现的基准报告

换盘了、调了配置、升了版本,存储"到底快没快"这个问题,靠感觉和 dd 答不出来。对象存储走 S3 接口,要按 HTTP 请求算吞吐、延迟和分位数,还得把每轮的原始数据留下来,下次才能比。这篇用 warp(MinIO 社区的开源 S3 压测工具)对着 RustFS 把流程走完整:装上、连上被测端点、跑第一轮、把输出读明白、把结果存成可对比的档案。文中所有命令、参数和示例输出都出自 warp 官方 README,没有编造的数字;README 里的示例数字是在它自己的测试环境跑出来的,仅供看懂输出结构,换成 RustFS 的数字得自己跑。

为什么挑 warp,而不是自己写个脚本压

自写循环压测通常栽在两件事上:一是只算平均数,p99 抖动全被平均掉;二是跑完不留原始数据,两周后想复算只能重跑。warp 把这两件事都替你做了:它是 Go 写的单二进制工具,release 页直接下各平台的可执行文件;每次基准跑完,会把每一个请求的明细存成一份 zstd 压缩的 CSV ,默认文件名形如 warp-operation-2026-10-12[143000]-xxxx.csv.zst。事后用 warp analyze 随时重新分析,换个分析参数就能从另一个角度看同一份数据,不用重跑。

安装两条路。省事的直接从 warp Releases 下载对应平台的二进制;有 Go 环境的从源码编,README 要求 Go 1.21 以上:

bash 复制代码
git clone https://github.com/minio/warp.git
cd warp && go build

另外有个独立的 warp-rdma 包,支持把 PUT/GET 的负载走 RDMA 直送内存或显存,标准二进制不支持 --rdma 旗标,需要时从 release 单独装。日常压 S3 接口用不到它。

子命令按操作类型分:get、put、delete、list、stat 各测一种,mixed 按比例混跑多种操作,multipart 和 multipart-put 测分片上传下载,还有 versioned、snowball、atomic 这类专项。没有叫 warp s3 的总命令,别照着老教程找。

把 RustFS 端点和密钥备好,注意那口会被清空的桶

被测端用 RustFS:S3 API 默认监听 9000 端口,所以 endpoint 写 http://<rustfs-host>:9000。注意 9001 是控制台端口,给人看 Web 界面用的,压测别打到这个口。RustFS 是 Apache 2.0 协议、兼容 S3 的分布式对象存储,部署与密钥管理见官方文档。

warp 的连接参数是 --host、--access-key、--secret-key,TLS 加 --tls,自定义 region 加 --region。同样的东西也能走环境变量:WARP_HOST、WARP_ACCESS_KEY、WARP_SECRET_KEY、WARP_REGION、WARP_TLS,写进脚本比每条命令重复敲干净。README 对密钥权限有明确要求:必须能创建、删除、列出桶,还要能上传对象,只读账号跑不了。

最大的一个坑在这里:warp 默认操作一个叫 warp-benchmark-bucket 的桶,每轮基准开始前和结束后都会把它整个清空 。README 用警告框原话强调了桶里不能放任何数据。所以要么用 --bucket 指一个专用的空桶,要么确认目标桶里没有你舍不得的东西。把生产桶指给 warp,等于亲手执行了一次全删。

第一跑:一条命令先测读

最小可用命令就一行:

bash 复制代码
warp get --host=http://<rustfs-host>:9000 \
  --access-key=<ACCESS_KEY> --secret-key=<SECRET_KEY> \
  --duration=1m

warp get 会先往桶里上传 --objects 个 --obj.size 大小的对象(这批上传的耗时也会作为 PUT 统计展示),然后开始随机下载,跑满 --duration 为止。跑完输出长这样(原样引自 README 的 GET 章节,注意这是 README 测试环境的示例数字):

text 复制代码
Operation: GET
* Average: 94.10 MiB/s, 9866.97 obj/s

Throughput, split into 299 x 1s:
 * Fastest: 99.8MiB/s, 10468.54 obj/s
 * 50% Median: 94.4MiB/s, 9893.37 obj/s
 * Slowest: 69.4MiB/s, 7279.03 obj/s

三段结构:第一行是整轮平均,后面是把全程切成 299 个 1 秒段后,最快段、中位段、最慢段各是多少。这两组数差距大不大,比平均值本身更能说明稳不稳。读性能还有 TTFB(首字节时间)的统计,加 --analyze.v 会展开成完整的分位数表,下一节细说。

三个变体按需用。想拿桶里已有的对象当测试集、跳过预上传,加 --list-existing,warp 会先列出至多 --objects 个对象再随机下载它们;想测部分读(Range 请求),加 --range,每次从随机偏移读随机长度,S3 网关类应用和断点续传场景对口的正是这条路;桶开了版本控制想顺带测版本化读,用 --versions=n 指定每个对象放几个版本。默认情况下 warp 上传的都是随机数据,这个设计是有意的:避免存储端对可压缩内容做优化,测出来的才是裸吞吐。

duration、concurrent、obj.size:三个旋钮决定你在测什么

同一套存储,这三个参数不同,数字能差出一个数量级,所以报数字必须连参数一起报。

--duration 控制压多久。太短会撞上预热期,TCP 爬坡、缓存未热都拉低数字;太长浪费时间。一分钟起步,正式对比再加长。

--concurrent 控制并发操作数,默认 20。README 专门提醒:调并发对性能有影响,测延迟的时候尤其明显。想知道吞吐上限,把并发往上调到吞吐不再涨为止;想知道单请求延迟,就压低并发。

--obj.size 控制对象大小,默认值按子命令各不相同。固定大小适合对照测试;加 --obj.randsize 变成随机大小(上限还是 --obj.size),分布按 log2 切,README 给了换算:平均大小约为 --obj.size 乘 0.179151,想要目标平均大小就乘 5.582 得出该填的最大值。它还接受分桶格式,4096:10740,8192:1685,16384:1623 表示 0 到 4096 字节这段占权重 10740,以此类推,用来模拟真实业务的大小分布。

还有个 --autoterm 让 warp 自己判断稳定性:它持续把当前数据降采样成 25 个点,最后 7 个点落在阈值内就提前收工,阈值默认 7.5%(--autoterm.pct 可改)。好处是不用手掐表,代价是每轮实际时长不同,对比时要用 50% Median,不能用 Average,README 明确提醒这种场景下不该比均值,中位数好得多。

单一操作之外,mixed 子命令按比例混跑四种操作,配 --get-distrib、--stat-distrib、--put-distrib、--delete-distrib 四个旗标调比例(设 0 关掉某类),最终占比按各值的分数决定。它有个约束:put-distrib 必须大于等于 --delete-distrib,不然对象池迟早被删空。想贴近真实业务的读写比,用 mixed 比单跑 get 或 put 更有说服力,代价是结果里 GET、PUT 各算各的,吞吐不能简单相加对外报。

输出怎么读:看 Median、看 TTFB,别忘了预热被裁掉了

先说一个容易懵的点:你跑了 60 秒,输出里的分析时长可能只有 59.9 秒甚至更少。别慌,这是 warp 故意裁的。README 写明了分析窗口的起止:从所有线程都完成第一个请求开始,到最后一个线程发起请求为止,两头裁掉,为的是排除预热和收尾的抖动。看懂这个,就不会把"时间对不上"当成 bug。

逐行拆一遍输出:

  • Average:整轮平均吞吐和对象速率。大对象看 MiB/s,小对象和元数据类操作看 obj/s,stat 这种操作只报 obj/s。
  • 50% Median:中位 1 秒段的值。两轮结果对比看这个数,别看 Average,理由上一节说过。
  • Fastest / Slowest:最快和最慢的 1 秒段。Slowest 和 Median 差距悬殊,通常意味着有卡顿源值得去查。
  • TTFB:README 的定义分两个方向,下载是从请求发出到收到响应第一个字节的时间,上传是从请求体最后一个字节发出到收到响应的时间。读场景的响应快慢基本就看它。

默认输出只有均值级别的信息,加 --analyze.v 才展开每请求的分位数(Avg、50%、90%、99%、Fastest、Slowest,TTFB 同样一套),还能按主机拆开看,多节点集群排查单节点拖后腿就靠这个。--analyze.op=GET 只看某一类操作,--analyze.host 只看某一台,分析窗口想再裁就加 --analyze.skip=10s 跳过开头 10 秒。分位数里还藏了两个容易被略过的指标:First Access 和 Last Access,分别是每个对象的首次和末次访问耗时,预上传阶段的 PUT 慢、正式阶段的 GET 快,从这个切面能看出来。想把切段后的时序数据导出去画图,--analyze.out=文件.csv 会把每段的吞吐、对象数、错误数写成标准 CSV,字段表在 README 里。

两次跑的结果要能摆在一起比,流程得先固定

基准数字只在同条件下才有意义。想做到调配置前后的两组数能直接对上,流程比工具重要:

  1. 固定版本和参数:记下 warp 版本、RustFS 版本、完整命令行。并发、对象大小、时长任何一个变了,数字就不该放一起比。
  2. 归档原始数据:每轮的 csv.zst 文件按默认命名存好,这是你的复算凭证;想自己命名用 --benchdata 指定。
  3. 用 warp cmp 出对比报告:warp cmp 旧文件.csv.zst 新文件.csv.zst,输出直接给百分比差值,Average、Median、Slowest 各一行,参数差异也会列出来。
  4. 客户端瓶颈要排掉:单台客户端打不满服务端时,测出来的是客户端的上限。warp 支持多机分布式压测:各机器跑 warp client(默认监听 7761 端口),主控端加 --warp-client=client-{1...10}:7761 协调发压;参数按每个客户端各自生效,--concurrent=8 意味着每台都是 8。散跑的几轮也能事后用 warp merge 合并,但只有时间上真正重叠的数据会被算进去,所以各客户端要时钟同步(README 建议对齐到 1 秒内),最好用 --syncstart 对齐起跑。

还有个对复现特别有用的机制:warp 支持把整套参数写进 YAML 配置文件,README 在 yml-samples 目录放了每种基准类型的样例,用 warp run <file.yml> 运行,命令行里还能用 -var 变量名=值 往模板里注入变量。把每次基准的 YAML 和产出文件放同一个目录归档,半年后别人拿着这份 YAML 就能原样复跑,比翻聊天记录找命令行可靠得多。

被测端是多节点时,--host 支持逗号分隔多地址和 {1...8} 区间展开,warp 默认把请求派给在途请求最少的主机,想改成轮询用 --host-select=roundrobin。

至于上线前该测哪几组读场景,之前写过一篇《S3对象存储上生产:务必做的3组读压测》,讲的是"测什么";这篇讲的是"怎么测",两篇配合着用。

踩坑清单,都写在 README 里了

  • 桶会被清空:再强调一次,warp-benchmark-bucket 或 --bucket 指定的桶,每轮前后都会被 wipe,README 警告框原文是"should not contain any data"。
  • 端口别打错:RustFS 的 S3 API 在 9000,控制台在 9001,压测目标永远是前者。
  • 预热和抖动:分析窗口自动裁掉了预热,但如果你判断预热期更长,用 --analyze.skip 再裁;重跑几轮取一致的区间,比单轮的 Fastest 可信。
  • 数字上不去先怀疑客户端:单机带宽、CPU、连接数都可能先于存储饱和。分布式模式和 warp merge 都是为消掉客户端瓶颈准备的。
  • 并发是每客户端的:分布式压测时总并发是 --concurrent 乘以客户端数,README 原话"parameters apply to each client"。
  • csv.zst 会随规模变大:明细是按请求逐条记录的,时长和并发加上去,文件就跟着变大,几轮长压测的产出归档前留意磁盘占用,别让它把归档盘塞满。
  • warp 测的是 S3 协议层:它评估的是经 HTTP 的 S3 接口表现,底层磁盘的块设备性能要用 fio 这类工具单独测,两者不能互相替代,报数字时别把 S3 压测结果说成磁盘性能。

下次动配置前,先跑这一轮

动作收拢成四步:装 warp(release 二进制,或 Go 1.21+ 自编);--bucket 指个专用空桶;一条 warp get --duration=1m 跑基线;改配置后同参数再跑一轮,warp cmp 出差值。原始 csv.zst 和完整命令行一起归档,半年后还能复算。

相关入口:warp 仓库与 Releases 页(各平台二进制,README 覆盖全部旗标说明),RustFS 文档覆盖部署与密钥配置。

相关推荐
用户298698530141 小时前
Python 实现 Word 转 XPS、PostScript 与 OFD 格式
后端·python·api
蜗牛互联网1 小时前
Python Agent 工具调用:审批令牌、参数白名单和累计预算
java·开发语言·人工智能·windows·后端·python
环境栈笔记1 小时前
指纹浏览器检查代理失败怎么排查?先分清代理、网络和检测服务
前端·人工智能·后端·自动化
做运维的阿瑞1 小时前
Terraform 的 Provider 与 Resource
云原生·云计算·terraform
武子康2 小时前
ESP32 唤醒词标称 98%,为什么还要自己做验收?
人工智能·后端·agent
william_yangshun2 小时前
WordCraft 观察:纯 Rust 重写文字处理器,把文档变成可编程对象
开发语言·后端·rust·文档自动化
IT_陈寒3 小时前
SpringBoot开发实战:从入门到精通
前端·人工智能·后端
geovindu3 小时前
rust: pool Pattern (续)
开发语言·后端·设计模式·rust·对象池简写模式
一条泥憨鱼3 小时前
拦截器与过滤器:一次请求穿过 Spring 时,会先经过谁呢
java·开发语言·后端·spring