感谢作者方傅皓敏、傅皓樑供稿!欢迎投稿分享你的使用经验。
傅皓樑
【背景】由于公司业务平台的网络环境苛刻,以Zabbix server为核心开发设计一套适应性强的监控运维境更强的方案,不仅能满足当下的需求还能方便后续扩展。写这篇文档的初衷希望遇到类似环境的同学有一个参考,在碰到严格、复杂的网络环境,数量庞大机器管理,如何能够利用 Zabbix 的特性做到深度监控。
解决方案:
目前用的最多 zabbix 分布式如下图,那为什么我们不用呢?zabbix agent 上报数据需要访问 zabbix proxy 10051 端口,通常整个环境也是在一个局域网内亦或者整个网络环境可以调控。
而我们的网络环境如下,环境限制问题有:
通过 go 编写 ws agent 主动上报,这样只要 ws server 端开 80 端口就能解决此问题,go 的 agent 压缩后只有 3M,可以解决包过大传输的问题和 3、4 问题,演变的数据上报架构如下。
解决方案:
zbx_sender -z zabbix_server的ip -s hostip -key 自动发现的key -o {“data”:[“#{ITEM_NAME}”:“监控项名字”,”#{ITEM_KEY}”:“监控项key”]}
这个是 zabbix 自带的命令,可以使用 python、go、java 等语言自己写一个,我们是用 python 写的。第一个问题解决了,下面就是第二个自动发现的监控项都有存活周期,这个周期如何更新,例如:自动发现设置 7 天后删除,那 7 天后失效了怎么办,经过测试上面创建监控项命令对存在的监控项再次创建就会更新监控项存活时间,例如昨天创建的监控项到今天还有 6 天就要被删除了,那今天再次创建监控项就会从今天开始计时往后延长 7 天。最后一个问题就是插入数据了,这个比较容易解决,命令提供在下面,在这里我们发现一个坑不知道大家有没有注意,使用 zbx_sender 时发送的数据时间是执行命令时的,而监控项数据在客户端采集到执行命令会有时间差,这个问题在自制 zab_sender 中已经解决,里面有个参数是 value_clock,脚本网上可以找到,看似问题都解决了其实不然。插入监控项数据命令。
zbx_sender -z zabbix_server的ip -s hostip -key 监控项key -o 监控项值
我们的监控项数量有30W+,相信大家的数量也不会少,我们 agent 完成后大约有 100W+的监控项,那如果监控项间隔为 5 分钟,相当于每次创建监控项任务要 5 分钟发送 100W 次,zabbix server 的 lld 进程最多只能开启 100 个,发送命令可以分布式多线程、多进程来发送,但是接收只有 1 个 zabbix server,我们运行到后面 zabbix server 就出现不会执行队列(创建监控项、更新监控项、插入数据)了,队列全部溢出。
对于这个问题我们尝试了 以下2 种方式,虽然全部失败但是也积累了经验。
1. 双 zabbix server 模式
这个模式查了相关文档没人用过,使用后会产生 2 个告警,查了源码和相关文档后找出原因,监控项数据发送给 zabbix server 后,zabbix server 会匹配对应监控项的触发器规则,如果匹配后发送给数据库,这样就不难理解会出现 2 个告警了,几个 zabbix server 就会有几个 zabbix server,这样问题还难不倒我们,一个 zabbix server 接收监控项数据,一个 zabbix server 接收创建监控项及更新监控项,但是就是这样对于大量更新监控项也扛不住,通过分析 lld 大部分工作在于更新监控项存活时间,从日志跟踪中找到下面的 sql,而创建监控项通常就创建一次,所以只要解决了这个问题就完美了。
update item_discovery set lastcheck=1624511695 where itemid=1674491
通过分析 zabbix server log 每一个触发更新监控项会输出 133 行日志,至少有 50 个以上的动作,那 100W 监控项的工作量可想而知了,如果采用批量 update 直接对数据库进行操作就可以解决这个问题了。解决方法如下,在消费监控项数据时把对应节点监控项输出一份到监控项需更新队列中,通过脚本汇聚这些监控项与 zabbix 数据库 items 表进行关联取差集得到需要更新的监控项 id,然后使用 update 批量更新,sql 如下,item_free 表为关联后取得 itemid 写入表中,不然不好操作:
Update item_discovery set lastcheck=UNIX_TIMESTAMP(NOW()),ts_delete=UNIX_TIMESTAMP(NOW())+(7*24*3600) where itemid in (select itemid from item_free)
2.zabbix proxy 模式
zabbix proxy 不支持 lld,所以发送创建监控项数据后,不会创建监控项,查看配置文件就没有 lld 的进程,查了下原理也释然,zabbix proxy 是定时读取 zabbix server 的配置数据保存在 zabbix proxy 数据库中,如果能够创建监控项信息,那多个 zabbix proxy 数据上传时会产生数据冲突。
我们数据库从 mysql->postgresql->tidb 不断进行迭代,从 mysql 说起吧,现在还在 mysql 的通常都是分表分库的方式,单标 1000W 已经影响性能了,当初 mysql 优化到极限单标 9000W 数据,查询 3 秒,面对现在动不动几亿的数据量实在扛不住,postgresql 是我们上一代的 zabbix server 数据库,单表性能没得说,目前各个 zabbix 场景下用的最多的就属他了,但是 pg 是单点的不能用于扩展,看着每天增加的指标量,数据阶梯式增长,在这种情况下分布式数据库是必选的方案,tidb 是开源的分布式数据库,想要扩展性能可以通过横向扩节点的方式,简单容易上手、社区活跃、官方解答问题非常积极,对于我们运维人员是一个福音,再更新数据库后虽然问题很多,但是大势所趋目的办法。
问题 1:zabbix server 日志排查问题?
我们的架构核心是通过 zabbix_sender 发送 zabbix_server 创建监控项、更新监控项、更新监控项值,在更新自动发现监控项存活和创建监控项时遇到 zabbix_server 处理不过来,具体的排查通过查看 zabbix server 的 lld 日志来判断,这里如果直接打开 debug 日志满屏刷无法定位问题,通过设置日志文档来打开 lld 日志输出,具体参考:https://www.zabbix.com/documentation/5.0/manpages/zabbix_server
问题 2:如何快速更新自动发现监控项存活?
监控项数据增加监控项更新操作就会非常多,统计了下有 133 行日志,创建 lld 监控项多好几倍,自动发现(lld)都压在 zabbix_server 上,通过日志发现一个监控项的更新执行逻辑步骤非常多,那在多并发的情况下 zabbix_server lld 进程数量就 100,大量的 update 可能还会触发相互锁的问题,而 zabbix proxy 还不支持 lld 进程,通过日志发现更新最终就是执行一个 updatesql,如下:
update item_discovery set lastcheck=1624511695 where itemid=1674491
思索后通过把需要更新监控项聚合后通过 sql 批量更新,直接对数据库操作不仅速度更快,还大大减少了 zabbix server 的压力,sql 操作如下,对统计后的 itemid 批量更新。
Update item_discovery set lastcheck=UNIX_TIMESTAMP(NOW()),ts_delete=UNIX_TIMESTAMP(NOW())+(7*24*3600) where itemid in (select itemid from item_free)
# 前置库安装
yum install unixODBC-devel mysql-devel net-snmp-devel libxml2-devel libcurl-devel libevent-devel gcc -y
useradd zabbix
#安装zabbix5.4
cd /opt/zabbix-5.4/zabbix-5.4.0/
./configure --prefix=/usr/local/zabbix --sysconfdir=/etc/zabbix/ --enable-server --enable-agent --enable-ipv6 --with-net-snmp --with-libcurl --with-mysql --with-libxml2
make && make install