Telegraf DiskIO 输入插件完全指南:磁盘 I/O 流量与延迟指标采集
2026/9/14 16:23:03 网站建设 项目流程

Telegraf DiskIO 输入插件完全指南:磁盘 I/O 流量与延迟指标采集

【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf

Telegraf 的diskio输入插件用于按块设备(block device)采集磁盘流量(traffic)与等待/服务时间(timing)指标,是磁盘性能监控(延迟、吞吐、利用率、队列深度)的核心数据来源。本文将以plugins/inputs/diskio/README.md为骨架,结合仓库源码(diskio.go、diskio_linux.go)与测试用例,系统讲解其配置项、全部指标字段的语义、源码实现原理、Docker 容器内监控宿主机的部署方式,以及基于 InfluxQL 的常用监控查询。

插件概述

diskio插件从操作系统中读取每个块设备的 I/O 统计信息,包括读写次数、读写字节数、I/O 等待时间、队列深度(in-flight 请求数)、合并读/写次数,并基于两次采集的差值推导出io_await(单次 I/O 平均等待时间)、io_svctm(单次 I/O 服务时间)与io_util(磁盘活跃时间占比)三个衍生指标。

  • ⭐ 引入版本:Telegraf v0.10.0
  • 🏷️ 分类:system(系统类输入插件)
  • 💻 平台支持:all(全部平台,Linux 下功能最完整)

在 Linux 上,这些数值直接对应于内核导出的/proc/diskstats/sys/block/<dev>/stat中的计数器。

说明:diskio关注的是块设备的 I/O 流量与时间,而非文件系统容量。若需采集挂载点、磁盘空间使用率,应使用inputs.disk插件;两个插件可配合使用形成完整的磁盘监控方案。

快速开始

在 Telegraf 配置文件中启用该插件,默认配置如下(完整样例见 sample.conf):

# Read metrics about disk IO by device [[inputs.diskio]] ## Devices to collect stats for ## Wildcards are supported except for disk synonyms like '/dev/disk/by-id'. ## ex. devices = ["sda", "sdb", "vd*", "/dev/disk/by-id/nvme-eui.00123deadc0de123"] # devices = ["*"] ## Skip gathering of the disk's serial numbers. # skip_serial_number = true ## Device metadata tags to add on systems supporting it (Linux only) ## Use 'udevadm info -q property -n <device>' to get a list of properties. ## Note: Most, but not all, udev properties can be accessed this way. Properties ## that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH. # device_tags = ["ID_FS_TYPE", "ID_FS_USAGE"] ## Using the same metadata source as device_tags, you can also customize the ## name of the device via templates. ## The 'name_templates' parameter is a list of templates to try and apply to ## the device. The template may contain variables in the form of '$PROPERTY' or ## '${PROPERTY}'. The first template which does not contain any variables not ## present for the device is used as the device name tag. ## The typical use case is for LVM volumes, to get the VG/LV name instead of ## the near-meaningless DM-0 name. # name_templates = ["$ID_FS_LABEL","$DM_VG_NAME/$DM_LV_NAME"]

启用后,每个匹配的设备会生成一条diskio测量(measurement),默认每 10 秒采集一次(由[agent].interval控制)。除配置文件外,插件还支持 Telegraf 的全局与插件级通用配置项(如name_overridetagsfieldpass/fielddroptagpass/tagdrop以及插件执行顺序配置),详见 CONFIGURATION.md。

配置参数详解

devices:设备选择与通配符

devices用于指定需要采集的设备列表,支持通配符(glob)匹配:

# 采集所有设备(默认) devices = ["*"] # 精确指定 devices = ["sda", "sdb"] # 通配符:采集所有 sd 开头的设备 devices = ["vd*", "sd*", "nvme*"] # 通过 /dev/disk/by-id 下的符号链接指定 devices = ["/dev/disk/by-id/nvme-eui.00123deadc0de123"]

注意:通配符不适用于/dev/disk/by-id这类磁盘别名路径——这类路径上的 glob 行为不受支持。从源码实现看(diskio.go),插件在Init()中通过filter.Compile()将包含 glob 元字符(*?[)的设备模式编译为正则过滤器;Gather()时不仅会匹配设备名,还会逐一匹配设备符号链接(devlinks)来判定归属(diskio.go)。

skip_serial_number:跳过序列号采集

默认情况下插件会尝试读取磁盘序列号并作为serial标签写入。序列号通常通过 SCSI/SATA 设备查询获取,代价较高,且某些环境(如容器、虚拟磁盘)下不可用。将其设为true可跳过该步骤:

skip_serial_number = true

从源码看,该选项同时影响默认值:注册插件时SkipSerialNumber默认即为true(diskio.go),即默认不采集序列号,示例配置中的# skip_serial_number = true是开启后的形态。若开启序列号采集,插件会先通过sanitizeSerialNumber()去除字符串中的换行与回车(防止 line protocol 注入,diskio.go),设备无序列号时写入serial = "unknown"。测试用例 diskio_test.go 专门验证了带换行序列号的清洗行为。

device_tags:基于 udev 的设备元数据标签(仅 Linux)

device_tags允许将 udev 设备属性作为额外标签附加到指标上,例如文件系统类型、文件系统用途:

device_tags = ["ID_FS_TYPE", "ID_FS_USAGE"]

可用属性列表可通过命令查看:

udevadm info -q property -n /dev/sda

已知限制:绝大多数 udev 属性可以访问,但DEVTYPEDEVNAMEDEVPATH三个属性当前无法通过此方式获取(DEVNAMEDEVPATH属于插件内部自行解析并用于设备定位的属性,见下文源码分析)。

从源码实现看(diskio.go),diskTags()会调用diskInfo()获取设备的 udev 数据,只挑选device_tags中列出的、确实存在的属性写入标签;若 udev 数据读取失败,则仅记录一次告警日志(每个设备仅告警一次,由warnDiskTags去重)。

name_templates:设备命名模板

name_templates用于基于 udev 属性重命名设备的name标签。模板支持$PROPERTY${PROPERTY}两种变量写法,插件按顺序尝试列表中的模板,第一个所有变量都能在当前设备上取到值的模板会被采用:

# 典型用例:LVM 卷,用 VG/LV 名称替代无意义的 dm-0 名称 name_templates = ["$ID_FS_LABEL", "$DM_VG_NAME/$DM_LV_NAME"]

模板语法与匹配规则在测试 diskio_linux_test.go 中被完整验证:

模板设备属性结果
$MY_PARAM_1存在myval1
${MY_PARAM_1}存在myval1
x$MY_PARAM_1存在xmyval1
$MISSING(第一个模板)缺失回退到$MY_PARAM_1
$MISSING(唯一模板)缺失使用原始设备名null
$MY_PARAM_1/$MY_PARAM_2都存在myval1/myval2
$MY_PARAM_2/$MISSING部分缺失使用原始设备名

实现逻辑位于diskName()(diskio.go):先用正则\$(?:\w+|\{\w+\})提取模板中的变量,逐个到 udev 属性字典中查找;任何变量缺失即放弃该模板,所有模板都失败则回退为原始设备名。

源码视角:udev 数据的读取与缓存

device_tagsname_templates的数据源相同,由 diskio_linux.go 中的diskInfo()提供。其工作流程(仅 Linux 编译,非 Linux 平台为 no-op,见 diskio_other.go):

  1. 确认设备存在:对/dev/<dev>执行stat,获取主次设备号;
  2. 读取 udev 数据库:优先读/run/udev/data/b<major>:<minor>(systemd 风格),失败则回退到/dev/.udev/db/block:<dev>(非 systemd 风格);
  3. 解析 udev 文件readUdevData()E:前缀行解析为key=value属性,将S:前缀行累积为空格分隔的DEVLINKS(设备符号链接)列表,测试样例见 testdata/udev.txt;
  4. 补充 /sys 信息:读取/sys/class/block/<dev>/uevent获得DEVNAMEDEVTYPE,并通过符号链接解析DEVPATH
  5. 结果缓存:以设备文件的mtime作为失效依据,mtime 未变化则直接返回缓存,避免每个采集周期重复读取磁盘文件。

另外,Linux 下插件还会尝试读取/sys/block/<dev>/wwid并写入wwid标签(getDeviceWWID(),diskio_linux.go),测试TestGetDeviceWWIDHonorsHostSys验证了该行为。

Docker 容器内监控宿主机磁盘

要在容器内监控 Docker 引擎宿主机的磁盘,需要将宿主机文件系统挂载进容器、启用特权模式以访问/dev,并设置HOST_PROC环境变量指向/proc文件系统的挂载位置:

docker run --privileged \ -v /:/hostfs:ro \ -v /run/udev:/run/udev:ro \ -e HOST_PROC=/hostfs/proc \ telegraf

两点说明:

  • /run/udev只读挂载是可选但推荐的:仅当使用device_tagsname_templates选项时才需要,因为插件需要读取 udev 数据库来获取设备属性;
  • 路径环境变量:从源码看(diskio.go),插件在Init()中依次读取HOST_MOUNT_PREFIXHOST_ROOTHOST_DEVHOST_RUNHOST_SYS环境变量来确定/dev/run/sys的实际路径,README 中的-v /:/hostfs:ro挂载方式对应其中的HOST_ROOT(或HOST_MOUNT_PREFIX)用法。测试用例 diskio_linux_test.go 分别验证了HOST_DEVHOST_ROOTHOST_MOUNT_PREFIX三种覆盖方式。

指标与字段语义

diskio测量包含如下 tags 与 fields:

tags

标签说明
name设备名(可被name_templates改写)
serial设备序列号(skip_serial_number = true时不采集;无序列号时为unknown
wwid设备 WWID(仅 Linux 且/sys/block/<dev>/wwid存在时写入)
其他device_tags自定义的 udev 属性标签

fields

字段类型语义单位
readsinteger, counter完成的读请求次数
writesinteger, counter完成的写请求次数
read_bytesinteger, counter读取的字节数bytes
write_bytesinteger, counter写入的字节数bytes
read_timeinteger, counter读请求在设备上的等待时间累计毫秒
write_timeinteger, counter写请求在设备上的等待时间累计毫秒
io_timeinteger, counter设备有 I/O 请求排队的时间累计毫秒
weighted_io_timeinteger, counter加权 I/O 等待时间累计毫秒
iops_in_progressinteger, gauge已下发但尚未完成的 I/O 请求数(瞬时值)
merged_readsinteger, counter被合并的读请求次数
merged_writesinteger, counter被合并的写请求次数
io_utilfloat64, gauge磁盘活跃时间占比(由插件基于差值计算)百分比
io_awaitfloat64, gauge单次 I/O 的平均等待时间(由插件基于差值计算)毫秒
io_svctmfloat64, gauge单次 I/O 的服务时间,不含排队等待(由插件基于差值计算)毫秒

在 Linux 上,上述整型计数器直接对应/proc/diskstats/sys/block/<dev>/stat中的数值。前 11 个字段由底层库(gopsutil 的disk.IOCounters,封装于 ps.go)直接提供;后 3 个衍生字段由插件在Gather()中基于相邻两次采集的差值自行计算(diskio.go)。

reads 与 writes

这两个值在一次 I/O 请求完成时递增。注意内核可能将连续的小请求合并(见下方merged_reads/merged_writes),因此这里的次数反映的是实际下发给设备驱动层的请求数。

read_bytes 与 write_bytes

统计从该块设备读取/写入的字节数,是衡量磁盘吞吐量的原始数据。计算吞吐量速率时需结合采集间隔做derivative(见下文示例查询)。

read_time 与 write_time

统计 I/O 请求在该块设备上累计等待的毫秒数。由于是累加值,当多个请求并发排队等待时,其增长速度可能超过 1000/秒。例如 60 个读请求平均等待 30ms,则read_time会一次性增加 60×30 = 1800 毫秒。

io_time

统计设备上有 I/O 请求排队的时间累计(毫秒)。与read_time/write_time不同,它只记录"有请求在排队"的墙钟时间,不随并发请求数放大。

weighted_io_time

统计 I/O 请求在设备上的加权等待时间累计(毫秒)。若多个请求同时等待,该值按"毫秒数 × 等待中的请求数"的乘积增长(示例同上文的read_time)。它本质上是"请求-时间"的积分量,其导数值可近似代表平均队列深度

iops_in_progress

统计已下发给设备驱动但尚未完成的 I/O 请求数(瞬时值 gauge)。注意它不包含仍在队列中、尚未下发给设备驱动的请求。该字段是采样瞬间的排队/在途请求快照。

merged_reads 与 merged_writes

相邻的读/写请求可能被内核合并以提升效率。例如两个 4K 读可能合并为一个 8K 读再下发给磁盘,因此只会计数(并排队)为一次 I/O。这两个字段反映的就是合并发生的频度——合并率越高,实际下发的 I/O 数相对逻辑请求数越少,有助于评估调度器的合并效率。

io_await、io_svctm 与 io_util

这三个字段并非内核直接提供,而是插件基于两次采样的计数器差值推算:

  • io_await= (读等待时间增量 + 写等待时间增量) / (读次数增量 + 写次数增量),即单次 I/O 的平均等待时间(毫秒),含排队时间;
  • io_svctm= I/O 时间增量 / (读次数增量 + 写次数增量),即单次 I/O 的服务时间(毫秒),不含排队等待;
  • io_util= 100 × I/O 时间增量 / 采集间隔毫秒数,即磁盘处于活跃状态的时间占比(%)。例如两次采集间隔 10 秒内设备活跃了 5 秒,则io_util ≈ 50

从源码看,只有当读写次数增量为正时才会输出io_await/io_svctm,且插件内置了计数器回绕(wrap-around)检测(diskio.go):若读/写次数或时间比上一次采集变小,则认为计数器发生了回绕,本次跳过三个衍生字段的计算以避免产生异常负值。测试 diskio_test.go 专门构造了回绕场景进行验证;而 diskio_test.go 则验证了连续两次采集后三个衍生字段均正确产出。

常用监控查询(InfluxQL)

以下示例查询面向 InfluxDB,可直接套用。

按磁盘与主机计算 I/O 利用率(%)

io_time计数器求非负导数,得到每秒活跃毫秒数,再除以 1000 即为利用率(%),按 60 秒聚合:

SELECT non_negative_derivative(last("io_time"),1ms) FROM "diskio" WHERE time > now() - 30m GROUP BY "host","name",time(60s)

计算平均队列深度

iops_in_progress只能给出瞬时值;而weighted_io_time的导数(除以 1000)可给出采集间隔内的平均排队请求数(平均队列深度):

SELECT non_negative_derivative(last("weighted_io_time"),1ms) from "diskio" WHERE time > now() - 30m GROUP BY "host","name",time(60s)

其他常见监控模式

  • 吞吐量SELECT non_negative_derivative(last("read_bytes"),1ms)*1000 FROM "diskio" ... GROUP BY time(60s)(以 60 秒窗口换算为 bytes/s);
  • 延迟io_awaitio_svctm本身即毫秒级数值,可直接绘图或聚合求均值;
  • 实际使用中建议配合tagpass过滤掉loop0ram*等无关虚拟设备,避免噪声与基数膨胀。

输出示例

以下为该插件在两个采集周期产生的典型输出(第一段为内核计数器与部分衍生字段):

diskio,name=sda1 merged_reads=0i,reads=2353i,writes=10i,write_bytes=2117632i,write_time=49i,io_time=1271i,weighted_io_time=1350i,read_bytes=31350272i,read_time=1303i,iops_in_progress=0i,merged_writes=0i 1578326400000000000 diskio,name=centos/var_log reads=1063077i,writes=591025i,read_bytes=139325491712i,write_bytes=144233131520i,read_time=650221i,write_time=24368817i,io_time=852490i,weighted_io_time=25037394i,iops_in_progress=1i,merged_reads=0i,merged_writes=0i 1578326400000000000 diskio,name=sda write_time=49i,io_time=1317i,weighted_io_time=1404i,reads=2495i,read_time=1357i,write_bytes=2117632i,iops_in_progress=0i,merged_reads=0i,merged_writes=0i,writes=10i,read_bytes=38956544i 1578326400000000000
diskio,name=sda io_await:0.3317307692307692,io_svctm:0.07692307692307693,io_util:0.5329780146568954 1578326400000000000 diskio,name=sda1 io_await:0.3317307692307692,io_svctm:0.07692307692307693,io_util:0.5329780146568954 1578326400000000000 diskio,name=sda2 io_await:0.3317307692307692,io_svctm:0.07692307692307693,io_util:0.5329780146568954 1578326400000000000

注意第一段输出中name=centos/var_logname_templates生效的结果——原始设备可能是dm-0,经$DM_VG_NAME/$DM_LV_NAME模板改写为逻辑卷名,这正是该功能最典型的实战场景。

采集流程与实现原理总结

综合源码(diskio.go),一个完整的采集周期如下:

  1. 若配置了含通配符的devices,先编译为过滤器;否则将各设备名经resolveName()解析符号链接;
  2. 通过ps.DiskIO()(gopsutildisk.IOCounters)获取所有设备的计数器快照(读取/proc/diskstats);
  3. 对每个设备:计算name标签(应用name_templates)、读取wwid、按需读取序列号、按device_tags附加 udev 属性标签;
  4. 组装 11 个基础计数器字段;
  5. 与上一次采集快照做差值:检测回绕、计算io_await/io_svctm/io_util
  6. AddCounter写入指标(diskio.go),并保存本次快照供下轮计算。

深入阅读

  • 插件配置样例:plugins/inputs/diskio/sample.conf
  • 插件主实现(跨平台逻辑):plugins/inputs/diskio/diskio.go
  • Linux 专属实现(udev 数据读取、WWID):plugins/inputs/diskio/diskio_linux.go
  • 非 Linux 平台的 no-op 实现:plugins/inputs/diskio/diskio_other.go
  • 单元测试与回绕/衍生字段验证:plugins/inputs/diskio/diskio_test.go、plugins/inputs/diskio/diskio_linux_test.go
  • 底层系统统计接口(gopsutil 封装):plugins/common/psutil/ps.go
  • 插件通用配置与执行顺序说明:docs/CONFIGURATION.md

若要采集磁盘容量与挂载点使用率,可搭配inputs.disk插件;结合io_utilio_await与吞吐量三个维度,即可构建一套完整的磁盘健康与性能监控大盘。

【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询