使用 low level discovery 添加不同的 instance

到目前为止,zabbix 一般的监控需求都能完全搞定,唯一有问题的就是同一台主机上不同端口的 instance 的监控,比如我在同一台主机上同时起了 27017, 27018, 27019 三个 mongod 的 instance 这类的情况。对此,这两个(1, 2)链接讨论了可行的情况。

1. Parametrized templates,这个需要引入一个抽象的 template,其实类似 nagios 里面通过 register 定义一个抽象可继承的 host/service,这个开发量比较大,目前使用不现实
2. 每一个 instance 单独定义一个 host,这个实现方式虽然可用,也比较简单,但是姿势太丑,如果一台主机有 10 个 instance,那么我需要定义 10 个不同的 host,大量重复无聊的工作
3. 通过 zabbix 2.0 引入的 low level discovery 实现,几乎没有开发量,姿势非常的优美,通过 active check 能自动的检测添加匹配要求的 instance

low level discovery 最重要的就是对不同 instance 特征的匹配问题,我们这里的情况相对比较简单,通过 netstat, lsof 把不同 mongo instance 的匹配出来,然后添加 item, graph, trigger 之类的就好了。
以下的工作参考了这两个链接(1, 2)。

按照起官方文档的解释,其匹配出的结果必须是 JSON 格式:
# cat /etc/zabbix/scripts/discovery.sh
#!/bin/bash
portarray=(`sudo lsof -iTCP -sTCP:LISTEN | grep "$1"| awk '{print $9}' | awk -F: '{if ($NF~/^[0-9].*$/) print $NF}' | sed -n 'p;n' | sort | uniq   2>/dev/null`)

length=${#portarray[@]}
printf "{\n"
printf  '\t'"\"data\":["
for ((i=0;i<$length;i++))
do
        printf '\n\t\t{ '
        printf "\"{#TCP_PORT}\":\"${portarray[$i]}\" }"
        if [ $i -lt $[$length-1] ];then
                printf ','
        fi
done
printf  "\n\t]\n"
printf "}\n"

注意: 在执行 lsof 的时候,别忘了前面有个 sudo,原因后面说明。

在 zabbix_agentd.conf 里面定义 UserParameter:
UserParameter=mongodb.discovery[*], /etc/zabbix/scripts/mongo_discovery.sh "$1"
UserParameter=mongodb.status[*],echo "db.serverStatus().$1" | mongo admin –port $3| grep "$2"|awk -F: '{print $$2}'|awk -F, '{print $$1}'

接下来新建一个 template,在 "Discovery rules" 里面添加新的 "Item prototypes", "Trigger prototypes" 等等就好了。

在使用 low level discovery 的时候,需要注意用户的权限问题。默认情况下,zabbix agent 使用的是 zabbix 这个普通用户运行的,很显然,没有 root 权限,这在执行诸如 netstat, lsof 等命令时出现返回空字符串的情况,比如下面这个,我从另外一台机器上通过 zabbix_get 获取 zabbix agent 的某个 item:
$ zabbix_get  -s 192.168.10.24 -p 18024 -k mongodb.discovery[“mongod”]
{
  "data":[
  ]
}

实践了一下,有下面两种方式可以解决上面的问题,不过都需要以牺牲一定的安全作为代价。
1. 增加 AllowRoot=1 的字段,很明显,这个是让 abx agent 以 root 权限执行
2. 通过 visudo 给 zabbix 用户加上 root 的权限:
zabbix  ALL=(ALL)      NOPASSWD:NOPASSWD:ALL

操作完之后就可以得到期望的结果了:
$ zabbix_get  -s 192.168.10.24 -p 18024 -k mongodb.discovery[“mongod”]
{
  "data":[
    { "{#TCP_PORT}":"27017" },
    { "{#TCP_PORT}":"27018" },
    { "{#TCP_PORT}":"27020" },
    { "{#TCP_PORT}":"27021" },
    { "{#TCP_PORT}":"27023" },
    { "{#TCP_PORT}":"29999" }
  ]
}

另外还有个问题,通过 zabbix_get 返回的结果曾经出现过 "ZBX_NOTSUPPORTED" 的字段,后来调查发现可能跟 agent 这台机器上挂载了 nfs 有关,agent 这台机器执行 netstat(-n), lsof 会非常非常的慢(10s+),可能跟这个有关,具体的原因并不清楚,卸载了之后问题确实消失了。

后来又想到了一种获取端口的方式,直接通过 ps:
$ ps axu | grep mongo | grep -v grep
mongodb    5251  0.8  1.7 18318792 859100 ?     Sl    2012 2534:09 mongod –slave –journal –port 27018 –directoryperdb –fork –logappend –source xxx:27018 –logpath /home/jaseywang/logs/apps_slave.log –dbpath /home/jaseywang/db/apps_slave
mongodb    5619  2.7  3.5 8939240 1759316 ?     Sl    2012 8390:04 mongod –slave –port 27023 –directoryperdb –fork –logappend –source xxx:27020 –logpath /home/jaseywang/logs/av_slave.log –dbpath /home/jaseywang/db/av_slave

然后通过 awk 之类的获取到 –port 后面的数据,由于当初的启动脚本写的不是很规范,各个参数的顺序先前没有约定形成规范,在这种情况下就不是很方便的批量获取到各个机器的 port 参数了 :-(

  • harveyzh

    netstat(-n), lsof 在网络连接很多的时候,的确很慢,ss -lnp 大多数情况会快些。
    在 zabbix_agentd.conf 可以设置命令超时时间 Timeout = 30,应该很减少蛮多命令超时引起的错误。