1. 从零拆解Zabbix客户端监控:为什么被动模式依然是生产环境的首选
搞过几年运维的人都有一个共识:监控系统搭起来容易,但真正让它稳定跑三年、五年不出幺蛾子,靠的不是花哨的界面,而是底层数据采集的可靠性。Zabbix这套东西我从早期版本一路用到现在的6.x、7.x,踩过的坑比吃过的饭还多。今天聊的Zabbix客户端监控Linux,说白了就是怎么让Zabbix Server通过Agent把一台Linux机器的CPU、内存、磁盘、网络、进程这些指标稳稳当当地收上来。这件事听起来简单,但里面涉及的东西一点都不少——从Agent的安装配置、被动模式与主动模式的取舍、防火墙和SELinux的纠缠,一直到自定义key的编写与调试,每一步都有讲究。
这篇文章适合谁看?如果你刚接手一套Zabbix监控系统,或者正准备给一批新上架的Linux服务器接入监控,又或者你已经在用Zabbix但总觉得数据采集不够灵活、想通过自定义key搞定业务层面的监控需求,那这篇内容就是写给你的。我会把被动模式的完整链路拆开讲透,包括每一步为什么这么做、参数怎么算、出问题怎么查,最后再重点讲自定义key的实战写法。整个过程我会用一台模拟的Linux主机作为示例,所有命令和配置都可以直接抄作业。
先说一个基本判断:在绝大多数中小规模场景下,Zabbix Agent的被动模式(Passive Check)依然是首选。为什么?因为它的逻辑最直观——Server端发起请求,Agent端响应返回数据。这种“拉”的模式让Server完全掌控采集节奏,配置简单、排查方便。主动模式虽然在大规模场景下能减轻Server压力,但它把采集的主动权交给了Agent,一旦Agent端出问题,Server端很难第一时间感知。所以我的建议是:先把被动模式吃透,再根据规模决定要不要切主动。
2. 被动模式的核心链路与Agent部署实操
2.1 被动模式到底是怎么工作的
要理解被动模式,你得先搞清楚数据是怎么从被监控主机流到Zabbix Server的。整个链路其实就四步:Server端根据监控项配置,定期向Agent的10050端口发起TCP连接;Agent收到请求后,查找对应的key;Agent执行这个key对应的采集逻辑,拿到结果;Agent把结果返回给Server,Server存入数据库并触发触发器计算。
这里面有个关键点很多人忽略:被动模式下,是Server主动连接Agent,所以防火墙规则要在Agent所在主机上放行10050端口的入站流量。我见过太多人配了半天发现数据上不来,最后发现是防火墙没放行,或者SELinux把端口访问给拦了。这个后面会详细讲。
被动模式的另一个特点是,每个监控项的采集间隔是独立的。比如CPU使用率可能30秒采一次,磁盘空间可能5分钟采一次,这些都由Server端的监控项配置决定,Agent端不需要关心采集频率。这种设计的好处是灵活,坏处是当监控项数量很多时,Server端的轮询压力会比较大。
2.2 Agent安装:包管理器和源码编译怎么选
在Linux上装Zabbix Agent,通常有两条路:用系统包管理器装,或者从源码编译。我的经验是,优先用包管理器,除非你有特殊需求(比如需要特定版本、需要自定义编译参数)。
以常见的RPM系发行版为例,先安装官方仓库配置包,然后直接装:
rpm -Uvh https://repo.zabbix.com/zabbix/6.4/rhel/8/x86_64/zabbix-release-6.4-1.el8.noarch.rpm dnf clean all dnf install -y zabbix-agentDebian/Ubuntu系类似:
wget https://repo.zabbix.com/zabbix/6.4/ubuntu/pool/main/z/zabbix-release/zabbix-release_6.4-1+ubuntu22.04_all.deb dpkg -i zabbix-release_6.4-1+ubuntu22.04_all.deb apt update apt install -y zabbix-agent装完之后,Agent的配置文件通常在/etc/zabbix/zabbix_agentd.conf。这个文件里参数很多,但真正需要你改的就那么几个。我下面列一个最小可用配置的对照表:
| 参数 | 默认值 | 建议值 | 说明 |
|---|---|---|---|
| Server | 127.0.0.1 | Zabbix Server的IP | 允许哪些Server来拉数据 |
| ServerActive | 127.0.0.1 | 同Server | 主动模式下用的,被动模式可不管 |
| Hostname | 本机hostname | 与Web端配置的主机名一致 | 必须完全匹配,否则数据对不上 |
| ListenPort | 10050 | 10050 | 除非端口冲突,否则别改 |
| StartAgents | 3 | 3-10 | 被动模式下并发处理请求的进程数 |
| Timeout | 3 | 3-5 | 采集超时时间,自定义key耗时长要调大 |
这里重点说三个参数。Hostname必须和Web端添加主机时填的主机名一模一样,大小写敏感。我踩过这个坑:有次批量部署,脚本里用了小写hostname,Web端填的是大写,结果Agent明明在跑,Server就是收不到数据,查了半天才发现是名字对不上。
StartAgents这个值要根据监控项数量和采集频率来调。默认3个进程,如果你有几百个监控项、采集间隔又短,3个进程可能不够用,会出现请求排队甚至超时。一般建议按“监控项数量 ÷ 10”来估算,但不要超过CPU核数的两倍。
Timeout默认3秒,对于大部分系统级监控项够用。但如果你写了自定义key去执行一个耗时的脚本,比如查数据库或者调接口,3秒肯定不够,这时候要调到10秒甚至30秒。注意Server端也有一个Timeout配置,两边的值要匹配,否则Server端先超时了,Agent返回再快也没用。
2.3 防火墙与SELinux:两个最容易翻车的地方
Agent装好了、配置改完了,启动之前先把防火墙和SELinux处理好,不然你会在排查上浪费大量时间。
防火墙方面,如果用的是firewalld:
firewall-cmd --permanent --add-port=10050/tcp firewall-cmd --reload如果用的是iptables:
iptables -A INPUT -p tcp --dport 10050 -j ACCEPT service iptables saveSELinux这块要特别注意。很多人一上来就setenforce 0把SELinux关了,这在生产环境是不推荐的。正确的做法是给Zabbix Agent相关的进程和端口打上正确的标签。不过说实话,Zabbix Agent的SELinux策略在大多数发行版里已经配好了,你只需要确认端口标签正确:
semanage port -l | grep zabbix如果10050端口没有关联到zabbix_port_t,可以手动加:
semanage port -a -t zabbix_port_t -p tcp 10050提示:如果你确实不想折腾SELinux,临时用
setenforce 0测试可以,但生产环境一定要用setsebool或者semanage做持久化配置,别直接改配置文件里的SELINUX=disabled然后重启,那样影响面太大。
2.4 启动Agent并验证连通性
配置改好之后,启动并设置开机自启:
systemctl start zabbix-agent systemctl enable zabbix-agent systemctl status zabbix-agent验证分两步。先在Agent本机自测:
zabbix_agentd -t agent.ping如果返回agent.ping [u|1],说明Agent本身工作正常。然后再从Zabbix Server端测试连通性:
zabbix_get -s 被监控主机IP -p 10050 -k agent.ping返回1就说明Server能正常拉到数据。如果这一步失败,按这个顺序排查:网络通不通(ping/telnet 10050)、防火墙放没放行、Agent进程在不在、配置文件里Server参数有没有包含Server的IP。
3. 自定义Key:让监控覆盖业务层面的真实需求
3.1 为什么内置Key不够用
Zabbix Agent内置了几百个key,覆盖了CPU、内存、磁盘、网络、进程、文件等常见指标。但实际运维中,你总会遇到内置key搞不定的场景。比如:你想监控某个业务进程处理队列的积压数量、想监控某个接口的响应时间、想统计某个目录下特定类型文件的数量、想检查某个定时任务上次执行是否成功。这些需求,内置key要么做不到,要么做起来很别扭。
自定义key就是解决这个问题的。它的本质是:你在Agent端定义一个key名字,把它映射到一条命令或者一个脚本,Server端就可以像用内置key一样去调用它。这样一来,任何你能用命令拿到的东西,都能变成Zabbix的监控项。
3.2 自定义key的配置语法与参数详解
自定义key的配置写在Agent配置文件的UserParameter指令里,格式是:
UserParameter=key_name,command看起来简单,但有几个细节必须注意。key_name里可以带参数,用逗号分隔,在command里用$1、$2这样的位置变量引用。比如:
UserParameter=check.process[*],/usr/bin/pgrep -c $1这样Server端就可以用check.process[nginx]来查nginx进程数,用check.process[mysql]来查mysql进程数。这种带参数的写法非常实用,一个key能覆盖一类需求。
command必须是绝对路径。Agent执行命令时的环境变量和你的登录shell不一样,PATH可能很精简,所以pgrep要写成/usr/bin/pgrep,python要写成/usr/bin/python3。这个坑我踩过不止一次,在命令行里跑得好好的脚本,配到UserParameter里就报command not found,就是因为PATH的问题。
command的输出必须是单行文本。Zabbix Agent会把命令的stdout作为监控值返回,如果输出多行,只有第一行有效。所以你的脚本最后要确保只输出一个值。如果是数字,直接输出数字;如果是文本,注意不要有换行符。
命令的退出码很重要。如果命令返回非0退出码,Zabbix会认为这次采集失败,监控项会变成unsupported状态。所以脚本里要做好错误处理,即使出错也要exit 0并输出一个约定的值(比如-1),而不是让脚本崩掉。
3.3 一个完整的自定义Key实战案例
光说理论没意思,我拿一个实际场景来演示。假设我们要监控一台Linux服务器上某个日志目录里,最近5分钟内产生的错误日志条数。这个需求内置key做不到,必须自定义。
第一步,写采集脚本。放在/etc/zabbix/scripts/check_error_log.sh:
#!/bin/bash LOG_DIR="/var/log/myapp" MINUTES=5 COUNT=$(find "$LOG_DIR" -name "*.log" -mmin -$MINUTES -exec grep -c "ERROR" {} \; 2>/dev/null | awk '{sum+=$1} END {print sum+0}') echo "${COUNT:-0}" exit 0这个脚本的逻辑是:找到日志目录下最近5分钟内修改过的.log文件,统计其中包含ERROR的行数,把所有文件的结果加起来。注意最后的${COUNT:-0},如果COUNT为空就输出0,避免返回空值导致监控项异常。
第二步,给脚本加执行权限:
chmod +x /etc/zabbix/scripts/check_error_log.sh chown zabbix:zabbix /etc/zabbix/scripts/check_error_log.sh注意属主要是zabbix用户,因为Agent是以zabbix身份运行的。如果脚本需要读取只有root才能访问的文件,要么改文件权限,要么用sudo配置免密,这个后面讲。
第三步,在Agent配置文件里加UserParameter。建议不要直接改主配置文件,而是在/etc/zabbix/zabbix_agentd.d/目录下新建一个.conf文件,比如custom_checks.conf:
UserParameter=app.errorlog.count,/etc/zabbix/scripts/check_error_log.sh这样做的好处是升级Agent时不会覆盖你的自定义配置,管理起来也清晰。
第四步,重启Agent并测试:
systemctl restart zabbix-agent zabbix_agentd -t app.errorlog.count如果返回类似app.errorlog.count [t|3]的结果,说明key工作正常。然后从Server端再测一次:
zabbix_get -s 被监控主机IP -k app.errorlog.count两边都通了,就可以去Web端创建监控项了。监控项的key直接填app.errorlog.count,类型选Zabbix Agent(被动),信息类型选数字(无符号),这样就能正常采集和告警了。
3.4 带参数的自定义Key进阶用法
上面那个例子是固定逻辑的key。实际场景中,我们往往希望一个key能灵活应对不同参数。比如监控不同服务的进程状态,或者检查不同端口的连通性。
来看一个带参数的例子,监控指定TCP端口的连通性:
UserParameter=net.tcp.check[*],/usr/bin/nc -z -w 2 127.0.0.1 $1 && echo 1 || echo 0Server端用net.tcp.check[3306]检查MySQL端口,用net.tcp.check[6379]检查Redis端口。返回值1表示通,0表示不通。这种key在触发器里特别好用,直接判断值等于0就告警。
再来看一个更复杂的,监控某个URL的HTTP状态码和响应时间:
UserParameter=web.url.status[*],/usr/bin/curl -o /dev/null -s -w "%{http_code}" --max-time 5 $1 UserParameter=web.url.time[*],/usr/bin/curl -o /dev/null -s -w "%{time_total}" --max-time 5 $1这两个key配合使用,一个监控状态码是否200,一个监控响应时间是否超过阈值。注意--max-time 5要小于Agent的Timeout配置,否则curl还没返回,Agent就先超时了。
注意:带参数的自定义key,参数里如果包含特殊字符(比如URL里的
&、?),在Server端配置时要注意转义。另外,参数不要直接拼接进shell命令里执行,有命令注入风险。如果参数来自不可信来源,一定要做校验。
4. 权限、安全与性能:自定义Key绕不开的三个硬骨头
4.1 Agent执行权限的边界在哪里
Zabbix Agent默认以zabbix用户运行,这个用户权限很低,这是出于安全考虑的正确设计。但低权限意味着很多操作做不了,比如读取root才能访问的日志、执行需要特权的命令、访问某些系统文件。
遇到权限问题,有三种解决思路,我按推荐程度排序:
第一种,调整文件或目录权限。如果只是读某个日志文件,把文件属组改成zabbix,或者给other加读权限。这是最简单也最安全的做法。比如:
chown root:zabbix /var/log/myapp/error.log chmod 640 /var/log/myapp/error.log第二种,用sudo做精细化授权。如果脚本确实需要root权限执行某条命令,可以配置sudoers,只允许zabbix用户免密执行特定的命令,而不是给全部权限。在/etc/sudoers.d/zabbix里加:
zabbix ALL=(root) NOPASSWD: /usr/bin/systemctl status myservice然后在UserParameter里用sudo /usr/bin/systemctl status myservice调用。注意sudoers文件权限必须是440,否则sudo会拒绝加载。
第三种,用Setuid或者Capabilities。这两种方式风险较高,除非你非常清楚自己在做什么,否则不建议在生产环境使用。Setuid脚本本身就有安全风险,Capabilities虽然更精细,但配置复杂,容易出错。
我的经验是,90%的权限问题都能用第一种方式解决,剩下9%用sudo,只有极特殊情况才考虑第三种。
4.2 自定义Key的安全红线
自定义key本质上是在Agent端执行命令,如果配置不当,会变成安全漏洞。几条红线必须守住:
绝对不要把用户输入直接拼接到命令里执行。比如UserParameter=check.ping[*],ping -c 1 $1,如果Server端传进来的参数是127.0.0.1; rm -rf /,那就出大事了。正确的做法是在脚本里对参数做白名单校验,只允许合法的IP格式通过。
脚本里不要硬编码敏感信息。数据库密码、API密钥这些东西,不要直接写在脚本里。可以用环境变量或者独立的配置文件,并且把配置文件权限设为600。
限制Server端的访问来源。Agent配置文件里的Server参数要明确指定Zabbix Server的IP,不要用0.0.0.0/0这种全放开的写法。如果有多台Server或者Proxy,逐个列出来。
定期审计自定义key。时间长了,自定义key会越加越多,有些可能已经废弃了但还在跑。建议每季度过一遍,把不用的清理掉,减少攻击面。
4.3 性能优化:别让自定义Key拖垮Agent
自定义key如果写得不好,会严重影响Agent的性能,甚至导致Agent假死。几个优化要点:
控制脚本执行时间。Agent的Timeout默认3秒,如果脚本经常跑好几秒,会占用Agent进程,导致其他监控项采集延迟。脚本里要加超时控制,比如用timeout 2 command限制命令最长执行时间。
避免频繁执行重操作。如果某个自定义key需要查数据库或者调接口,不要每次采集都去查。可以在脚本里做本地缓存,比如把结果写到临时文件,设置一个缓存有效期,有效期内直接读缓存。
合理设置采集间隔。不是所有指标都需要30秒采一次。日志错误数这种变化不频繁的指标,5分钟采一次就够了。采集间隔越长,Agent压力越小。
监控Agent自身的性能。用zabbix[wcache,values]这类内置key监控Agent的队列情况,如果发现队列积压,说明采集压力过大,需要调整。
下面这张表总结了自定义key常见的性能问题和对应措施:
| 问题现象 | 可能原因 | 解决措施 |
|---|---|---|
| 监控项频繁unsupported | 脚本超时或返回非0 | 加timeout控制,脚本末尾exit 0 |
| Agent CPU占用高 | 脚本执行太频繁或太重 | 拉长采集间隔,加缓存 |
| 数据采集有延迟 | StartAgents不够 | 增加StartAgents值 |
| 部分监控项无数据 | 脚本权限不足 | 检查zabbix用户权限 |
| Server端收不到数据 | 防火墙或Hostname不匹配 | 检查网络和主机名配置 |
5. 常见故障排查与避坑经验实录
5.1 监控项变成Unsupported怎么办
这是最常见的问题,没有之一。监控项变成红色unsupported,意味着Agent返回的数据Server无法解析,或者Agent执行key时出错了。排查思路是自下而上:
先在Agent本机用zabbix_agentd -t key_name测试。如果本机就失败,看Agent日志/var/log/zabbix/zabbix_agentd.log,里面会写明具体错误。常见原因有:脚本路径不对、脚本没有执行权限、脚本输出多行、脚本返回非0退出码。
如果本机测试通过,但从Server端用zabbix_get失败,那问题在网络上或者Server配置上。检查防火墙、检查Server端监控项的key是否写对、检查Hostname是否匹配。
如果zabbix_get也通过,但Web端还是unsupported,那可能是监控项的信息类型配错了。比如脚本返回的是浮点数,但监控项信息类型选的是数字(无符号),就会解析失败。这时候要么改脚本输出整数,要么改监控项类型为浮点数。
5.2 数据有延迟或断断续续
数据延迟通常和Agent的并发处理能力有关。被动模式下,Server端发起的每个请求都需要一个Agent进程来处理。如果StartAgents设得太小,请求就会排队。默认3个进程,在监控项不多的情况下够用,但如果你的主机有几百个监控项,建议调到10以上。
另一个原因是网络抖动。如果Server和Agent之间网络不稳定,TCP连接会超时重试,导致数据延迟。这种情况可以在Server端调整Timeout和UnreachableDelay参数,但根本解决还是要靠网络质量。
还有一种情况是Agent所在主机负载太高,CPU被占满,Agent进程抢不到时间片。这时候要看看是不是有别的进程在吃资源,或者Agent本身的采集任务太重。
5.3 自定义Key不生效的几种典型情况
自定义key配了但不起作用,我总结了几种典型情况:
配置文件没加载。如果你把UserParameter写在zabbix_agentd.d/目录下的文件里,要确认主配置文件里Include指令包含了这个目录。默认是有的,但如果你改过配置,可能被注释掉了。
改完没重启Agent。UserParameter的改动必须重启Agent才能生效,systemctl restart zabbix-agent。我见过有人改完配置直接测试,发现不生效,折腾半天才想起来没重启。
key名字冲突。如果你自定义的key名字和内置key重名了,内置key优先级更高,你的自定义key会被忽略。所以自定义key最好加个前缀,比如custom.或者app.,避免冲突。
参数传递问题。带参数的key,Server端配置时方括号里的参数要和UserParameter定义的位置对应。比如定义了UserParameter=check[*],script $1 $2,Server端就要用check[arg1,arg2],少传一个参数脚本就会出错。
脚本编码问题。如果脚本里有中文或者特殊字符,要确保文件编码是UTF-8,并且脚本开头指定了正确的解释器。有些环境下脚本编码不对会导致执行失败。
5.4 一份实用的排查速查表
| 故障现象 | 排查命令 | 可能原因 | 解决方法 |
|---|---|---|---|
| Agent启动失败 | systemctl status zabbix-agent | 配置语法错误 | 检查配置文件,用zabbix_agentd -T测试 |
| Server拉不到数据 | zabbix_get -s IP -k agent.ping | 防火墙/网络 | 放行10050端口,检查网络 |
| 监控项unsupported | zabbix_agentd -t key | 脚本错误/权限 | 看Agent日志,检查脚本 |
| 数据延迟 | `zabbix_agentd -p | grep wcache` | 并发不够 |
| 自定义key不生效 | zabbix_agentd -t custom.key | 配置未加载 | 重启Agent,检查Include |
| 权限拒绝 | sudo -u zabbix command | zabbix用户权限不足 | 调整文件权限或配sudo |
提示:排查问题时,养成先看日志的习惯。Agent日志在
/var/log/zabbix/zabbix_agentd.log,Server日志在/var/log/zabbix/zabbix_server.log。日志级别可以在配置文件里调,排查阶段可以临时调到debug,问题解决后记得调回来,否则日志会爆。
6. 从被动到主动:什么时候该切换模式
被动模式虽然好用,但它有一个天然的瓶颈:所有采集请求都由Server发起,当被监控主机数量达到几百上千台时,Server端的轮询压力会非常大。这时候就该考虑主动模式了。
主动模式下,Agent主动连接Server的10051端口,把数据推上去。Server端不需要维护大量的轮询连接,压力小很多。但主动模式的代价是配置更复杂,而且Agent端出问题时Server不容易感知。
我的建议是:主机数量在200台以下,被动模式完全够用;超过200台,考虑混合模式——关键指标用被动,批量指标用主动;超过500台,建议上Zabbix Proxy做分布式采集。
切换主动模式时,Agent配置文件里要设置ServerActive为Server的IP,监控项类型要改成“Zabbix Agent(主动)”,Hostname依然要严格匹配。另外主动模式下Agent会先把数据缓存在本地buffer里,如果Server长时间不可达,buffer满了会丢数据,所以BufferSize参数要根据数据量适当调大。
最后分享一个我在实际环境中的做法:对于新接入的主机,先用被动模式跑一周,确认所有监控项都正常采集、触发器都正常工作,再根据规模决定是否切主动。这样出了问题容易定位,不会一上来就搞复杂。
这个内容后续还可以这样扩展:结合Zabbix的Low-Level Discovery做自动发现,让自定义key能动态监控变化的资源(比如动态增加的网卡、目录、服务);或者把自定义key的采集结果通过Zabbix的依赖项和计算项做二次加工,生成更有业务价值的复合指标。这些等把基础打牢了再折腾,效果会好很多。