ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Zabbix 7.0 运维排障实战:安装、监控项、SNMP 与钉钉告警

Zabbix 7.0 运维排障实战:安装、监控项、SNMP 与钉钉告警 0. 从一次凌晨的报错说起028 是我自己那本排障笔记的序号主题是 zabbix 问题处理记录。这本笔记最早只是我随手贴在工位显示器边上的便利贴后来便利贴贴满了才挪到文档里按编号排下去。第 028 篇记的东西比较杂横跨了 zabbix 搭建、zabbix 监控项配置、模板改造还有告警链路联动钉钉这一整套链条上我真实踩过的坑。写这篇记录的起点很具体某天凌晨两点多我被一堆重复告警叫醒登上服务器一看zabbix server 日志里刷的是Access denied for user zabbixlocalhost (using password: YES)采集全部中断前端页面还在转圈。那一次之后我就把zabbix 出问题怎么查这件事当成一个正经流程来整理了因为 zabbix 这套东西的特点是它本身不难难的是它由 agent、server、数据库、前端、告警通道五个环节串起来任何一环打嗝表象都长得很像你要是没有一套固定的排查顺序就很容易在错误的方向上耗掉一两个小时。这篇记录适合三类人看。第一类是刚把 zabbix 跑起来、还在跟安装报错较劲的新手我会把 Rocky Linux 9 上装 zabbix 7.0 的完整路径和那几条最容易卡死的参数写清楚。第二类是把 zabbix 用了一两年、监控项越加越多、开始遇到队列积压和告警风暴的运维同学我会讲监控项分层、主动被动模式的选择依据、以及告警收敛的几种做法。第三类是负责网络设备监控、要给深信服这类设备做 SNMP 接入的人接口发现和私有 OID 探测那部分应该能省你不少时间。全篇都是我在真实环境里验证过的做法参数我尽量给出推算过程因为拍脑袋填的数字迟早会在某个业务高峰的夜里还给你。1. 问题处理这件事先想清楚整体设计1.1 为什么我把排障笔记当成一项资产来维护很多人做监控的心态是装完能用就行出了事再现场查。我做过一段时间这种模式结论是效率极低。原因很实在zabbix 的故障现象高度同质化——图表没数据、告警没收到、页面打不开这三种表象背后可能是几十种原因而每次现场排查你都要重新走一遍看日志、ping 端口、连数据库这三板斧重复劳动不说人还容易在紧张状态下漏掉关键线索。我的做法是把每一次故障都按固定模板落成一条记录哪怕只花五分钟。这个模板我迭代过好几版现在稳定成七栏维护成本低但信息密度足够栏目要写什么为什么必须写现象用户或监控自身看到的直接表现这是后续检索的唯一入口写得越接近原话越好影响面影响多少主机、哪些业务、持续多久决定你是先恢复还是先定位时间线首次出现、发现、动手、恢复的时间点复盘时用来区分真故障时长和人为拖延时长根因一句话说清楚到底哪里错了不能写数据库问题要写到具体参数或具体记录处置动作实际执行的命令和改动下次同类问题直接抄回归验证用什么指标证明真的好了避免看着像好了就收工防复发配置、告警、文档上做了什么改动这一栏才是记录的价值所在前面六栏只是过程这里有个经验防复发那一栏不要写加强监控这种废话。要么写成给 X 主机的 Y 监控项加触发器阈值 Z要么写把 A 参数从 3 调到 10 并写入配置管理。能落成具体动作的才算防复发否则下次一定还会栽在同一个地方。1.2 一条固定的排查顺序能省掉一半时间zabbix 的链路长所以我给自己定了一个从下往上、从内往外的固定顺序无论现象是什么都按这个顺序走不跳步。这个顺序的逻辑是先排除最底层、最容易验证的环节避免在高层推理上浪费时间。看数据库是否正常。mysql -e select 1一条命令两秒钟。数据库挂了后面所有排查都没意义。看 zabbix_server 进程与日志。systemctl status zabbix-server再tail -100 /var/log/zabbix/zabbix_server.log。日志里通常会直接告诉你答案比如Access denied、connection to database failed、cannot bind socket。看 agent 侧。从 server 上执行zabbix_get -s 被监控IP -k agent.ping返回 1 说明 agent 和网络都通返回超时说明是网络或者 agent 服务的问题跟 server 配置无关。看具体监控项。用zabbix_agentd -t key在被监控机上本地测试 key能把key 错和网络错彻底分开。最后才看前端和告警。前端的报错往往是最下游的表现先查它容易误导。注意不要一上来就重启服务。重启能解决一部分问题但会把现场证据一起清掉。我的习惯是先cp一份日志再动手尤其是 server 日志和 agent 日志出问题时的日志比事后复现的日志值钱得多。1.3 一张排障地图用来对齐认知在不熟悉的环境里接手排障我会先在纸上画一张最小地图把五个角色和它们之间的连接标出来agent10050 被动 / 主动连 10051、server10051 监听、连数据库 3306、数据库、前端PHP-FPM Web 服务器、告警出口脚本或 Webhook。画完之后再对着现象问一句这件事发生在哪条线上方向立刻就窄了。这张地图还有第二个用处判断该在哪一层做冗余或者限流。比如采集抖动你可以在 agent 层加 BufferSize 缓解也可以在 server 层加 poller但如果你连抖动产生在哪一层都不清楚就只是在碰运气调参数。这也是我后来坚持先画图再动手的原因。2. 环境底座与部署阶段最容易卡住的地方2.1 Rocky Linux 9 上装 zabbix 7.0顺序比命令重要在 Rocky Linux 9 这类 RHEL 系发行版上装 zabbix命令本身没几条但顺序错一步就要重来。我固定用下面这一套已经在多台机器上复现过# 1. 装官方仓库Rocky 9 对应 el9 rpm -Uvh https://repo.zabbix.com/zabbix/7.0/rhel/9/x86_64/zabbix-release-latest.el9.noarch.rpm dnf clean all # 2. 一次装齐server 前端 SQL 脚本 agent selinux 策略包 dnf install -y zabbix-server-mysql zabbix-web-mysql zabbix-apache-conf \ zabbix-sql-scripts zabbix-selinux-policy zabbix-agent # 3. 同步时间与时区这一步不能省 timedatectl set-timezone Asia/Shanghai dnf install -y chrony systemctl enable --now chronyd chronyc sources -v时间同步为什么放在这么靠前的位置因为 zabbix 的所有历史数据都带时间戳采集端和 server 端只要差几分钟图表就会出现前面一段有数据、后面一段空白的假断点而你会以为是采集挂了白白查半小时。我遇到过最离谱的一次是差了两个小时前端显示未来数据触发器状态全乱。SELinux 是第二个常见陷阱。Rocky 9 默认 enforcingzabbix 的官方 selinux 策略包能解决大部分问题但前端连数据库那一步还是会被拦需要补两条布尔值setsebool -P httpd_can_connect_zabbix on setsebool -P httpd_can_network_connect_db on getsebool -a | grep -E httpd_can_(connect_zabbix|network_connect_db)防火墙这块我一般不在生产机器上用--add-service图省事而是明确写端口因为 zabbix 涉及的端口比较分散写清楚以后交接给同事也不会懵firewall-cmd --permanent --add-port80/tcp # 前端 firewall-cmd --permanent --add-port10051/tcp # server 监听与主动模式接收 firewall-cmd --permanent --add-port10050/tcp # agent 被动模式 firewall-cmd --reload2.2 数据库初始化字符集和权限一次做对数据库这一步偷懒后面一定会还债。字符集选错中文主机名和告警内容会变问号权限写错就是文章开头那个Access denied。我固定用 utf8mb4 utf8mb4_bin后者是为了让 zabbix 的大小写敏感判断符合预期。CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; CREATE USER zabbixlocalhost IDENTIFIED BY Zbx_2024#Strong; GRANT ALL PRIVILEGES ON zabbix.* TO zabbixlocalhost; SET GLOBAL log_bin_trust_function_creators 1;最后那条log_bin_trust_function_creators经常被漏掉。它只在开启了 binlog 的 MySQL 上需要作用是允许创建存储函数而 zabbix 的初始化脚本里确实有函数。漏掉它导入 schema 会中途报错你会得到一个半成品数据库比全空还难收拾。导入前先设导入完可以再关掉。# 导入顺序先库后前端配置导入时显式指定字符集 zcat /usr/share/zabbix-sql-scripts/mysql/server.sql.gz | \ mysql --default-character-setutf8mb4 -uzabbix -p zabbix导入完有个很实在的验证动作登进数据库数一下表。SELECT COUNT(*) FROM information_schema.tables WHERE table_schemazabbix;正常应该在 170 张左右不同版本略有差异。如果只有几十张说明导入中途失败了回头看上面那条语句的报错十有八九是字符集或者权限问题。2.3 那条 Access denied 报错我按这五步拆Access denied for user xxxlocalhost (using password: YES/NO)这条报错在 zabbix 场景下出现频率极高我把它拆成五步基本上三步之内能定位。第一步看 (using password: YES) 还是 NO。这个括号里的信息是 MySQL 给你的免费提示准确说是 zabbix 用的客户端库报的。显示 NO说明 server 根本没把密码传下去问题在 zabbix_server.confDBPassword被注释了、被写成了带引号的形式、或者密码里有#被当成了注释起始符。zabbix 的配置文件不需要给值加引号加了引号引号本身会变成密码的一部分。第二步确认 DBHost 与账号的匹配关系。MySQL 里zabbixlocalhost和zabbix127.0.0.1是两条完全独立的记录。如果DBHost127.0.0.1客户端走的是 TCPMySQL 会用zabbix127.0.0.1或zabbix%去匹配匹配不到就报 Access denied哪怕密码一模一样。想少踩这个坑最稳的写法是建账号时把 localhost 和 127.0.0.1 都建一遍或者统一用 localhost 走 socket。SELECT user, host, plugin FROM mysql.user WHERE userzabbix;第三步看认证插件。MySQL 8 默认caching_sha2_password。新版的 zabbix 客户端和较新的 PHP 驱动都能处理但如果你的环境里有老版本的客户端组件会连不上。这种情况可以临时改成兼容插件观察但要清楚这是权宜之计长期做法是升级客户端组件。ALTER USER zabbixlocalhost IDENTIFIED WITH mysql_native_password BY Zbx_2024#Strong; FLUSH PRIVILEGES;第四步用完全相同的凭据手工连一次。这一步能把配置里的密码和你脑子里的密码对齐。mysql -uzabbix -pZbx_2024#Strong -h 127.0.0.1 zabbix -e SELECT 1;第五步检查配置文件里的实际内容。别用眼睛扫用命令提取避免看漏一个注释符。grep -nE ^(DBHost|DBName|DBUser|DBPassword) /etc/zabbix/zabbix_server.conf实操心得密码里带$、、\这类字符时在 shell 里测试要用单引号包住双引号会被 shell 展开你会误以为密码错了。真要图省心密码里只留大小写字母、数字和_ - #这几种能避开一大堆转义问题。2.4 几个必须算一遍的参数别照抄网上的值网上流传的 zabbix 配置参数多半来自很小的测试环境直接抄到生产上会出两种问题给太少导致丢数据给太多把内存吃光。我一般先看实际负载再按下面的方式估算。ValueCacheSize。这个缓存的用途是保存最近一小时内被触发器引用过的数据让触发器能在内存里算表达式而不用每次去查数据库。粗算方式是NVPS × 3600 × 每条值占用的字节数。假设你的环境实测 NVPS 是 500每条值连结构体带索引开销按 150 字节算就是500 × 3600 × 150 ≈ 270MB。但我不建议你直接把 270MB 填进去因为这是最坏情况估计。更实用的做法是先给 128M然后用内部监控项盯着缓存占用率zabbix[wcache,history,pfree] # 值缓存剩余百分比这个值持续低于 20%说明缓存吃紧加长期在 80% 以上说明给多了可以适当回收。用数据调参比用公式调参可靠。StartPollers。被动模式下每个监控项的采集包含建连 发请求 等响应 断开在局域网里一次往返大约 20 到 50 毫秒。按偏悲观的值 50 毫秒算单个 poller 每秒能处理 20 个检查。如果你的环境有 6000 个被动监控项、采集间隔统一 60 秒那么每秒需要处理 100 个检查理论需要 5 个 poller我一般配到 8 到 10 留余量。这里有个必须一起考虑的联动项每个 poller 都会占用数据库连接。StartPollers调大之后MySQL 的max_connections要跟着往上走否则会出现Too many connections症状是采集大面积超时而你会误以为是网络问题。History 与 Trends 保留天数。这是最容易被随口改坏的两个值。原始历史数据history、history_uint 这些表是写入压力最大的地方我的经验值原始历史保留 7 到 15 天趋势数据保留 90 到 365 天具体看你的报表需求。原因很直接趋势表按小时聚合行数比原始历史少两个数量级长期留存成本很低而原始历史每来一个值就写一行留久了必然把清理任务拖死。3. 监控项与模板怎么落地才算有效3.1 先把监控对象分层再谈加多少监控项我见过太多环境是想到什么加什么最后主机上有两百多个监控项真正会触发告警的不到十个出了故障还是靠人打电话。这种状态的根本问题是缺少分层监控项没有服务于具体的判断目标。我给自己的分层方式是五层每层回答一个明确的问题层级回答的问题典型监控项是否告警L0 存活这台机器还活着吗agent.ping、ICMP、端口探测告警最高优先级L1 资源资源够不够用会不会撑爆CPU、内存、swap、磁盘、inode、网卡部分告警看趋势L2 中间件服务自身健康吗连接数、慢查询、队列长度、线程池告警设合理阈值L3 业务用户能不能正常用订单量、成功率、接口耗时告警按业务定义L4 合规有没有隐患证书到期、端口变更、关键文件变动告警低优先级分层之后有个直接好处判断一个监控项值不值得加只需要问它属于哪一层、触发之后我会不会真去处理。L1 里的CPU 使用率往往不需要设告警因为高负载本身不是故障但CPU 持续 15 分钟高于 90%就值得告警。低价值的数据留着做容量分析就好不必都变成告警。3.2 UserParameter 写得好不好看三个细节自定义监控项是 zabbix 最能发挥价值的地方但也是故障最多的地方。我总结了三条硬要求写脚本的时候照着做能避开九成以上的ZBX_NOTSUPPORTED。# /etc/zabbix/zabbix_agentd.d/userparameter_ops.conf UserParameterapp.proc.count[*],/bin/ps -ef | grep -c [j]ava .*$1 UserParameterapp.log.err[*],/usr/bin/find /data/logs/$1 -name *.log -mmin -5 -xdev -exec grep -c ERROR {} 2/dev/null | awk -F: {s$2} END{print s0} UserParameterapp.port.listen[*],/usr/bin/ss -lntp | grep -c :$1 第一输出必须是单个数字或单行文本。这是硬性要求。脚本里echo了多行、或者把警告信息一起打出来agent 会直接判为不支持前端显示ZBX_NOTSUPPORTED。特别是用管道处理文本时顺手加一句| head -1或者用awk归到一行能省掉很多莫名其妙的报错。第二必须在 3 秒内返回。被动模式下 agent 默认的超时是 3 秒超了就直接放弃这次采集。所以脚本里不要做全盘扫描、不要查大表、不要调用需要建连的外部接口。真需要跑得久的采集要么改成主动模式配合更长超时要么做成定时任务写文件、让监控项只读文件。第三脚本权限和路径要干净。agent 以 zabbix 用户运行脚本必须 zabbix 可读可执行脚本里用到的命令要么写绝对路径要么确认 zabbix 用户的 PATH 里能找到。我踩过一次坑脚本在 root 下测试完美放上去一直不支持查了半小时才发现脚本里调用的是/usr/local/bin/xxx普通用户没权限。注意grep -c [j]ava里那个方括号不是笔误。直接写grep -c javagrep进程自身会匹配到自己的命令行计数永远比实际多 1。这个技巧在统计进程数时基本是标配。3.3 主动模式和被动模式怎么选这两种模式的名字起得有点绕用一句话记被动模式下服务器来敲门主动模式下 agent 自己上报。被动模式的特点是每个监控项都是一次独立的连接请求配置简单调试方便zabbix_get一条命令就能测代价是连接数多、agent 压力随监控项数量线性上升。所以它适合监控项不多、同网段、网络质量有保障的场景。主动模式是 agent 把一批采集结果打包发给 server 的 10051 端口一个连接搞定所有监控项带宽占用和连接开销都小得多。它适合三类场景监控项数量很大比如每台几十上百项、跨公网或跨机房采集、被监控机需要做端口最小化开放的场景。主动模式有两个坑网络上的教程经常只提一半# /etc/zabbix/zabbix_agentd.conf ServerActive10.0.0.10:10051 Hostnameweb-prod-01Hostname 必须和前端里这台主机的主机名字段完全一致包括大小写。不一致的话agent 日志里会出现no active checks on server, host [xxx] not found但前端看起来一切正常——因为主动模式没有连接失败这种明确的反馈。我习惯的做法是主机名统一用hostname -f的输出或者在部署脚本里强制写入不让人手工填。ServerActive 要写 IP 和端口不能只写主机名。如果 DNS 解析不稳定agent 会在解析上耗掉超时时间表现是采集断续。3.4 深信服这类网络设备的 SNMP 接入思路网络设备的监控和主机监控完全是两套思路因为设备不会给你装 agent只能靠 SNMP 读取。这里我以深信服设备为例讲讲我的一般流程因为这个流程对绝大多数支持 SNMP 的网络设备都通用。先做协议连通性验证。别急着在 zabbix 里配先在 server 上用 snmpwalk 确认能读到东西# -On 输出纯数字 OID方便和模板里的 OID 逐个对照 snmpwalk -v2c -c 只读团体名 -On 10.0.0.1 1.3.6.1.2.1.1.5 # sysName snmpwalk -v2c -c 只读团体名 10.0.0.1 1.3.6.1.2.1.2.2.1.2 # 接口描述 snmpwalk -v2c -c 只读团体名 10.0.0.1 1.3.6.1.2.1.31.1.1.1.18 # 接口别名 ifAlias snmpwalk -v2c -c 只读团体名 10.0.0.1 1.3.6.1.4.1 # 厂商私有分支最后那条命令很关键。标准 MIB 分支1.3.6.1.2.1里只有通用指标设备的 CPU、内存、会话数这些通常放在厂商私有的1.3.6.1.4.1下面。保险的做法是把私有分支整个导出到文件里再结合设备管理页面上的实时数值去比对——比如你在页面上看到 CPU 是 37%就在导出文件里找值为 37 或 3700 的行找到的那条就是你要的 OID。这个方法笨但比到处找 MIB 文件快得多。再做接口发现注意索引稳定性。SNMP 的接口发现规则默认用ifIndex作为唯一标识问题是设备重启或者接口顺序变化后ifIndex可能整体重排导致历史和告警全部错位。稳妥的做法是用发现规则 过滤器组合发现键值用ifDescr或ifName因为这两个是运营人员自己命名的稳定。用{#IFALIAS}这类宏做过滤排除NULL0、Vlanif、Loopback这些没有物理流量的接口否则你会收到一堆无用告警。对上行口单独打标签让它们可以走独立阈值。最后是模板改造。深信服相关的模板如果拿来直接用常见问题是监控项太多、采集间隔太密SNMP 又比 agent 慢得多结果就是队列积压。我的处理方式是三步走先从模板里挑出真正常用的十几项可用性、CPU、内存、每个上行口的流量和错误包其余全部关掉再把采集间隔从 30 秒放宽到 60 秒甚至 120 秒网络设备不需要秒级精度最后用导出 XML、批量编辑、再导入的方式统一改比在前端一条条点快很多。实操心得SNMP 团体名绝对不要用public。我见过被扫到之后、有人用只读团体名把整台设备的所有接口状态读走的案例。正确做法是建一个专门的只读账号团体名用随机字符串同时在设备侧限制只能从 zabbix server 的 IP 访问。4. 告警链路zabbix 7.0 联动的稳定实现4.1 为什么我最后选了脚本而不是 Webhookzabbix 7.0 提供两种主要方式把告警发出去Webhook 媒体类型和脚本媒体类型。Webhook 看起来更现代配置界面里直接写 JS不需要在服务器上放文件。但我实测下来在钉钉这类需要签名的机器人上脚本更省心。原因很明确钉钉的自定义机器人如果要开加签需要做 HMAC-SHA256 计算再 base64 再 URL 编码。而 zabbix 的 Webhook 里跑的是内置的 JS 引擎出于安全考虑不提供加密相关的接口你自己实现一个 SHA256 也不是不行但没必要为了省一个脚本文件去写两百行 JS。用外部脚本openssl一行就解决而且日志好查、出问题能单独在命令行跑一遍。选脚本的代价是脚本文件必须存在于 zabbix server 所在机器上前端和 server 分离部署时尤其要注意并且路径要和AlertScriptsPath对得上。这一点我会反复确认因为它的报错很隐晦动作执行了但消息没到日志里只有一行Cannot execute command。4.2 完整可用的一段告警脚本下面这段是我现在在用的版本用 python3 写Rocky 9 自带比 shell 版本少很多转义坑。核心是三件事算签名、拼 payload、把响应码打出来。#!/usr/bin/env python3 # /usr/lib/zabbix/alertscripts/dingtalk.py import base64, hashlib, hmac, json, sys, time, urllib.parse, urllib.request WEBHOOK https://oapi.dingtalk.com/robot/send TOKEN REPLACE_WITH_YOUR_ACCESS_TOKEN SECRET REPLACE_WITH_YOUR_SECRET def make_sign(ts: str) - str: raw f{ts}\n{SECRET}.encode(utf-8) digest hmac.new(SECRET.encode(utf-8), raw, hashlib.sha256).digest() return urllib.parse.quote_plus(base64.b64encode(digest)) def main() - None: to_user sys.argv[1] if len(sys.argv) 1 else subject sys.argv[2] if len(sys.argv) 2 else Zabbix Alert body sys.argv[3] if len(sys.argv) 3 else ts str(int(time.time() * 1000)) url f{WEBHOOK}?access_token{TOKEN}timestamp{ts}sign{make_sign(ts)} content f【{subject}】\n{body} payload {msgtype: text, text: {content: content}} if to_user: payload[text][content] content f\n{to_user} payload[at] {atMobiles: [to_user], isAtAll: False} req urllib.request.Request( url, datajson.dumps(payload).encode(utf-8), headers{Content-Type: application/json}, ) try: with urllib.request.urlopen(req, timeout8) as resp: print(resp.read().decode(utf-8)) except Exception as exc: print(fSEND_FAILED: {exc}, filesys.stderr) sys.exit(1) if __name__ __main__: main()注意最后那个except它做了一件很重要的事失败时用非零退出码返回。zabbix 判断动作是否成功看的就是退出码。如果脚本吞掉异常、正常退出zabbix 会认为消息发出去了你就永远不会在日志里发现钉钉那边已经限流了。部署步骤按顺序来跳步很容易出问题install -m 0755 -o zabbix -g zabbix dingtalk.py /usr/lib/zabbix/alertscripts/dingtalk.py # 确认 server 配置里的脚本目录 grep -n ^AlertScriptsPath /etc/zabbix/zabbix_server.conf # 改过配置就要重启 systemctl restart zabbix-server # 用 zabbix 用户身份跑一次这一步能提前暴露权限问题 su -s /bin/bash zabbix -c /usr/lib/zabbix/alertscripts/dingtalk.py 测试主题 测试正文前端配置的对应关系是Alerts → Media types → Create media type类型选 Script脚本名写dingtalk.py只要文件名不要全路径三个参数按顺序填{ALERT.SENDTO}、{ALERT.SUBJECT}、{ALERT.MESSAGE}。然后创建用户、给用户配这个媒介、填手机号再建 Action 把触发器和用户关联起来。注意媒体类型里的三个参数顺序必须和脚本里的sys.argv顺序一一对应多一个少一个都会让消息内容错位。我第一次配的时候把 SENDTO 和 SUBJECT 写反了结果告警主题变成了手机号排查了十几分钟才反应过来。4.3 告警收敛怎么才能不被半夜的告警风暴叫醒告警通道打通只是开始真正影响睡眠质量的是噪声控制。我按从便宜到贵的顺序做了四层收敛每层解决不同的问题。第一层触发器依赖。这是性价比最高的一招。核心交换机或者出口链路断开时它下面所有主机的可用性告警都会跟着触发几百条一起来。做法是在触发器上配置依赖关系主机存活类触发器依赖网络设备接口类触发器。配置好之后上游断了下游自动不告警上游恢复下游自己恢复正常。这一层能砍掉大部分风暴。第二层分级路由。我按严重程度把消息发到不同渠道最高级别直接到人配合电话中间级别发到值班群低级别只写邮件或者工单不进群。判断标准不是这个指标重不重要而是它坏了会不会影响用户。业务指标坏了必须马上处理磁盘使用率 80% 这种可以等到上班时间。第三层动作里加上合理的重试间隔。默认的重试配置很容易造成重复轰炸。我的习惯是操作步骤的间隔设 60 秒重试次数 3 次同时把更新操作打开但间隔设成 30 分钟以上。这样一条持续的问题事件第一次立刻发之后最多半小时提醒一次而不是每秒一条。第四层计划维护。有变更窗口的时候用 Maintenance 而不是关闭触发器。用维护窗口的好处是维护期内的告警不发出但数据照常采集维护结束后如果问题还在会立刻补发告警。我见过有人图省事关掉触发器然后忘了打开结果真出故障时一片安静——这种事发生过一次就够记一辈子。实操心得钉钉自定义机器人有频率限制短时间内大量消息会返回限流错误。脚本里把响应内容打印出来配合 zabbix 的动作日志你就能明确区分消息发出去了和消息被限流了。这两件事在页面上看起来一模一样。5. 疑难问题排查实录与速查表5.1 采集侧问题ZBX_NOTSUPPORTED 的四种成因这个报错大概是 zabbix 使用者遇到最多的一种。它的意思很直白agent 收到了请求但没法返回一个合法的值。我按出现频率排了一下成因跟着这个顺序查基本不会走弯路。成因一key 写错或者用户参数没被加载。agent 加载自定义参数文件是在启动时完成的改完配置文件必须重启 agent 才生效systemctl reload有时不重新读参数文件。验证方式是在被监控机上直接测zabbix_agentd -t app.proc.count[java]成因二脚本超时。agent 日志里会出现Timeout while executing a shell script。这时先看脚本本身跑了多久time /path/to/script超过 3 秒就得优化别急着把超时调大——调大超时的代价是占住 poller采集项一多就会互相拖累。成因三权限或者安全策略拦截。脚本属主不对、目录没有执行权限、或者 SELinux 阻止了 agent 执行自定义程序。用su -s /bin/bash zabbix -c 脚本模拟一次最直接。成因四输出格式不合法。脚本返回了多行、返回了文字、或者返回了空。注意空输出也会被判为不支持所以脚本末尾最好做个兜底没数据就输出 0 而不是什么都不输出。网络层的问题和上面这四种要分开看如果zabbix_get -s IP -k agent.ping直接超时那就跟 key 无关了检查 10050 端口、防火墙规则、以及Server参数里有没有包含 server 的 IP被动模式下 agent 只接受配置里列出的地址来连。5.2 服务端问题队列积压怎么定位队列是 zabbix 的健康晴雨表我把它作为日常盯的第一个指标。内部监控项有两个够用了zabbix[queue,10m] # 10 分钟内未采集的监控项数量 zabbix[process,poller,avg,busy] # poller 平均繁忙率判断逻辑很简单队列数量长期大于某个值我一般设 200并且在增长说明采集能力跟不上监控规模配合繁忙率看如果繁忙率超过 70%就是 poller 不够或者单次采集太慢。这时候有三个方向可以动按代价从小到大提高采集间隔。把 30 秒的项改成 60 秒负载直接减半而且很多指标本来就不需要 30 秒精度。加 poller 进程同时把数据库max_connections一起放大。查数据库慢查询。这一步经常被跳过但实测下来队列积压里有相当一部分根因是数据库写不动。-- 先看当前活跃会话 SELECT id, user, time, state, LEFT(info, 120) FROM information_schema.processlist WHERE command Sleep ORDER BY time DESC; -- 再确认 buffer pool 是否给够 SHOW VARIABLES LIKE innodb_buffer_pool_size;innodb_buffer_pool_size给到物理内存的 50% 到 60% 是常见做法前提是这台机器只跑数据库。如果 zabbix 和数据库混部这个比例要往下压否则 server 进程会被换出问题更严重。5.3 前端与数据库层面的典型问题中文乱码。症状是主机名、告警内容显示成问号或者方块。根因基本都是导入 schema 时没指定字符集。已经导错了不能靠改配置补救因为数据里存的字节就是错的只能删库重导。所以这一步我在 2.2 节里特意放在最前面成本最低。图表出现断点。先分清楚是真没数据还是画不出来。到 Monitoring → Latest data 里看对应监控项的最新值时间戳如果时间戳是几分钟前的说明采集断了按 5.1 的流程查如果最新值正常但图表断通常是时间不同步或者清理任务把数据删在了图表区间之前。我遇到过 retention 设成 1 天、查看过去 7 天报表全是空白的情况一度以为是前端 bug。前端 502 或者打开很慢。大部分是 PHP-FPM 的问题看/etc/php-fpm.d/zabbix.conf里的pm.max_children。并发用户多的时候这个值太小会导致排队。同时检查max_execution_time某些大报表页面比如趋势聚合执行时间会超过默认值直接返回空白页。; /etc/php-fpm.d/zabbix.conf pm dynamic pm.max_children 50 pm.start_servers 5 pm.min_spare_servers 5 pm.max_spare_servers 35 php_value[max_execution_time] 300 php_value[date.timezone] Asia/Shanghai5.4 常见问题速查表下面这张表是我贴在自己工位上的那张便利贴的电子版按现象 → 最可能原因 → 一条验证命令 → 处置四列整理。出问题时我会先扫一遍这张表命中就直接照做不命中再走完整流程。现象最可能原因验证方式处置Access denied for user密码含特殊字符、账号 host 不匹配mysql -uzabbix -p -h 127.0.0.1 zabbix -e select 1核对 DBHost 与 mysql.user 的 host 记录using password: NODBPassword 被注释或带引号grep DBPassword /etc/zabbix/zabbix_server.conf去掉引号与注释符后重启 serverZBX_NOTSUPPORTEDkey 错、脚本超时、输出非单值zabbix_agentd -t key本地测通后再从 server 侧测一次agent.ping 超时防火墙、agent 未启动、Server 参数未放行zabbix_get -s IP -k agent.ping放行 10050 并核对 Server 参数主动模式主机找不到Hostname 与前端不一致grep ^Hostname agentd.conf改成完全一致的字符串后重启队列持续增长poller 不足、采集过密、DB 写慢zabbix[queue,10m]先放宽采集间隔再看慢查询前端提示 server 未运行进程未起、端口未监听、SELinuxss -lntp | grep 10051查 server 日志并处理 SELinux 策略图表断点时间不同步、采集中断、保留期过短查 Latest data 时间戳修 chrony调整保留天数告警未送达脚本路径不对、签名错、被限流用 zabbix 用户手工执行脚本核对 AlertScriptsPath 与返回内容中文显示为问号建库或导入时字符集不对SHOW CREATE DATABASE zabbix;删库重建导入时显式指定 utf8mb46. 日常运维让这套东西自己能撑住6.1 备份与升级按能回滚的粒度来做监控系统本身也是生产系统坏了没人知道所以备份要做而且要能验证。我的做法分两块数据库全量导出带着 zabbix 的配置数据一起加上前端配置的 XML 导出用于跨版本迁移或者局部回滚。# 每周全量保留 4 周 mysqldump --single-transaction --default-character-setutf8mb4 \ --routines --triggers zabbix /backup/zabbix_$(date %F).sql # 校验不看文件大小看能不能导入 gzip -t /backup/zabbix_$(date %F).sql.gz 2/dev/null || true grep -c CREATE TABLE /backup/zabbix_$(date %F).sql第二条校验动作很重要。备份文件大小为 0 但任务成功退出的情况我遇到过不止一次通常是因为磁盘满了或者权限问题而监控备份任务的脚本只看了退出码。所以我现在的习惯是备份完成后必须有一次可读性校验哪怕只是数一下 CREATE TABLE 的数量对不对。升级方面小版本比如 7.0.x 到 7.0.y直接dnf update通常没问题但一定要先停 server、备份数据库。大版本升级前必须看官方的升级说明因为有些表结构变化只能单向进行降级非常麻烦。另外提醒一点zabbix server 启动时会自动检测数据库版本并执行结构升级这个过程在库很大的时候可能要跑很久期间前端会不可用安排在维护窗口里做。6.2 容量估算三个数字决定你要不要扩容我不喜欢凭感觉判断监控系统是不是撑不住了所以固定盯三个数字。第一个是 NVPS每秒新增值数。内部监控项zabbix[wcache,values,all]的斜率基本上能反映它。这个是所有容量计算的基数扩容决策都从它出发。第二个是数据库增长速率。粗算方式是单条历史记录连索引开销大约 60 到 100 字节那么每 1000 NVPS 每天大约产生 5 到 8.6 GB 的原始历史数据。拿这个数去对比你实际的磁盘增长如果实测远高于估算说明有表缺索引或者有异常的采集项在疯狂写数据——我遇到过某个自定义脚本每次返回一个超长的 JSON 字符串一天写了 40GB。第三个是趋势数据的体量。趋势是按小时聚合的行数大约只有原始历史的 1/60所以你可以放心地把保留期设长。我的配置是趋势留一年历史留 14 天磁盘占用上趋势部分几乎可以忽略但回头做年度容量分析时有数据可用。6.3 我踩过的几个以为没问题的坑第一个坑把 history 保留天数从 7 天改成 90 天。当时的需求是想多看几个月的数据改完当天没什么感觉一周后 server 开始周期性卡顿housekeeper 进程长时间占满 CPU。原因是清理任务要在大表上做删除数据越多删得越慢最后形成删不完 继续写的恶性循环。后来改成按天分区用DROP PARTITION代替DELETE清理瞬间完成。如果你的环境 NVPS 上千我建议直接上分区别跟 housekeeper 较劲。第二个坑监控项加得太随意。有个阶段我给每台机器都加了 40 多个自定义项包括各种日志关键字计数。结果 agent 的 CPU 占用上去了而且因为很多脚本要读大日志文件采集超时频繁。后来我定了一条规矩任何自定义监控项上线前必须先在测试机上测一次采集耗时超过 1 秒的一律改成离线生成数据、监控项只读结果文件。第三个坑告警阈值拍脑袋定。早期我给磁盘使用率设了 80% 的固定阈值结果一台专门存日志的机器天天告警因为它的设计水位就是 85%。后来改成按主机的角色打标签、不同标签用不同阈值噪声立刻降下来。阈值这件事没有通用答案只有你这台机器平时是什么水位。第四个坑把 zabbix 前端暴露在公网。为了在家也能看我曾把一个测试实例放到了公网第二天就发现有人尝试登录。现在的做法是前端只在内网开放需要外部访问时走内网跳板或者专门的访问通道同时给管理账号开强密码和登录失败锁定。最后分享一个我最近才养成的小习惯每次处理完一个 zabbix 问题我会把下次遇到同类问题第一条要执行的命令写成一个单行的 shell 别名丢到/etc/profile.d/zbx-check.sh里。比如查队列、查缓存占用率、查 agent 连通性各自一条。日积月累下来排障时真正花在敲命令上的时间少了一大半脑子可以留着想为什么会这样。这个习惯看着不起眼但它是整套记录体系里我最舍不得丢的一部分。
返回列表