尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Zabbix自定义监控实战:脚本编写、Agent配置与日志服务监控

Zabbix自定义监控实战:脚本编写、Agent配置与日志服务监控 1. 什么是Zabbix自定义监控不是“加个监控”那么简单而是把系统脉搏握在自己手里Zabbix自定义监控说白了就是绕开Zabbix自带模板的“标准答案”亲手写脚本去问服务器“你此刻CPU到底多烫”“你的Nginx进程还在喘气吗”“/var/log/nginx/error.log里刚冒出来的502错误是不是又来了”——它不是锦上添花的功能扩展而是Zabbix真正从“看门狗”升级为“私人健康管家”的分水岭。我干这行十年见过太多团队卡在这一关买了Zabbix企业版装完就只盯着那几个预设的CPU、内存、磁盘图表结果线上服务半夜挂了告警邮件却安静如鸡日志里早堆满了Connection refusedZabbix却还在报告“服务端口通”。问题出在哪不是Zabbix不行是没把它“驯服”——而驯服的唯一方式就是用shell脚本、Python脚本这些最原始也最锋利的工具把监控逻辑直接焊进业务毛细血管里。关键词里的“zabbix”“自定义监控”“脚本”“服务”“日志”每一个都不是孤立存在zabbix是平台骨架自定义监控是肌肉神经脚本是控制指令服务和日志则是你要实时把脉的具体器官。它解决的从来不是“能不能监控”而是“监控得准不准、快不快、有没有用”。适合谁运维工程师必须掌握因为这是你判断故障根因的第一手证据开发同学也该懂尤其微服务架构下每个Pod的日志格式、健康检查端点都千差万别靠通用模板根本抓不住关键指标就连测试同学用自定义脚本做压测后自动解析JMeter生成的jtl日志也能把性能瓶颈定位时间从2小时压缩到5分钟。这不是炫技是让监控从“事后诸葛亮”变成“事前预警器”的硬功夫。2. 为什么非得自己写脚本Zabbix原生能力的三道硬伤与真实战场代价很多人觉得Zabbix自带的“Agent”“SNMP”“JMX”已经够用直到某次大促凌晨三点被电话叫醒——订单服务响应时间飙升到8秒Zabbix仪表盘上所有预设指标CPU、内存、线程数全在绿区。最后排查发现是数据库连接池耗尽但Zabbix默认根本不采集“活跃连接数”这个指标。这就是原生能力的第一道硬伤指标覆盖存在结构性盲区。Zabbix官方模板像一本《常见病诊疗手册》但你的业务系统是独一无二的“疑难杂症患者”。比如微服务架构中Spring Boot Actuator暴露的/actuator/metrics/jvm.memory.used指标Zabbix 6.0之前压根不支持直接解析JSON嵌套路径再比如K8s环境Zabbix Agent无法直接获取Pod的重启次数而这个值恰恰是判断容器健康度的黄金指标。第二道硬伤是日志解析的粗暴与滞后。Zabbix内置的Log Monitoring功能表面看能监控日志文件实则有致命限制它只能基于正则匹配整行日志且不支持上下文关联。举个真实案例某支付系统需要监控“交易失败但未触发补偿”的异常链路。日志里先出现[ERROR] OrderService: payment failed, orderId123455秒后应有[INFO] CompensateService: start compensation for 12345。Zabbix Log Monitoring只能分别告警这两行却无法判断“有失败无补偿”这个复合事件。而用自定义脚本你可以用awk读取日志流用数组缓存最近10条失败记录再实时匹配后续补偿日志毫秒级识别异常闭环。第三道硬伤最隐蔽也最致命服务状态判定的逻辑僵化。Zabbix默认用net.tcp.port[host,80]判断Web服务存活这等同于只确认“端口开着”却不管Nginx是否返回502、Tomcat是否已OOM崩溃但进程仍在。我们曾遇到一个案例某Java服务因GC频繁导致HTTP请求超时Zabbix显示“端口通、进程在”但用户实际无法下单。后来用自定义脚本改写检测逻辑curl -s -o /dev/null -w %{http_code} http://localhost:8080/health | grep -q 200瞬间揪出问题。这背后是核心认知转变——监控的本质不是查“进程是否存在”而是查“业务是否可用”。这三道硬伤带来的真实战场代价是什么平均故障定位时间MTTR延长3-5倍关键业务指标漏报率超40%更可怕的是团队会陷入“监控幻觉”看着满屏绿色图表误以为系统坚不可摧直到用户投诉电话打爆客服热线。所以自定义脚本不是可选项而是Zabbix发挥真正价值的必经之路。3. 自定义监控的核心实现路径从脚本编写、Zabbix配置到数据落地的全链路拆解3.1 脚本设计的底层逻辑不是写代码而是构建“可观测性契约”写监控脚本的第一步永远不是打开vim敲代码而是明确“我要向Zabbix承诺什么”。这个承诺就是可观测性契约脚本必须稳定输出单一、确定、无歧义的数值或字符串且每次执行耗时严格控制在Zabbix Agent的Timeout阈值内默认3秒。我见过太多失败案例源于契约意识缺失有人写Python脚本调用requests库抓取API网络抖动时耗时超10秒Zabbix Agent直接kill进程导致监控项持续显示“Not supported”还有人用grep在10GB日志里全文搜索脚本跑一次要2分钟Zabbix干脆放弃轮询。因此脚本设计必须遵循三大铁律第一输入绝对可控。所有外部依赖必须预设兜底方案。比如监控MySQL主从延迟脚本不能直接执行mysql -e show slave status\G而要先检查mysql命令是否存在、~/.my.cnf配置文件是否可读、主从连接是否超时。我的标准模板开头永远是#!/bin/bash # 检查依赖 command -v mysql /dev/null 21 || { echo mysql command not found; exit 1; } [ -f ~/.my.cnf ] || { echo ~/.my.cnf not found; exit 1; } # 设置超时避免hang住 timeout 2 mysql -N -s -e SELECT Seconds_Behind_Master FROM information_schema.slave_status 2/dev/null | awk {print ($1 ~ /^[0-9]$/ ? $1 : 0)}这里timeout 2强制2秒内返回awk确保只输出数字空值或错误时返回0便于Zabbix设置触发器阈值。第二输出绝对纯净。Zabbix Agent只认“一行一个值”任何多余字符都会导致解析失败。曾有个同事在脚本末尾加了echo check finished结果Zabbix收到123\ncheck finished整个监控项失效。正确做法是用printf %d $value替代echo $value并确保脚本结尾无空行。第三逻辑绝对幂等。脚本执行1次和执行100次对系统状态零影响。严禁在监控脚本里写rm -rf /tmp/cache这类操作——某次Zabbix Server配置错误导致每秒调用脚本结果清空了生产环境临时目录。所有临时文件必须用mktemp创建独立路径执行完立即清理。3.2 Zabbix Agent端配置让脚本成为Agent的“原生器官”脚本写好只是第一步必须让Zabbix Agent“认识”它。核心在于UserParameter配置它本质是给脚本注册一个“别名”让Zabbix Server能像调用内置函数一样调用你的脚本。配置位置在/etc/zabbix/zabbix_agentd.conf或/etc/zabbix/zabbix_agentd.d/userparameter_custom.conf推荐后者便于管理。以监控Nginx请求速率为例# /etc/zabbix/zabbix_agentd.d/userparameter_nginx.conf # UserParameterkey,command UserParameternginx.requests.persec,/usr/local/bin/check_nginx_requests.sh UserParameternginx.connections.active,/usr/local/bin/check_nginx_connections.sh这里nginx.requests.persec就是你在Zabbix Web界面创建监控项时填写的Key。关键细节在于路径必须绝对/usr/local/bin/check_nginx_requests.sh不能写成./check_nginx_requests.shAgent运行用户通常是zabbix没有当前工作目录概念权限必须精准脚本需对zabbix用户可执行chmod 755 /usr/local/bin/check_nginx_requests.sh且zabbix用户要有读取Nginx状态页的权限若用stub_status模块需配置location /nginx_status并允许zabbix用户访问参数传递要安全如果脚本需要动态参数如监控不同端口的服务用$1接收但必须校验# check_service_port.sh if [[ ! $1 ~ ^[0-9]$ ]] || [ $1 -lt 1 ] || [ $1 -gt 65535 ]; then echo Invalid port number exit 1 fi nc -z 127.0.0.1 $1 echo 1 || echo 0对应的UserParameter写成UserParameterservice.port.status[*],/usr/local/bin/check_service_port.sh $1配置完成后必须重启Agent并验证sudo systemctl restart zabbix-agent然后手动执行zabbix_get -s 127.0.0.1 -k nginx.requests.persec确认返回预期数值。这一步跳过90%的后续问题都源于此。3.3 Zabbix Server端配置从监控项到触发器的精密组装Agent端配置好Server端才是真正的“指挥中心”。在Web界面依次创建监控项Item→ 应用集Application→ 触发器Trigger→ 图形Graph。以日志监控为例展示关键配置要点监控项Item配置Name清晰描述用途如“Nginx Error Log 502 Count (last 5min)”Type选择“Zabbix agent”若脚本在Agent本地运行或“Zabbix agent (active)”若Agent主动上报Key必须与UserParameter定义的key完全一致如nginx.error.502.countUpdate interval根据业务敏感度设定。高频指标如QPS设30秒低频指标如日志错误计数设300秒避免Agent过载History storage period日志类指标建议设长些如90天便于追溯历史趋势Trends storage period趋势数据用于图形可设短些如365天节省数据库空间。应用集Application这是常被忽视的组织利器。不要把所有监控项扔进“Default Application”按业务维度建应用集Nginx-Web,MySQL-DB,Log-Error。这样在主机详情页你能一眼看到“这个主机的Nginx相关指标在哪”而不是在上百个监控项里滚动查找。触发器Trigger配置这才是监控的灵魂。避免用“大于阈值就告警”的简单逻辑。以“Nginx 502错误突增”为例Expression{HOSTNAME:nginx.error.502.count.last(300)}5 and {HOSTNAME:nginx.error.502.count.avg(300)}3last(300)取最近5分钟最新值判断是否突发avg(300)取5分钟均值排除毛刺干扰Severity设为“High”并关联告警媒介邮件、钉钉、短信Dependencies设置依赖关系如“只有当Nginx进程存活触发器为OK时502告警才生效”避免服务宕机时产生无效告警。图形Graph不要只画单指标。把nginx.requests.persec、nginx.connections.active、nginx.error.502.count画在同一张图上时间轴对齐你立刻能看出“QPS飙升时502是否同步上涨”这是根因分析的黄金视图。4. 四类高频场景的脚本实战从服务存活到日志深度解析的完整代码与避坑指南4.1 服务存活监控超越端口检测的业务级健康检查监控服务“活着”是最基础需求但Zabbix默认的端口检测net.tcp.port太浅。真正的业务级检查需模拟真实用户行为。以下是一个监控Spring Boot Actuator健康端点的Shell脚本它解决了三个关键痛点HTTPS证书验证、超时控制、JSON解析容错。#!/bin/bash # check_springboot_health.sh # 参数$1服务URL如https://api.example.com/actuator/health, $2超时秒数默认5 URL${1:-https://localhost:8080/actuator/health} TIMEOUT${2:-5} # 检查curl是否存在 command -v curl /dev/null 21 || { echo curl not found; exit 1; } # 执行curl忽略SSL证书错误生产环境应配置正确证书 # -k: 忽略证书验证-s: 静默模式-m: 最大超时-w: 输出HTTP状态码-o: 丢弃响应体 HTTP_CODE$(curl -k -s -m $TIMEOUT -w %{http_code} -o /dev/null $URL 2/dev/null) # 根据HTTP状态码判断 case $HTTP_CODE in 200) # 解析JSON提取status字段兼容不同格式UP/DOWN/UNKNOWN STATUS$(curl -k -s -m $TIMEOUT $URL 2/dev/null | grep -o status:[^]* | cut -d -f4 | tr [:lower:] [:upper:]) case $STATUS in UP) echo 1 ;; DOWN|UNKNOWN) echo 0 ;; *) echo 0 ;; # JSON解析失败视为异常 esac ;; 401|403) # 认证失败服务存在但权限不足视为部分可用 echo 1 ;; *) # 其他状态码500/502/503/超时等服务不可用 echo 0 ;; esac避坑指南证书问题生产环境绝不能用-k忽略证书正确做法是将CA证书路径传入--cacert /path/to/ca.crt或配置curl全局证书路径JSON解析风险grep -o status:[^]*可能匹配到日志中的status字段应限定在响应体首行或改用jq工具curl ... | jq -r .status // DOWN超时陷阱curl -m只控制连接传输超时DNS解析超时需额外加--connect-timeout 3Zabbix集成UserParameter写成UserParameterspringboot.health.status[*],/usr/local/bin/check_springboot_health.sh $1 $2监控项Key填sprinboot.health.status[https://api.example.com/actuator/health,10]。4.2 日志错误计数监控从“grep一把梭”到精准时间窗口统计监控日志错误最常见误区是grep ERROR /var/log/app.log | wc -l这会导致两个严重问题1每次统计全量日志IO压力巨大2无法限定时间范围凌晨的错误会污染白天的告警。正确方案是用logrotate配合tail -n只读取新增行。#!/bin/bash # count_log_errors.sh # 参数$1日志路径$2错误模式正则$3时间窗口分钟数默认5 LOG_FILE${1:-/var/log/app.log} PATTERN${2:-ERROR} WINDOW_MIN${3:-5} # 计算时间窗口起始时间戳精确到秒 WINDOW_START$(date -d $WINDOW_MIN minutes ago %s 2/dev/null) if [ -z $WINDOW_START ]; then WINDOW_START$(($(date %s) - WINDOW_MIN * 60)) fi # 获取日志文件最后修改时间 LOG_MTIME$(stat -c %Y $LOG_FILE 2/dev/null) if [ -z $LOG_MTIME ]; then echo 0 exit 0 fi # 如果日志文件比窗口还老直接返回0 if [ $LOG_MTIME -lt $WINDOW_START ]; then echo 0 exit 0 fi # 使用awk按时间戳过滤假设日志格式2023-10-01 12:34:56 ERROR ... # 提取时间戳转换为秒比较 awk -v start$WINDOW_START -v pattern$PATTERN BEGIN { # 定义时间格式解析函数 FS ; OFS } { # 假设时间在第1、2列如2023-10-01 12:34:56 if (NF 2) { datetime $1 $2 # 将datetime转为时间戳GNU awk支持mktime cmd date -d \ datetime \ %s 2/dev/null cmd | getline ts close(cmd) if (ts ! ts start $0 ~ pattern) { count } } } END { print count0 } $LOG_FILE 2/dev/null避坑指南日志轮转处理logrotate后旧日志会被重命名如app.log.1脚本需同时监控app.log*用find /var/log -name app.log* -mmin -$WINDOW_MIN获取所有相关文件性能优化对超大日志用tac倒序读取新日志在前配合awk NR10000{exit} /pattern/{count}限制扫描行数Zabbix触发器不要设“错误数0”就告警应设“5分钟内错误数10且环比增长200%”避免偶发错误扰民安全加固PATTERN参数需严格校验禁止传入.*等危险正则防止ReDoS攻击。4.3 数据库连接池监控直击微服务性能瓶颈的“心脏监测仪”数据库连接池耗尽是微服务雪崩的导火索但Zabbix默认不采集此指标。以下脚本通过JDBC URL直连MySQL查询information_schema.PROCESSLIST统计活跃连接数并区分业务连接与监控连接。#!/bin/bash # check_mysql_pool.sh # 参数$1MySQL host, $2port, $3user, $4password, $5pool max size用于计算使用率 HOST${1:-localhost} PORT${2:-3306} USER${3:-zabbix} PASS${4:-zabbix} MAX_POOL${5:-100} # 检查mysql客户端 command -v mysql /dev/null 21 || { echo mysql client not found; exit 1; } # 查询活跃连接数排除Sleep状态和监控自身连接 ACTIVE_COUNT$( mysql -h$HOST -P$PORT -u$USER -p$PASS -N -s -e SELECT COUNT(*) FROM information_schema.PROCESSLIST WHERE COMMAND ! Sleep AND USER ! $USER AND HOST NOT LIKE 127.0.0.1% AND HOST NOT LIKE localhost% 2/dev/null ) # 处理空结果 ACTIVE_COUNT${ACTIVE_COUNT:-0} # 计算使用率百分比用于触发器阈值 USAGE_PERCENT$((ACTIVE_COUNT * 100 / MAX_POOL)) # 输出两个值活跃数 和 使用率Zabbix支持多值返回用换行分隔 echo $ACTIVE_COUNT echo $USAGE_PERCENT避坑指南权限最小化zabbix用户只需SELECT权限在information_schema.PROCESSLIST禁用SUPER等高危权限连接泄漏防护脚本执行完自动退出但需在MySQL配置wait_timeout60避免僵尸连接Zabbix多值接收监控项类型选“Zabbix agent (active)”Key填mysql.pool.stats在Zabbix Server端用{$MYSQL_POOL_ACTIVE}和{$MYSQL_POOL_USAGE}提取第一、二行值微服务适配若用Druid连接池可改查/actuator/druid/datasource端点逻辑类似。4.4 磁盘inode监控被99%团队忽略的“隐形杀手”磁盘空间充足但服务宕机大概率是inode耗尽。Zabbix自带的vfs.fs.size只监控空间不监控inode。以下脚本精准检测指定挂载点的inode使用率。#!/bin/bash # check_inode_usage.sh # 参数$1挂载点路径如/data$2告警阈值默认90 MOUNT_POINT${1:-/} THRESHOLD${2:-90} # 检查挂载点是否存在 if ! mount | grep -q $MOUNT_POINT ; then echo Mount point $MOUNT_POINT not found exit 1 fi # 获取inode使用率df -i输出Use%在第5列 INODE_USAGE$(df -i $MOUNT_POINT | tail -1 | awk {print $5} | sed s/%//) # 处理空值 INODE_USAGE${INODE_USAGE:-0} # 判断是否超阈值 if [ $INODE_USAGE -gt $THRESHOLD ]; then echo 1 # 超阈值需告警 else echo 0 # 正常 fi避坑指南小文件陷阱/var/spool/postfix/maildrop等目录易堆积小文件需单独监控Docker环境容器内df -i可能显示宿主机inode应在宿主机部署脚本监控/var/lib/dockerZabbix触发器设为“inode.usage0 for 5m”避免瞬时波动关联动作发送find $MOUNT_POINT -xdev -type f | head -100找出最大文件列表辅助定位。5. 实战排障与经验沉淀那些文档里不会写的血泪教训与提效技巧5.1 Zabbix自定义监控的“死亡五连问”快速定位90%的问题当你的自定义监控项显示“Not supported”或数值异常按以下顺序灵魂拷问5分钟内定位根源Agent端脚本能否手动执行sudo -u zabbix /usr/local/bin/your_script.sh—— 必须用zabbix用户执行模拟Agent运行环境。常见失败脚本路径错误、权限不足chmod 755、缺少依赖which curl、环境变量缺失PATH未包含/usr/local/bin。UserParameter配置是否生效sudo zabbix_agentd -t your.key.name—— 这是Zabbix Agent的调试命令直接返回脚本输出。若报错Cannot obtain value检查配置文件语法前后不能有空格、配置文件是否被include、Agent是否重启。Zabbix Server能否获取到数据zabbix_get -s agent_ip -k your.key.name—— 若返回ZBX_NOTSUPPORTED说明Agent端问题若超时检查防火墙10050端口、Agent配置StartAgents值需0、Server与Agent时间是否同步相差300秒会拒绝通信。监控项配置是否匹配在Zabbix Web界面进入监控项详情页核对Key是否与UserParameter完全一致大小写、符号类型是否为“Zabbix agent”更新间隔是否合理太短导致Agent过载历史存储周期是否足够。触发器表达式是否写错进入触发器配置页点击“Test”按钮输入主机名和时间范围查看实时计算结果。常见错误{HOSTNAME:key.last()}写成{HOST:key.last()}HOSTNAME是宏HOST是错误写法阈值单位混淆如内存用MB却设阈值10000实际应为10000000。提示在Agent配置中开启Debug日志DebugLevel4重启Agent后查看/var/log/zabbix/zabbix_agentd.log里面会详细记录每次脚本调用的命令、返回值、耗时是终极排障利器。5.2 提效技巧让自定义监控从“手工劳动”升级为“流水线工程”写10个脚本是体力活管理100个脚本是噩梦。我团队沉淀的提效技巧技巧一脚本模板化与参数化所有脚本统一入口用case $1分发逻辑#!/bin/bash # unified_monitor.sh case $1 in nginx_qps) check_nginx_qps $2 ;; mysql_slow) check_mysql_slow $2 $3 ;; log_error) count_log_errors $2 $3 $4 ;; *) echo Usage: $0 {nginx_qps|mysql_slow|log_error} [args...]; exit 1 ;; esacUserParameter统一写成UserParametermonitor.[*],/usr/local/bin/unified_monitor.sh $1 $2 $3 $4管理成本直降70%。技巧二Zabbix配置版本化用Git管理/etc/zabbix/zabbix_agentd.d/下的所有.conf文件每次修改提交Commit并附上变更原因如“修复log_error脚本在CentOS8的date命令兼容性”。Zabbix Server端同样用Git管理模板XML导出实现配置回滚与审计。技巧三自动化部署与验证用Ansible Playbook一键部署- name: Deploy custom monitoring scripts copy: src: scripts/ dest: /usr/local/bin/ mode: 0755 - name: Deploy UserParameter configs template: src: templates/userparameter_*.j2 dest: /etc/zabbix/zabbix_agentd.d/ - name: Verify script execution command: sudo -u zabbix /usr/local/bin/check_nginx_qps.sh register: script_test changed_when: false - name: Fail if script fails fail: msg: Custom script verification failed when: script_test.rc ! 0每次上线前自动验证杜绝“配置写了但没生效”的低级错误。技巧四监控即文档在脚本头部用注释写明监控目的、指标含义、正常范围、告警建议、关联业务。例如# 监控目的检测Redis主从同步延迟延迟100ms触发告警 # 指标含义slave节点的master_last_io_seconds_ago值秒 # 正常范围0-5s网络良好时100s可接受 # 告警建议检查主从网络、Redis负载、AOF重写是否阻塞 # 关联业务订单缓存、用户会话新同事接手时看脚本注释就能理解全部无需翻查Wiki。5.3 经验之谈关于“何时该用自定义监控”的三条红线不是所有监控都值得自定义。我踩过坑后总结的三条红线红线一Zabbix原生指标能满足绝不自定义比如监控CPU使用率system.cpu.util[,idle]已足够精准再写脚本调用top纯属重复造轮子还增加维护负担。自定义只用于原生无法覆盖的场景。红线二脚本执行耗时超过Zabbix Timeout的1/3必须重构Zabbix Agent默认Timeout3秒脚本应控制在1秒内完成。若需调用外部API必须加timeout 1并设置合理的失败兜底值如返回-1避免拖垮整个Agent。红线三监控逻辑涉及业务核心数据必须走应用层埋点比如“支付成功率”不应在Nginx日志里统计200和500响应码来计算而应在支付服务代码中用Micrometer等框架直接上报payment.success.rate指标。日志监控是兜底方案应用埋点才是真相。最后分享个小技巧在Zabbix Web界面给所有自定义监控项的Name字段加上前缀[CUSTOM]如[CUSTOM] Nginx 502 Count。这样在主机监控项列表里所有自定义项自动聚在一起筛选、排序、管理效率提升数倍。这看似微小却是我每天节省10分钟的实在功夫。
返回列表