系统环境
ZABBIX服务器:centos7,zabbix6.4,jq,zabbix-sender-3.0.5
EMQX服务器:centos7, emqx4.4.3
监控思路
通过 EMQX 的 API 获取实时监控数据(包括统计信息和指标),然后将这些数据发送到 Zabbix 服务器进行监控。具体来说,脚本执行了以下操作:
- 从 EMQX API 获取统计信息(stats)、指标(metrics)和节点信息(nodes)。
- 解析这些 JSON 数据,并提取出所需的监控指标。
- 通过 Zabbix Sender 将提取的指标发送到 Zabbix 服务器。
实施过程
数据获取
脚本使用 curl 命令向 EMQX 服务器的 API 发送请求,获取以下三类数据,当然,也可以自行添加更多的需求指标:
Stats: 包含有关主题、订阅、连接等的统计信息。
Metrics: 包含有关消息传递、连接数、数据包等的详细指标。
Nodes: 包含节点的状态信息,如版本、运行时间、内存使用情况等。
可参考官方接口文档:https://docs.emqx.com/zh/emqx/v4.4/advanced/http-api.html#get-api-v4
请求示例,"$2:$3"是账号密码,$4是EMQX服务器IP
脚本内的命令示例
stats=$(curl --basic -u "$2:$3" -k -s "http://$4:8081/api/v4/stats/")
metrics=$(curl --basic -u "$2:$3" -k -s "http://$4:8081/api/v4/metrics/")
nodes=$(curl --basic -u "$2:$3" -k -s "http://$4:8081/api/v4/nodes/")手动执行的命令示例
curl --basic -u "admin:password" -k -s "http://192.168.1.1:8081/api/v4/nodes"
数据解析和处理,发送
使用 jq 工具,脚本从获取的 JSON 数据中提取出特定的键值对。这些键值对由 STATS_KEYS、METRICS_KEYS 和 NODE_METRICS_KEYS 数组定义。脚本遍历这些数组,提取相应的值。使用 zabbix_sender 工具将提取的数据发送到 Zabbix 服务器。每个数据项都通过指定的 Zabbix 主机名、键名和数据值进行发送。例如:
例如,处理 stats 数据的代码如下,$key对应相关接口指标也是是监控项的键名,$1是zabbix服务器IP,$out 是从 EMQX API 返回的数据值:
for key in "${STATS_KEYS[@]}"; doout="$(jq -r --arg arg "$key" '.data[0].stats[$arg]' <<< "$stats")"zabbix_sender -z 127.0.0.1 -s "$1" -k "emqtt[$key]" -o "$out" > /dev/null 2>&1
done
完整的监控脚本如下
放在zabbix服务器的 /usr/local/zabbix/share/zabbix/externalscripts 路径下,需要赋予执行权限chmod +x 脚本名
以及加到zabbix用户组chown zabbix:zabbix 脚本名
#!/bin/bash
#set -x# 更新 STATS_KEYS 以匹配 EMQX API 返回的 stats 数据
STATS_KEYS=("topics.count""topics.max""subscriptions.shared.count""subscriptions.shared.max""subscriptions.count""subscriptions.max""subscribers.count""subscribers.max""sessions.count""sessions.max""routes.count""routes.max""retained.count""retained.max""live_connections.count""live_connections.max""connections.count""connections.max""channels.count""channels.max"
)# 更新 METRICS_KEYS 以匹配 EMQX API 返回的 metrics 数据
METRICS_KEYS=("messages.acked""packets.publish.received""messages.dropped.no_subscribers""packets.publish.sent""delivery.dropped.qos0_msg""packets.connect.received""packets.pubcomp.received""delivery.dropped.queue_full""session.resumed""packets.received""packets.unsubscribe.received""delivery.dropped""messages.retained""packets.pubrel.missed""packets.pubrec.sent""packets.pubrec.received""bytes.sent""messages.dropped.await_pubrel_timeout""packets.auth.sent""packets.pubrec.inuse""packets.puback.received""messages.qos1.sent""session.created""messages.qos2.sent""session.terminated""client.connect""packets.unsuback.sent""packets.puback.missed""client.subscribe""bytes.received""packets.disconnect.sent""packets.publish.auth_error""packets.pingresp.sent""packets.pubrel.sent""client.acl.deny""session.discarded""messages.received""packets.subscribe.auth_error""packets.publish.error""packets.publish.dropped""messages.delayed""messages.delivered""messages.qos2.received""client.connack""messages.sent""packets.pubrel.received""client.unsubscribe""packets.puback.inuse""client.authenticate""packets.connack.error""client.acl.cache_hit""delivery.dropped.expired""client.auth.anonymous""messages.forward""packets.pingreq.received""packets.pubrec.missed""packets.pubcomp.inuse""messages.qos1.received""client.check_acl""messages.publish""packets.publish.inuse""packets.unsubscribe.error""packets.disconnect.received""packets.subscribe.error""packets.auth.received""packets.connack.sent""packets.puback.sent""client.disconnected"