干运维的,谁没跟 Zabbix 打过几次照面?我刚开始接手监控平台那会儿,几乎天天都在跟各种报错死磕:装完服务打不开页面、数据库授权失败、主机加进来一直显示红色 ZBX、监控项 not supported、告警消息发不出去……今天这篇就当是个人踩坑笔记,把这些年调 Zabbix 遇到的报错和排查思路整理成一个集锦,覆盖从安装部署、初始化配置到日常监控与告警联动的完整链路。不管是刚准备搭 Zabbix 的新手,还是在生产环境里被问题折腾到头疼的老手,希望这份整理能帮你少走几步弯路。
1. 安装部署阶段:先别急着装,这几个大坑一定要知道
1.1 经典报错:Access denied for user 'replace_user'@'localhost'
这个报错我见过太多次了,尤其是跟着网上零散的教程一步步装 Zabbix 6.0 或 7.0 的时候,走到导入数据库这一步,突然冒出来一句:
ERROR 1045 (28000): Access denied for user 'replace_user'@'localhost' (using password: YES)很多人都懵了:我什么时候创建过 replace_user 这个用户?其实谜底就在源码包的 SQL 文件里。Zabbix 源码包里的database/mysql目录下,存放的是模板 SQL 文件,并没有默认数据库密码。老版本用的create.sql.gz里就把初始化用户名写死了,如果直接在命令行里执行导入,它就会尝试用replace_user去连数据库,自然被 MySQL 拒绝。
我当时用来绕开这个坑的思路是:先手动建一个独立账号,再按顺序导表,最后才让 Zabbix 前端去连这个库。这样既规避了 replace_user 的问题,后续权限也好管理,不用把 root 密码直接写在 web 配置里。
先创建数据库和专属用户:
mysql -uroot -p CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; CREATE USER 'zabbix'@'localhost' IDENTIFIED BY 'YourPassword'; GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'localhost'; FLUSH PRIVILEGES;然后进入源码包里的database/mysql目录,按顺序导入。5.0 以前的版本通常是一个create.sql.gz,6.0 之后拆成了三个文件,顺序不能乱:
zcat schema.sql.gz | mysql -uzabbix -pYourPassword zabbix zcat images.sql.gz | mysql -uzabbix -pYourPassword zabbix zcat data.sql.gz | mysql -uzabbix -pYourPassword zabbix注意:密码含特殊字符时,在命令行里最好加上单引号包裹,比如
-p'YourP@ssword',防止 shell 把$、&这类符号提前解析掉,否则你会看到一个更诡异的授权失败。
导完表之后,再去 web 页面配置数据库连接,填上 zabbix 用户和新密码,一路点下一步基本就能过。这个报错最烦人的地方在于,网上搜索出来的结果往往让你去改zabbix_server.conf或者重启 mysql,其实根子就在初始化导库这一步,把顺序理顺就没那么多事。
1.2 PHP 环境检查不通过:时区与依赖一个都不能少
Zabbix 的 web 前端对 PHP 版本和扩展的要求非常严格。装 6.0 至少要 PHP 7.4,装 7.0 就得 PHP 8.0 以上。如果你用发行版自带的软件源装 PHP,版本太老,打开安装向导就会看到类似:
PHP version 7.4.3 does not satisfy minimum requirement of 8.0.0很多朋友在这个地方卡了很久,其实解决办法是给系统添加对应的第三方软件源,再把 PHP 升上去。比如 CentOS/Rocky 上用 EPEL 和 Remi 源,然后执行yum module reset php加上yum module install php:remi-8.2这类操作,装完再确认php -v已经是新版本。
版本对了之后,还会碰到扩展缺失的提示,常见的有bcmath、mbstring、gd、xml、ldap等。报错信息里写着哪个就装哪个,用发行版的包管理器安装即可。这时候有一个特别隐蔽的坑:PHP 的date.timezone没设置。安装向导会一直挂着一个 Warning,虽然能继续装,但后续监控图形里的时间会整体偏移 8 小时,触发器的时间判断也会跟着出问题,排查起来非常痛苦。
我一般直接在php.ini里改成:
date.timezone = Asia/Shanghai改完记得重启 php-fpm 或 Apache,让配置生效,再刷新安装向导页面,那个警告就会消失。
1.3 Server 和 Agent 启动失败:多半是配置文件参数没对齐
安装完成、数据库也初始化好后,systemctl start zabbix-server一执行,很多人直接被结果搞蒙,服务起不来或者起来了又停。这时候第一件事不是翻报错,而是去看日志:
tail -f /var/log/zabbix/zabbix_server.log我见过最多的是两类。一类是 socket 文件目录权限问题,日志里会写cannot bind socket to "/var/run/zabbix/zabbix_server_alerter.sock",这种通常是/var/run/zabbix目录属主不对,把目录属主改成 zabbix 用户就行。另一类更常见,是 agent 端的配置和 server 端对不上,agent 反复重启,日志里刷连接失败。
Agent 的配置文件一般叫zabbix_agentd.conf,里面这三个参数必须认真核对:
Server=127.0.0.1,192.168.10.10 ServerActive=192.168.10.10 Hostname=Zabbix serverServer表示允许谁来被动采集。ServerActive表示 agent 主动往哪个 server 上报数据。Hostname必须和前端页面添加主机时的名称完全一致,否则主动模式拿不到数据,前端会一直显示“ZBX 不可用”。
我第一次搭的时候,就是忘了改 Hostname,前端怎么加都报 agent 不可达,折腾到半夜才发现是名字没对上。
2. Web 界面与初始化:向导和日常页面里的坑
2.1 安装向导卡住或直接白屏
数据库导好了,PHP 也没问题,但打开http://你的IP/zabbix后,要么安装向导白屏,要么点了下一步之后一直转圈没反应。白屏的排查方向我建议按这个顺序来:先确认 php-fpm 进程是否在运行,再看 PHP session 目录是否可写,最后看浏览器控制台有没有 500 或者 502。
很多发行版安装 PHP 之后,/var/lib/php/session这个目录的属主是 root,Web 服务用户写不进去,Zabbix 前端初始化时无法写 session,就会直接白屏。处理办法也很简单:
chown -R nginx:nginx /var/lib/php/session注意把 nginx 换成你实际使用的 web 用户,Apache 的话一般是 apache 或 www-data。这个问题在 CentOS、Rocky 和 Ubuntu 上我都遇到过,几乎是必踩项。
另外如果你用的是 Nginx + PHP-FPM 而不是 Apache,还需要确认 Nginx 配置文件里的fastcgi_pass指向的是 PHP-FPM 监听的套接字或端口。很多教程里告诉你改 Nginx 配置,但不同发行版的默认路径不一样,改错一个字符,整个页面就是 502。
2.2 “Cannot connect to the database”排查三部曲
安装向导走到数据库配置那一步,填好账号密码之后,前端报出这句:
Cannot connect to the database.这个报错看起来直接,但原因可能藏在四五个地方。我现在的排查习惯是固定的三步:
第一步,先确认数据库服务本身在监听网络端口。有些 MySQL 部署把skip-networking打开了,本机用mysql -uzabbix -p能连,但 web 服务通过网络连不进去。用一条命令验证:
mysql -h127.0.0.1 -uzabbix -pYourPassword -e "select 1;"如果这里提示连接失败,检查 MySQL 配置文件里是否有skip-networking,去掉之后重启。第二步,确认 Zabbix 数据库用户的主机匹配关系。MySQL 的授权是“用户 + 来源主机”双重绑定的,你只授权了'zabbix'@'localhost',但 web 端实际用了127.0.0.1去连,一样会被拒。在 MySQL 里检查:
SELECT user, host FROM mysql.user WHERE user='zabbix';如果只有localhost,就补一个'zabbix'@'127.0.0.1'或者直接授权给'%',然后FLUSH PRIVILEGES。第三步,看 web 配置文件里的数据库参数有没有填错。Zabbix 前端的数据库连接信息在zabbix.conf.php里,确认$DB['SERVER']、$DB['USER']、$DB['PASSWORD']这三项和实际一致。这个文件路径在不同发行版上不太一样,最稳的查找方式是find / -name "zabbix.conf.php" 2>/dev/null。
补充一个生产环境里遇到的真实案例:数据库主机名填了
localhost,前端 PHP 解析走的是 IPv6 的::1,而 MySQL 只监听了 IPv4,导致连接被拒。把主机名改成127.0.0.1后立刻恢复正常。所以 Web 服务器和数据库在同一台机器时,别迷信 localhost,直接写 IP 反而更省事。
2.3 图形中文乱码:字体替换三板斧
Zabbix 默认带的字体不支持中文,监控图形里只要主机名或者监控项名称带中文,渲染出来全是一排排小方块,完全没法看。这个问题不影响监控数据,但影响你每天打开大屏时的观感,尤其要给领导汇报的时候,满屏方块真的很尴尬。
解决办法三步走:第一,取一个支持中文的 TTF/TTC 字体文件,比如从 Windows 系统目录下拷贝一个msyh.ttc(微软雅黑),或者下载开源字体文泉驿正黑。第二,把字体文件上传到 Zabbix 前端的字体目录里,常见路径有/usr/share/zabbix/assets/fonts、/usr/local/share/zabbix/assets/fonts,不同发行版路径不同,找带有DejaVuSans.ttf的目录就行。第三,修改前端字体配置,把默认字体名替换为新字体。
有些版本的 Zabbix 在zabbix.conf.php里直接有$DB['GRAPH_FONT_NAME']配置,改成你字体文件的完整名称,例如:
$DB['GRAPH_FONT_NAME'] = 'msyh';改完清一下浏览器缓存,再强制刷新页面,中文图形就正常了。如果用的 Zabbix 7.0,部分前端页面还支持在Administration -> General -> Other里直接配置默认字体,把字体名称填进去,效果一样。
3. 监控数据采集:主机添加不上与监控项拿不到数据
3.1 主机列表显示红色 ZBX:先分清主动模式和被动模式
前端添加完一台新主机,过一会儿去看,状态列出现一个红色的 ZBX,说明 Zabbix Server 跟 Agent 之间的连接出了问题。但连接问题分很多种,我不建议一上来就盯着防火墙,先把数据流向理清楚。
Zabbix 有两种模式。被动模式下,是 Server 主动连 Agent 的 10050 端口去拉数据;主动模式下,是 Agent 主动连 Server 的 10051 端口上报数据。如果你前端主机配置的是被动模式,检查顺序是:先在 Server 上用telnet 主机IP 10050测试端口通不通,再确认 Agent 进程是否在运行,最后检查防火墙和 SELinux。如果端口不通,大概率是防火墙拦截,放行端口即可:
firewall-cmd --permanent --add-port=10050/tcp && firewall-cmd --reload如果前端是一个灰色状态,那个代表不支持主动模式,需要重点看 Agent 配置里的ServerActive和Hostname是否和前端一致。
这里放一个可用性状态的速查表:
| 状态 | 含义 | 优先排查方向 |
|---|---|---|
| 绿色 ZBX | Agent 在线可用 | 无需处理 |
| 红色 ZBX | Server 连不上 Agent | 10050 端口、防火墙、Agent 进程 |
| 灰色 | 主动模式不可用 | ServerActive、Hostname 匹配 |
| 无标签 | 尚未开始采集 | 等待下一次刷新周期 |
3.2 Not supported 与 Timeout:监控项拿不到数据的六大原因
监控项状态变成not supported或者timeout,算是 Zabbix 日常使用里出现频率最高的报错之一。点进监控项详情,会看到一行具体错误信息,不同错误的处理方式差距很大,我直接整理成几个最典型场景。
第一种,key 写错了。Zabbix 的 key 有固定格式,比如system.cpu.load[percpu,avg1],中括号里的参数一个都不能多不能少。写错的话会直接提示Invalid key。解决方式是用页面上的“测试”按钮,输入 key 试一下返回结果。
第二种,Agent 配置里没有定义这个 key。比如你想采集一个自定义脚本,但没有在zabbix_agentd.conf里写UserParameter,报错就非常直接。自定义 key 的写法:
UserParameter=my.check,/usr/local/bin/my_check.sh改完配置后重启 agent,再用zabbix_get远程验证。第三种,脚本执行超时。UserParameter调用的脚本默认执行时间很短,如果脚本逻辑复杂、网络请求慢,很容易触发 timeout。这时候把 agent 配置文件里的Timeout参数调大,一般设置成 10 秒或者 30 秒足够。
第四种,外部检查和网络探测类 key 依赖 fping。像icmpping、icmppingloss这类 key 如果没安装 fping,会报fping: not found。装好 fping 还要注意 setuid 权限,否则非 root 用户调用时还是会失败。第五种,权限问题。Agent 进程以普通用户身份运行,但脚本需要读取 root 才能读的文件,或者脚本本身没有执行权限,都会导致采集失败,报错信息一般是 permission denied。第六种,时间不同步。Server 和 Agent 的系统时间差太多,某些校验严格的场景会出现奇怪报错,最稳妥的做法是用 NTP 统一时间。
3.3 自监控“Host unreachable”却实际可用,这是个隐蔽问题
比红色 ZBX 更迷惑的是:Zabbix 自己监控自己,前端却一直报Host unreachable,但用浏览器访问 web 界面、用zabbix_get测本机 agent 全都是正常的。这种情况大概率是“监听地址不匹配”导致的。
Zabbix Server 的默认配置会监听所有网卡,但前端添加“Zabbix server”这台主机时,接口 IP 填的是127.0.0.1。如果 Agent 配置文件里的Server参数只写了内网 IP 而没有包含 127.0.0.1,那么 Server 从 127.0.0.1 去连 Agent,Agent 一看来源 IP 不在允许列表里,直接拒绝,于是自监控一直报不可达。
我当时的解法是:把前端里“Zabbix server”主机的接口 IP 改成实际内网 IP,同时确认 Agent 配置里Server包含了这个内网 IP,两边对齐后问题立刻消失。这种问题最大的坑在于表面看起来一切正常,数据也在采集,但告警一直在刷,非常容易让人误判为网络故障。
4. 告警与联动:钉钉通知、误报与告警风暴
4.1 Zabbix 7.0 联动钉钉:脚本和 Webhook 的常见报错
Zabbix 和钉钉的联动是现在告警通知的主流方案,当年我在生产环境接第一套钉钉告警时,也是被各种错误码折磨得不轻。钉钉群自定义机器人的安全设置有三种:自定义关键词、加签、IP 白名单。最容易踩的坑集中在这几个报错上。
第一个错:errcode: 310000, errmsg: keywords not in content。这是你在群里配置了关键词,但消息内容里没带这个词。比如关键词设了“告警”,那消息正文里必须包含“告警”二字,否则钉钉拒绝发送。第二个错:errcode: 310000, errmsg: sign not match。这是加签模式下签名计算错误。加签要求把时间戳和密钥做 HMAC-SHA256 加密,再 base64 编码,最后还要做一次 URL 编码,拼接在 Webhook 地址后面。很多脚本死在少了最后一步 URL 编码上。第三个错:中文内容乱码或发送失败。脚本里发 HTTP 请求时,如果没正确设置 JSON 编码,中文会变成UnicodeEncodeError,Python 脚本尤其常见。用json.dumps保证数据序列化正确,再指定Content-Type: application/json基本就能解决。
我自己常用的一段 Python 加签脚本核心逻辑是这样的:
import time import hmac import hashlib import base64 import urllib.parse import requests secret = "SEC你的密钥" timestamp = str(round(time.time() * 1000)) string_to_sign = f'{timestamp}\n{secret}' hmac_code = hmac.new( secret.encode('utf-8'), string_to_sign.encode('utf-8'), digestmod=hashlib.sha256 ).digest() sign = urllib.parse.quote_plus(base64.b64encode(hmac_code)) webhook = "https://oapi.dingtalk.com/robot/send?access_token=你的Token" url = f"{webhook}×tamp={timestamp}&sign={sign}" data = { "msgtype": "text", "text": { "content": "【Zabbix告警】服务器CPU负载过高,请及时处理" } } resp = requests.post(url, json=data) print(resp.text)重要提醒:机器人 Webhook 地址和密钥相当于告警通道的钥匙,千万别写进公开的配置仓库。密钥一旦泄露,任何人都可以向你的钉钉群发垃圾消息。
另外 Zabbix 7.0 新版的 Webhook 媒体类型做得已经比较完善,能配置钉钉、企业微信等。如果脚本方案维护成本高,可以用官方 Webhook 方案,但要注意不同版本之间字段名有差异,升级后需要重新测试一遍。
4.2 闪断误报与告警风暴:别让告警变成狼来了
告警配好之后,接下来困扰人的就是误报。最常见的情况是某个监控项值只在某一瞬间超过了阈值,触发器立刻触发,过一分钟又恢复了,于是告警事件刷个不停。这种“闪断误报”特别容易让人对告警系统失去信任。
我常用的优化思路有三个。第一,给触发器加“恢复延迟”,也就是要求问题持续一定时间才触发告警,比如nodata(5m)或者min(5m)配合触发器表达式,避免网络抖动造成的瞬间采样超阈值。第二,用趋势类函数替代瞬时值,比如avg(//10m)表示最近 10 分钟的平均值,这样偶尔一两次尖峰不会触发告警。第三,触发器表达式里设置恢复条件表达式,确保只有问题持续存在时才维持告警状态。
举一个 CPU 告警的例子,优化前:
system.cpu.util[,idle].last()<10优化后:
avg(system.cpu.util[,idle],5m)<10 and nodata(system.cpu.util[,idle],5m)=0这样 5 分钟内 CPU 空闲持续低于 10% 才告警,比只看最后一条数据的抖动小很多。告警风暴的另一个常见来源是“主机批量宕机”,比如交换机断电导致几十台机器同时不可达,告警消息瞬间刷屏。建议对网络设备做单独的网络监控模板,对服务器批量宕机场景使用业务分组和聚合告警,把噪音降下来,才能让真正重要的告警被第一时间看到。
5. 模板、数据处理与面试高频题
5.1 模板导入报错:版本与依赖是最大杀手
从社区下载一个模板,再用 Zabbix 前端的导入功能上传时,有两条高频报错:Cannot import template: invalid XML和Template already exists。
先说 invalid XML。模板文件本身是一个 XML 结构,开头长这样:
<?xml version="1.0" encoding="UTF-8"?> <zabbix_export> <version>6.0</version> <template_groups> ...如果你从 Zabbix 5.0 导出的模板,直接导入到 4.0 版本,或者反过来,报错的概率极高,因为<version>字段对应的结构和 4.0 不兼容。这时候要么找对应版本范围的模板,要么对模板文件做低版本兼容性改造。还有一个容易忽略的原因:模板文件的编码不是 UTF-8,从某些文本编辑器另存为 UTF-8 后重新导入即可。
再说 Template already exists。这个很好理解,库里已经存在同名模板。解决办法是导入时选择“更新已有模板”,或者先把旧模板删了再导入。但要注意,如果旧模板已经关联了监控主机,删除模板会导致这些主机的监控项被清除,操作前必须确认影响范围。另外就是模板依赖。有些模板引用了另一个基础模板,但你的 Zabbix 里没导入或被改名了,会报依赖缺失。去模板发布页把依赖模板一并下载导入,再导主模板,就能解决。
5.2 数据库膨胀:历史数据表才是磁盘杀手
Zabbix 跑了一年半载之后,数据库越来越胖,这是每一个 Zabbix 用户都会遇到的现实问题。我见过最夸张的一台监控服务器,history表占了快 200GB,磁盘报警告了才发现。报错信息一般是No space left on device或者数据库无响应。
原因很好理解:Zabbix 默认保存详细历史数据,比如 CPU、内存、磁盘 IO 这些指标,每个监控项每 30 秒或 1 分钟写一条记录,生产环境几百台机器一天就能产生几千万条数据。housekeeper 清理虽然在工作,但如果写入速度比清理速度快,磁盘就会持续增长。
常规解法有四个方向:第一,调整历史数据保留时间。进入Configuration -> Hosts,找到对应主机或模板,修改“历史数据保留期”和“趋势数据保留期”。一般历史数据保留 7 到 30 天足够,趋势数据可以保留半年到一年。第二,给history表做分区,按月分区,月底直接丢弃过期分区,删除大量数据时比 DELETE 语句快一个数量级。第三,数据库层面对历史表做定期归档,把数据导出到冷存储。第四,从 Zabbix 6.0 开始支持 TimescaleDB,启用压缩能力后,历史数据可以极大压缩,查询性能也更好。升级前记得先做兼容性评估,TimescaleDB 的安装和配置又是一个独立话题。
建议对磁盘使用率设置独立的监控项,比如 agent 的
vfs.fs.size[/,pused],阈值设在 80% 就告警,别等到No space left on device才反应过来。
5.3 面试高频题:Zabbix 报错排查思路速查
结合我这几年带人和被面试的经历,整理几个高频的 Zabbix 报错排查面试题。它们看着简单,但非常能看出一个人对监控体系的理解深度。
第一个:一台新加的主机显示红色 ZBX,你会怎么排查?参考回答顺序:先确认 Agent 进程运行状态,再确认前端填写的主机 IP 和端口是否正确,然后从 Server 端 telnet Agent 的 10050 端口,检查防火墙和 SELinux,最后看一眼 Agent 配置文件里Server允许列表是否包含 Server 的 IP。第二个:监控项报 not supported,常见原因有哪些?答案是 key 语法错误、Agent 端缺少对应的 UserParameter、脚本执行超时、权限不足、依赖工具缺失。第三个:主动模式和被动模式有什么区别?被动模式是 Server 主动拉取 Agent 数据,Agent 只需开放 10050 端口;主动模式是 Agent 主动上报数据到 Server 的 10051 端口,要求Hostname和前端一致,适合跨网络、大量主机场景,能减轻 Server 端的连接压力。第四个:自定义监控项怎么添加?先在 Agent 配置里定义 UserParameter,重启 Agent,再用 zabbix_get 验证,最后在前端创建监控项、套用模板或者直接挂到主机上。第五个:数据库越来越大怎么办?优化历史数据保留周期、分区归档、使用 TimescaleDB 压缩、调整 housekeeper 清理频率。
面试时把这几个问题答清楚,基本就说明你有真正的 Zabbix 使用经验,而不是只会照着教程点击鼠标。
最后分享一个我自己的习惯:每次改完配置,先看一眼zabbix_server.log和zabbix_agentd.log的最后几十行,90% 的报错都会在几分钟内刷出来。别急着去搜索工具复制整段中文报错,先把日志里的时间戳、IP、错误码这三样东西提炼出来,再组合关键词去搜,效率高得多。Zabbix 的报错信息其实一直很直白,只要按“网络 -> 权限 -> 配置 -> 数据”这四层逻辑去查,大部分问题都能在十几分钟内定位。这篇集锦我会继续更新,把新遇到的坑持续补进来,希望对你有实际帮助。