土法炼钢 · 系统与基础设施

【SPDK 用户态存储】可观测与性能口径:iostat、直方图与官方 Report 读法

文章导航

分类入口
storagelinux
标签入口
#spdk#observability#bdev_get_iostat#latency#performance-report#histogram#v26.01

目录

没有口径的「更快」会毁掉选型;有字段却不懂语义的 dashboard 会毁掉排障。第 12 篇 给出了 RPC 配置面;本篇只回答:进程内统计在量什么、官方 Performance Report 能证明什么、不能证明什么

本文是系列第 13 篇。不粘贴本机未跑的 fio/RPC 数字,不把官方 PDF 里的 IOPS 抄成本站结论。

本文是「SPDK / 用户态存储栈」系列第 13 篇(共 16 篇)。→ 系列目录

篇目 核心内容
第 12 篇 · JSON-RPC 配置面与生命周期
第 13 篇 · 可观测与性能口径 iostat 语义与 Report 读法
第 14 篇 · 排障坐标系 五轴故障清单

版本锚定:SPDK v26.01bdev_get_iostat 支持 names 数组查询多 bdev(changelog);结构字段见 spdk_bdev_io_stat。Performance Reports 入口:https://spdk.io/doc/performance_reports.html(26.01 页列出当版 NVMe-oF RDMA 等报告,硬件写在标题上)。


一、先分清三种「性能说法」

说法 合法用途 非法用途
进程内 RPC 统计(如 bdev_get_iostat 同一进程、同一配置下看趋势、找异常层 跨机器、跨版本当排行榜
官方 Performance Reports 学习方法、硬件代际、测试脚本与参数组合 当成「你的盘也能跑到这个数」
本机 fio / 应用 SLO 唯一能支撑上线结论的数字 在无直通 NVMe/RDMA 环境伪造

本站实验台账约定:WSL2 / 无直通环境 禁止 伪造输出。下文只讲语义与读法。


二、bdev_get_iostat:字段在量什么

RPC(v26.01 JSON-RPC):

对应累计结构 spdk_bdev_io_stat(文档字段,删减说明:以头文件为准)核心包括:

字段族 含义
bytes_read / num_read_ops(写、unmap、copy 同理) 字节与操作计数
*_latency_ticksmin_*max_* 延迟用 tick 累计/极值,不是现成微秒
ticks_rate(响应里常见 tick_rate 把 tick 换成时间的尺子
io_error 相关 错误计数;可与 reset 模式联动

换算关系(概念,非本机测值):

\[ t_{\text{sec}} = \frac{\text{latency\_ticks}}{\text{tick\_rate}},\quad \overline{t}_{\text{read}} = \frac{\text{read\_latency\_ticks}}{\text{num\_read\_ops} \cdot \text{tick\_rate}} \quad (\text{num\_read\_ops}>0) \]

读数纪律:

  1. 平均延迟由累计 ticks 与 ops 推出;min/max 是极值,不是百分位。
  2. 队列深度相关字段(如 queue_depthio_timeweighted_io_time)依赖轮询采样周期配置;未启用或周期不同,不能跨实例比绝对值。
  3. bdev_reset_iostat / 带 reset 的 get:文档写明——一个消费者重置,影响所有其他消费者。监控与人工排查共用计数器时,禁止「随手 reset」当清屏。

NVMe 多路径场景另有 bdev_nvme_get_path_iostat(路径级);与 bdev 聚合统计分层看,避免把「单路径挂了」读成「整盘没 I/O」。

命令形态(输出略;需本机进程):

scripts/rpc.py bdev_get_iostat
scripts/rpc.py bdev_get_iostat --help   # 查看 names / per_channel / reset 参数

三、延迟「直方图」:概念与边界

bdev 层可启用直方图类观测(版本演进中曾增加粒度与 min/max 配置以控制内存)。读直方图时只承诺三件事:

  1. 桶是离散近似,不是示波器连续曲线;跨版本桶宽可能变。
  2. 直方图回答分布形状(是否双峰、长尾是否变厚);不能在未校准 clock 与队列深度时跨机器比桶计数。
  3. min/max ticks 的关系:极值可被偶发一次 I/O 拉爆;直方图更适合看「主体落在哪一段」,但仍需声明采样窗口与是否 reset 过。

tracepoint 框架(--tpoint-group)属于低开销实验性路径(App Overview 注明文档仍在完善)。排障优先用 iostat / 传输层计数;把 trace 当日常全量采集前先量 CPU 与落盘成本——这是开放运维问题,不是「打开即真相」。

flowchart TD
  io["bdev I/O complete"] --> cnt["ops / bytes counters"]
  io --> ticks["latency ticks min/max/sum"]
  io --> hist["optional histogram buckets"]
  ticks --> rate["divide by tick_rate"]
  hist --> shape["distribution shape only"]

四、怎么读官方 Performance Reports

入口页按发布列出报告;26.01 例如标题即绑定硬件(如 NVMe-oF RDMA on NVIDIA BlueField3)。读法:

步骤 看什么 得出什么
1 报告对应的 SPDK 版本与硬件型号 能否外推到你的代际
2 拓扑(本机 bdev / vhost / NVMe-oF TCP RDMA)
3 队列深度、块大小、读写比、核 mask 口径是否可比
4 用的 SPDK 应用与是否 polling/interrupt 第 9 篇 模式是否一致
5 图表纵轴单位与是否含 CPU 占用 避免只比 IOPS 忽略核税

合法引用句式:「官方 SPDK x.y … Performance Report(硬件 H)在条件 C 下报告了指标 M」——这是外部、方法与硬件绑定的引用。

非法句式:「因此本机 / 本系列测得同等 IOPS」或「所以 SPDK 一定比内核快 N 倍」。

24.05 等更早报告对 NVMe bdev、vhost、TCP/RDMA 更全;跨大版本比较时,先核对 changelog 是否改了默认传输或统计口径,再谈曲线。


五、观测接入排障与发布门禁

统计回答「哪一层在忙 / 错 / 空」;不回答「该不该上 SPDK」。把观测接进门禁时,建议最少三类信号,且都要写清标签(进程、sock 路径、bdev 名、NQN):

  1. 存活与配置对账:关键 bdev / listener / vhost controller 是否存在(RPC 查询,不是「进程在」)。
  2. 速率与错误:ops、bytes、error 的滑动窗口;禁止用单次绝对值当 SLO,除非声明窗口与是否 reset。
  3. 延迟形状:由 ticks 推出的均值 +(若启用)直方图桶占比;max 只作「是否出现极端样本」的告警辅信号。

发布前后对比必须满足:同一 tick_rate 理解、同一 reset 纪律、同一 QD/块大小。否则「发布后变慢」可能只是有人清过计数,或采样周期变了。

与官方 report 的关系:可以把报告里的测试脚本与参数表当成实验设计参考,把报告里的曲线绝对值当成别的机器上的故事。门禁通过条件应写成「相对基线变更不超过团队约定」或「误差计数为零」,而不是「达到某 PDF 的 IOPS」。


六、直方图、百分位与「不能说的话」

运维语言里常说 p99;spdk_bdev_io_stat 的 min/max/sum 不直接等于百分位。要从直方图估百分位,必须:

若系统未启用直方图,只用 max ticks 谈「尾延迟」,会把偶发一次管理 I/O 或热路径外的提交误判成数据面回归。更稳的做法是:应用侧或 initiator 侧用明确窗口的时延直方图,SPDK 侧用 ops/error 与均值 ticks 做分层,两边时间对齐后再归因。

trace 与日志的成本模型也要写进容量规划:全开 -L 或宽 trace group 可能改变你要测的延迟本身。观测税与数据面税必须分开记账,这与代理数据面「全量 access log」问题同构(对照站内可观测性系列的治理直觉即可,不在此展开平台细节)。


七、谱系与争论

谱系(简):块层 iostat 传统提供 ops/字节/繁忙度 → 用户态栈把同类计数挂到 bdev 完成路径,并用 tick 对齐 TSC/时钟源 → 官方 Performance Report 用受控硬件讲「方法可达的上界故事」。三者层级不同,不可互相替代。

争论:轮询栈是否「必须」看 CPU%?一方认为高占用是健康;一方要求按有效 IOPS/核做效率账。没有 workload 与核 mask 时,争论无解。另一争论是监控是否允许 reset 计数:运维方便 vs 多租户共享计数器——文档已站在「影响所有消费者」一侧,产品若要多租户隔离需自建采样副本,而不是争用同一 reset。


八、本篇收束

能解释字段与外部报告边界,才有资格谈性能;谈性能而不写硬件与口径,等于没谈。

下一篇把症状映射到五轴,把本篇信号当成「选轴之后看什么」。


把观测做成「可机器核对」时,优先存原始字段:ops、bytes、latency_ticks、tick_rate、error,再在查询层换算成秒与带宽。先存已换算的浮点微秒,会在 tick_rate 理解错误或跨主机汇总时埋雷。看板与告警规则应引用同一换算库,避免有人用固定 1e9、有人用响应里的 tick_rate 各算各的。

对官方 Performance Reports 的二次使用,建议在团队内建一个「引用模板」:版本、硬件型号、拓扑、块大小、队列深度、读写比、是否 polling、指标名称与单位。缺任一项的引用,不允许进入架构评审材料。这样可以把「看过 PDF」提升为「可复核的外部证据」,同时挡住把特定 DPU/RNIC 报告抄到消费级 NVMe 笔记本上的做法。

采样频率也有机制后果:对 bdev_get_iostat 过高频率轮询会增加 RPC 与消息传递开销;过低则看不见短窗口拥塞。实践上应把「监控采样」与「事故抓取」分开:前者低频、只读、禁止 reset;后者在明确窗口内抓 per_channel 或直方图,并在工单中记录是否 reset。若两套系统共用同一 reset 入口,再精致的看板也会互相踩踏。

延迟数字还要与队列深度、未完成 I/O 数一起读。只报平均延迟、不报当时 QD,等于隐瞒负载。官方 report 通常会交代 QD 与核 mask;你的内部基线若缺这两项,就无法判断回归来自软件变更还是测试注入变了。把 QD、块大小、读写比、核 mask 称为「口径四元组」,任何对比缺少其中一项即判为不可比。

还要注意「层间重复计数」:nvmf 入口、bdev、下层 nvme 可能各自暴露统计,直接相加会双计。归因时应选定一层主真相(通常是最贴近症状的那一层),其他层只做交叉验证。vhost 场景下,guest 内 iostat 与主机 bdev iostat 的差额,往往落在虚拟化通知与轮询批次,而不是简单的「少了一半性能」叙事;没有同步时钟与同窗口负载,不要把差额写成结论。

若团队使用外部时序数据库,导出 RPC JSON 时保留 name 与实例标签,避免所有盘都叫 Nvme0n1 导致序列撞名。多主机汇总前先做标签规范,否则官方 report 式的「单机方法」会被错误放大成集群平均值。

口径四元组(QD、块大小、读写比、核 mask)应与软件版本、bdev 名一并写入每一次内部基线的元数据。缺少元数据的曲线,三个月后无法解释,只能重测。重测成本通常高于当初多写一行标签。

九、参考资料

规范 / 官方文档(A)

源码(A)

上一篇:JSON-RPC 与生命周期 · 系列目录 · 下一篇:排障坐标系

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。


By .