
Telegraf DiskIO 输入插件完全指南磁盘 I/O 流量与延迟指标采集【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegrafTelegraf 的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 disks 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_override、tags、fieldpass/fielddrop、tagpass/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默认即为truediskio.go即默认不采集序列号示例配置中的# skip_serial_number true是开启后的形态。若开启序列号采集插件会先通过sanitizeSerialNumber()去除字符串中的换行与回车防止 line protocol 注入diskio.go设备无序列号时写入serial unknown。测试用例 diskio_test.go 专门验证了带换行序列号的清洗行为。device_tags基于 udev 的设备元数据标签仅 Linuxdevice_tags允许将 udev 设备属性作为额外标签附加到指标上例如文件系统类型、文件系统用途device_tags [ID_FS_TYPE, ID_FS_USAGE]可用属性列表可通过命令查看udevadm info -q property -n /dev/sda已知限制绝大多数 udev 属性可以访问但DEVTYPE、DEVNAME、DEVPATH三个属性当前无法通过此方式获取DEVNAME与DEVPATH属于插件内部自行解析并用于设备定位的属性见下文源码分析。从源码实现看diskio.godiskTags()会调用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}存在myval1x$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_tags与name_templates的数据源相同由 diskio_linux.go 中的diskInfo()提供。其工作流程仅 Linux 编译非 Linux 平台为 no-op见 diskio_other.go确认设备存在对/dev/dev执行stat获取主次设备号读取 udev 数据库优先读/run/udev/data/bmajor:minorsystemd 风格失败则回退到/dev/.udev/db/block:dev非 systemd 风格解析 udev 文件readUdevData()将E:前缀行解析为keyvalue属性将S:前缀行累积为空格分隔的DEVLINKS设备符号链接列表测试样例见 testdata/udev.txt补充 /sys 信息读取/sys/class/block/dev/uevent获得DEVNAME、DEVTYPE并通过符号链接解析DEVPATH结果缓存以设备文件的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_tags或name_templates选项时才需要因为插件需要读取 udev 数据库来获取设备属性路径环境变量从源码看diskio.go插件在Init()中依次读取HOST_MOUNT_PREFIX、HOST_ROOT、HOST_DEV、HOST_RUN、HOST_SYS环境变量来确定/dev、/run、/sys的实际路径README 中的-v /:/hostfs:ro挂载方式对应其中的HOST_ROOT或HOST_MOUNT_PREFIX用法。测试用例 diskio_linux_test.go 分别验证了HOST_DEV、HOST_ROOT、HOST_MOUNT_PREFIX三种覆盖方式。指标与字段语义diskio测量包含如下 tags 与 fieldstags标签说明name设备名可被name_templates改写serial设备序列号skip_serial_number true时不采集无序列号时为unknownwwid设备 WWID仅 Linux 且/sys/block/dev/wwid存在时写入其他由device_tags自定义的 udev 属性标签fields字段类型语义单位readsinteger, counter完成的读请求次数次writesinteger, counter完成的写请求次数次read_bytesinteger, counter读取的字节数byteswrite_bytesinteger, counter写入的字节数bytesread_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_await与io_svctm本身即毫秒级数值可直接绘图或聚合求均值实际使用中建议配合tagpass过滤掉loop0、ram*等无关虚拟设备避免噪声与基数膨胀。输出示例以下为该插件在两个采集周期产生的典型输出第一段为内核计数器与部分衍生字段diskio,namesda1 merged_reads0i,reads2353i,writes10i,write_bytes2117632i,write_time49i,io_time1271i,weighted_io_time1350i,read_bytes31350272i,read_time1303i,iops_in_progress0i,merged_writes0i 1578326400000000000 diskio,namecentos/var_log reads1063077i,writes591025i,read_bytes139325491712i,write_bytes144233131520i,read_time650221i,write_time24368817i,io_time852490i,weighted_io_time25037394i,iops_in_progress1i,merged_reads0i,merged_writes0i 1578326400000000000 diskio,namesda write_time49i,io_time1317i,weighted_io_time1404i,reads2495i,read_time1357i,write_bytes2117632i,iops_in_progress0i,merged_reads0i,merged_writes0i,writes10i,read_bytes38956544i 1578326400000000000diskio,namesda io_await:0.3317307692307692,io_svctm:0.07692307692307693,io_util:0.5329780146568954 1578326400000000000 diskio,namesda1 io_await:0.3317307692307692,io_svctm:0.07692307692307693,io_util:0.5329780146568954 1578326400000000000 diskio,namesda2 io_await:0.3317307692307692,io_svctm:0.07692307692307693,io_util:0.5329780146568954 1578326400000000000注意第一段输出中namecentos/var_log即name_templates生效的结果——原始设备可能是dm-0经$DM_VG_NAME/$DM_LV_NAME模板改写为逻辑卷名这正是该功能最典型的实战场景。采集流程与实现原理总结综合源码diskio.go一个完整的采集周期如下若配置了含通配符的devices先编译为过滤器否则将各设备名经resolveName()解析符号链接通过ps.DiskIO()gopsutildisk.IOCounters获取所有设备的计数器快照读取/proc/diskstats对每个设备计算name标签应用name_templates、读取wwid、按需读取序列号、按device_tags附加 udev 属性标签组装 11 个基础计数器字段与上一次采集快照做差值检测回绕、计算io_await/io_svctm/io_util以AddCounter写入指标diskio.go并保存本次快照供下轮计算。深入阅读插件配置样例plugins/inputs/diskio/sample.conf插件主实现跨平台逻辑plugins/inputs/diskio/diskio.goLinux 专属实现udev 数据读取、WWIDplugins/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_util、io_await与吞吐量三个维度即可构建一套完整的磁盘健康与性能监控大盘。【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考