Zabbix Agent 2 Modbus 插件实战指南:TCP/RTU 设备监控配置与 modbus.get 键详解

原创2026-10-03 16:48:441,610 阅读
文章标签:可观测性运维指标监控告警异常检测

Zabbix Agent 2 Modbus 插件实战指南:TCP/RTU 设备监控配置与 modbus.get 键详解

本指南围绕 Zabbix Agent 2 内置的 Modbus 监控插件展开,讲解如何通过原生插件同时监控多台 Modbus 设备(支持 TCP 与 RTU 两种连接方式),涵盖命名会话配置、参数优先级规则、modbus.get 键的完整参数语义与返回值格式,并结合仓库源码(modbus.go、parse.go)深入解析各参数的默认值与校验逻辑,帮助读者直接落地一套可运行的 Modbus 设备监控方案。

插件概述:原生 Modbus 监控能力

该插件为 Zabbix 提供了监控 Modbus 设备的原生解决方案(见 插件说明文档)。它运行在 Zabbix Agent 2 进程中,可以同时监控多台 Modbus 设备,并同时支持:

  • TCP 连接:通过 IP 地址和端口访问 Modbus/TCP 设备;
  • RTU 连接:通过串口访问 Modbus RTU 设备。

从源码看,插件底层基于 Go 社区库 goburrow/modbus(3-Clause BSD 许可,声明见 modbus.go),并以一个名为 Modbus、键为 modbus.get 的插件注册进 Agent 2 指标系统(见 modbus.go)。插件通过空导入方式被平台构建文件纳入,例如 plugins_linux.go、plugins_darwin.go 与 plugins_windows.go。

虽然 README 只提及 TCP 与 RTU,但代码中同样支持 ASCII 串口连接(连接类型常量 RTU/ASCII/TCP 见 modbus.go),可视为对串口场景的补充能力。

安装:随 Zabbix Agent 2 免安装集成

根据官方文档,该插件随 Zabbix Agent 2 一同发布,无需任何特殊安装步骤。安装好 Zabbix Agent 2 后,插件即可就绪。后续只需确保:

  1. Modbus 设备与 Agent 2 之间的网络(TCP)或串口(RTU)链路可用;
  2. 在 Agent 配置中定义连接参数并创建监控项。

Agent 2 自带的插件配置参考文件位于 modbus.conf,其中以注释形式给出了每个会话参数的说明,是排查配置语法时的权威依据。

配置:命名会话(Named Sessions)

打开 Zabbix Agent 2 的配置文件 zabbix_agent2.conf,即可通过 命名会话 为每台具体的 Modbus 设备定义专属连接参数。命名会话允许你为每个设备实例单独指定参数,当前支持三个参数:

参数 说明
Endpoint 连接字符串(TCP 或 RTU),如 tcp://127.0.0.1:502、rtu://com1:9600:8n1
SlaveID Modbus 设备地址(从站 ID)
Timeout 已废弃(deprecated):仅对来自 7.0 以下版本 Zabbix Server 的请求生效

其中 Timeout 被标记为 deprecated,仅用于兼容 Zabbix Server 7.0 之前版本发来的请求;新版超时由 Zabbix Server 通过请求上下文下发(源码中 Export() 先取 ctx.Timeout(),仅当 ctx.LegacyTimeout() 为真时才回退到会话的 LegacyTimeout,见 modbus.go)。会话结构体也明确将该字段注释为 "Deprecated value",且取值范围限定在 1–30 秒(见 modbus.go 与 modbus.conf)。

配置示例

假如你有两台设备 MB1(TCP)和 MB2(RTU 串口),在 zabbix_agent2.conf 中加入:

Plugins.Modbus.Sessions.MB1.Endpoint=tcp://127.0.0.1:502
Plugins.Modbus.Sessions.MB1.SlaveID=20
Plugins.Modbus.Sessions.MB1.Timeout=2
Plugins.Modbus.Sessions.MB2.Endpoint=rtu://com1:9600:8n1
Plugins.Modbus.Sessions.MB2.SlaveID=40
Plugins.Modbus.Sessions.MB2.Timeout=4

配置完成后,这些会话名即可作为键(key)中的 connString 直接使用,替代冗长的 URI:

modbus.get[MB1]
modbus.get[MB2,,,30001,1,uint64,le,0]

注意上例第二个键中 MB2 后的 SlaveID 参数留空,此时将回退使用会话中定义的 SlaveID=40——这正是下文要讲的参数优先级。

参数优先级

Zabbix 按以下顺序解析参数(见 README.md):

  1. 监控项键参数(优先检查);
  2. 配置文件中的命名会话参数(Plugins.Modbus.Sessions.<sessionName>.<parameter>),仅在键参数对应位置为空时才生效。

源码中的实现与之对应:Export() 在解析参数前,先检查第一个参数是否为已注册的会话名;若命中会话,则用会话的 Endpoint 覆盖连接串,并在键中 SlaveID 参数缺失或为空时回填会话的 SlaveID(见 modbus.go)。因此在键中显式给出的值总是优先于会话配置。

支持的键:modbus.get

modbus.get[endpoint,slaveid,function,address,count,type,endianness,offset]

从 Modbus 设备读取值,返回 JSON 格式的数字数组(当请求数量为 1 时直接返回单个数值)。该键在插件注册时声明的用途为 "Returns a JSON array of the requested values"(见 modbus.go)。

参数详解

# 参数 说明 默认值 / 取值范围
1 endpoint TCP 或 RTU 连接字符串,如 tcp://localhost:511、rtu://COM1:9600:8n1 必填;协议由 scheme:// 前缀识别(支持 tcp/rtu/ascii,见 parse.go)
2 slaveid 设备 Modbus 地址 可选;TCP 默认 255,串口默认 1;RTU/ASCII 串口取值范围 0–247(见 parse.go)
3 function Modbus 读功能码 可选;取值 1、2、3、4(1=线圈 Read Coils,2=离散输入 Read Discrete Inputs,3=保持寄存器 Read Holding Registers,4=输入寄存器 Read Input Registers,见 modbus.go)
4 address 第一个寄存器/线圈/输入的地址 可选;默认 00001(见 parse.go)
5 count 要返回的数值个数 可选;默认 1,且不允许为 0
6 type 返回数据类型 可选;bit、int8、uint8、uint16、int16、uint32、int32、float、uint64、double;默认 bit(线圈/离散输入)或 uint16(寄存器)
7 endianness 字节序 可选;be(大端)、le(小端)、mbe(中端-大端)、mle(中端-小端);默认 be
8 offset 从 address 起需要丢弃的寄存器/位个数 可选;默认 0

值得注意的细节

  • 功能码与地址的隐式映射:当 function 留空时,插件允许使用 Modbus 惯例地址前缀自动推断功能码——1xxxx 映射到线圈(功能 1)、2xxxx 映射到离散输入(功能 2)、3xxxx 映射到输入寄存器(功能 4)、4xxxx 映射到保持寄存器(功能 3),并将传入地址减 1 转换为协议内部使用的零基地址(见 parse.go)。这也是 README 示例中 30001 出现的原因。
  • 类型与功能码的约束:线圈/离散输入只能使用 bit 类型,寄存器则禁止使用 bit(见 parse.go)。
  • count 与寄存器数量的换算:插件会根据类型自动把返回个数换算为实际读取的寄存器数——int8/uint8 每 2 个字节占 1 个寄存器,32 位类型每值占 2 个寄存器,double/uint64 每值占 4 个寄存器,换算后的总读取数不得超过 65535(见 parse.go)。
  • 字节序约束:bit 类型仅支持 be;mbe/mle(中端字节序,常见于部分 PLC 的大数类型)仅对 16 位以上的类型有意义,int8/uint8/int16/uint16 不允许使用中端字节序(见 parse.go)。
  • offset 语义:返回结果会跳过从 address 开始的前 offset 个寄存器/位;offset + count 不得超过 65535(见 parse.go)。

返回值格式

  • count=1 时返回单个数值(如 123);
  • count>1 时返回 JSON 数组(如 [123,456])。

位类型会按位展开:每个字节拆成 8 个位值(getArr16 的实现见 endianness.go);多字节类型则按指定字节序与中端字节序规则重组后输出(见 endianness.go)。

底层实现:请求流程与并发安全

一次 modbus.get 请求的完整链路为(见 modbus.go):

  1. 校验键与参数个数:键必须为 modbus.get,参数个数为 1–8,否则报错;
  2. 会话解析:若第一个参数命中命名会话,按上文优先级规则回填 Endpoint/SlaveID/Timeout;
  3. 参数解析:parseParams() 按顺序解析连接类型、串口/TCP 参数、SlaveID、功能码、地址、返回类型、count、字节序与 offset(见 parse.go);
  4. 设备读取:modbusRead() 依据连接类型创建 TCP/RTU/ASCII handler,建立连接并调用对应读功能(ReadCoils/ReadDiscreteInputs/ReadHoldingRegisters/ReadInputRegisters),再关闭连接(见 modbus.go);
  5. 结果转换:pack2Json() 将原始字节按类型、字节序、offset 转换为数值或 JSON 数组。

值得注意的是,插件在读取期间会按连接地址/串口名加锁(named.Lock,见 modbus.go),避免对同一设备/串口的并发请求互相干扰,同时支持多个不同设备的并行监控。

串口连接串格式解析

RTU/ASCII 的连接串格式为 rtu://<端口>:<波特率>:<数据位><校验><停止位>,例如 rtu://com1:9600:8n1 表示 9600 波特、8 数据位、无校验(N)、1 停止位。解析逻辑见 parse.go:

  • 若不指定波特率等参数,串口默认值为 115200 波特 / 8 数据位 / 无校验 / 1 停止位;
  • 数据位仅支持 5–8;校验仅支持 n(无)/e(偶)/o(奇);停止位仅支持 1/2;
  • 在非 Windows 平台上,不带 / 的端口名会自动补全为 /dev/<端口>。

TCP 连接串格式解析

TCP 连接串为 tcp://<地址>:<端口>。解析时若未指定端口,将自动使用 Modbus 标准端口 502(见 parse.go)。

故障排查(Troubleshooting)

该插件使用 Zabbix Agent 的日志体系输出运行信息。当监控项无数据或报错时,可采取以下排查步骤:

  1. 确认设备可达:TCP 场景用 telnet <ip> <port> 或 nc -vz 验证端口连通性;RTU 场景确认串口存在且无权限问题;
  2. 提高调试级别:在 zabbix_agent2.conf 中增大 Agent 的调试级别(DebugLevel),以获取更详细的日志信息,这是 README 明确给出的排查手段(见 README.md);
  3. 核对参数优先级:若键参数与命名会话同时给出了值,确认键参数是否按预期生效;
  4. 核对类型与字节序约束:例如对线圈使用非 bit 类型、或对 8/16 位类型使用 mbe/mle 均会直接报错,可对照上文参数表格逐一检查;
  5. 参考插件配置模板:modbus.conf 中列出的选项注释与取值范围(如 Timeout 的 1–30 范围)可作为配置合法性核对依据。

结语

Zabbix Agent 2 的 Modbus 插件以零安装成本提供了对 TCP、RTU(以及代码层面支持的 ASCII)设备的原生监控能力。通过"命名会话 + 参数优先级"机制,可以在配置文件与监控项键之间灵活分配连接参数;而 modbus.get 的 8 个参数配合类型、字节序、offset 的丰富约束,能够适配大多数工业设备的寄存器布局。本文所有参数默认值、取值范围与优先级规则均与仓库源码实现一致,读者可直接参照 README.md、modbus.go 与 parse.go 进一步核对与扩展自己的监控场景。

登录后查看全文
zabbix