Zabbix Agent 2 Modbus 插件实战指南:TCP/RTU 设备监控配置与 modbus.get 键详解
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 后,插件即可就绪。后续只需确保:
- Modbus 设备与 Agent 2 之间的网络(TCP)或串口(RTU)链路可用;
- 在 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):
- 监控项键参数(优先检查);
- 配置文件中的命名会话参数(
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):
- 校验键与参数个数:键必须为
modbus.get,参数个数为 1–8,否则报错; - 会话解析:若第一个参数命中命名会话,按上文优先级规则回填 Endpoint/SlaveID/Timeout;
- 参数解析:
parseParams()按顺序解析连接类型、串口/TCP 参数、SlaveID、功能码、地址、返回类型、count、字节序与 offset(见 parse.go); - 设备读取:
modbusRead()依据连接类型创建 TCP/RTU/ASCII handler,建立连接并调用对应读功能(ReadCoils/ReadDiscreteInputs/ReadHoldingRegisters/ReadInputRegisters),再关闭连接(见 modbus.go); - 结果转换:
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 的日志体系输出运行信息。当监控项无数据或报错时,可采取以下排查步骤:
- 确认设备可达:TCP 场景用
telnet <ip> <port>或nc -vz验证端口连通性;RTU 场景确认串口存在且无权限问题; - 提高调试级别:在
zabbix_agent2.conf中增大 Agent 的调试级别(DebugLevel),以获取更详细的日志信息,这是 README 明确给出的排查手段(见 README.md); - 核对参数优先级:若键参数与命名会话同时给出了值,确认键参数是否按预期生效;
- 核对类型与字节序约束:例如对线圈使用非
bit类型、或对 8/16 位类型使用mbe/mle均会直接报错,可对照上文参数表格逐一检查; - 参考插件配置模板:modbus.conf 中列出的选项注释与取值范围(如
Timeout的 1–30 范围)可作为配置合法性核对依据。
结语
Zabbix Agent 2 的 Modbus 插件以零安装成本提供了对 TCP、RTU(以及代码层面支持的 ASCII)设备的原生监控能力。通过"命名会话 + 参数优先级"机制,可以在配置文件与监控项键之间灵活分配连接参数;而 modbus.get 的 8 个参数配合类型、字节序、offset 的丰富约束,能够适配大多数工业设备的寄存器布局。本文所有参数默认值、取值范围与优先级规则均与仓库源码实现一致,读者可直接参照 README.md、modbus.go 与 parse.go 进一步核对与扩展自己的监控场景。