多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Zabbix poller进程CPU 100%?5大根因与排查方案详解

Zabbix poller进程CPU 100%?5大根因与排查方案详解 如果你负责的Zabbix最近频繁告警或者打开前端看到数据延迟一片红第一反应多半是冲到服务器上敲top。结果一敲就愣住了一堆zabbix_server进程里poller进程的CPU占用齐刷刷冲到100%主机负载直接飘到几十业务方开始连环夺命call……这种场景我经历过太多次。Zabbix poller进程说白了就是干采集的工人一个工人卡死影响的就是整条监控链路。这篇文章把我实际运维中遇到的poller进程100%占用的5类根因和对应解法全部摊开讲从现象、定位到优化方案顺便把踩过的坑也一并交代清楚。不管你是刚上手Zabbix的新手还是被监控性能折磨的老运维这份避坑指南都能拿来直接救火。1. 先搞懂Zabbix poller到底在忙什么1.1 poller不是一个人干活进程池模型先理清Zabbix server是个多进程程序安装完成后你执行ps -ef | grep zabbix_server会看到一大堆zabbix_server进程。这不是程序异常而是Zabbix有意为之的进程池设计。和线程不同进程之间拥有独立的内存空间一个进程崩溃不会波及同伴。在这么多进程里poller是最核心的一类工种。poller全称polling process直译过来就是轮询进程专门负责执行Zabbix里的各种数据采集任务比如连接Zabbix agent、查询SNMP设备、读取IPMI信息、做简单检查等等。我们配置的每个监控项最终都要由一个poller进程去跑。Zabbix server配置里有几个和poller强相关的参数最核心的是StartPollers默认5和StartPingers默认1。StartPingers专门负责ICMP ping检查StartPollers则是常规检查的通用工人。这里有个关键基础知识每个poller进程在同一时间只能干一件事。打个比方一个poller正在取A主机的CPU负载它就没法同时去取B主机的内存数据。如果这次检查是阻塞的比如网络迟迟没有响应这个poller就会卡在原地干等。这一点是所有后续问题产生的根源一定先记在脑子里。1.2 单核100%不等于整机故障先学会看指标我在最开始处理这个问题时最大的误区是一看到top里Zabbix进程CPU 100%就觉得天塌了。实际上如果服务器是8核16线程一个poller进程吃满一个逻辑核心整体负载其实只有6%左右不一定产生用户可见的故障。真正要警惕的是两类情况一类是多个poller进程全部处于忙等待状态对应的核心全部打满另一类是poller进程本身空闲但任务队列越堆越高前端数据延迟越来越明显。怎么区分呢建议先看Zabbix内部监控项这是最直接的方法。在Zabbix server本机装一个agent然后添加官方自带的“Zabbix Server”模板里面自带了zabbix[process,poller,avg,busy]这类内部键可以直接反映poller平均忙碌百分比。如果这个值长期保持在90%以上说明poller确实忙不过来。再配合zabbix[queue,60]看看有多少监控项已经延迟超过60秒就能判断问题到底出在采集能力还是出在其他环节。再强调一次“100%占用”这个表述要分清两种底层状态一种是CPU计算密集导致的高占用另一种是进程卡在I/O等待上导致的“活锁”。前者通常意味着检查任务本身太重后者往往指向数据库慢或者网络超时。后面每一类原因我都会把这两种情况区分开来讲。2. 原因一监控项数量与采集间隔失衡poller当然扛不住2.1 先用一道算术题定位“监控项爆炸”如果poller进程全忙最先怀疑的就是监控项数量和采集间隔的搭配出了问题。Zabbix每个poller是串行执行检查的一个检查没跑完下一个不会开始。所以一个poller单位时间内能处理的任务数大约等于“1秒除以单次检查平均耗时”。而整个server每秒需要发起多少次检查可以用一个简单公式估算每秒检查数 ≈ 主机数 × 每台主机监控项数 ÷ 监控项刷新间隔秒举个例子。假设你有2000台主机每台都绑定了默认模板里面有20个监控项刷新间隔都是60秒。那么每秒要跑2000乘以20再除以60约等于666.7次检查。如果单次检查平均耗时50毫秒考虑到网络RTT和agent内部处理一个poller每秒大约只能完成20个检查。算下来至少需要666.7除以20约33个poller进程。而默认配置只有5个自然全都会被塞满。这里的“单次检查平均耗时”很多人会忽略。在局域网内agent检查通常10毫秒以内但在跨机房、启用了大量外部脚本检查的场景下500毫秒甚至1秒都很正常。如果你在模板里加了UserParameter脚本每次检查都要执行一段shell逻辑poller的吞吐立刻降一个数量级。所以计算时不要乐观地填10毫秒要用实际压测或zabbix_get的耗时来估。2.2 怎么确认队列堵在哪光看CPU不能证明“监控项太多”要去Zabbix前端看队列。菜单Reports里的Queue页面会列出延迟的监控项数量和最大延迟时间。如果延迟的监控项集中在某个模板或某几台主机上说明是局部配置问题如果遍地开花那就是整体容量不够。还可以用命令行直接查。Zabbix安装好后自带zabbix_get工具可以在server上对自身执行zabbix_get -s 127.0.0.1 -k zabbix[queue,60]返回值表示延迟超过60秒的监控项数量如果持续大于0且不断增大队列堆积无疑。另外zabbix[process,poller,avg,busy]这个键值可以看忙碌百分比。两者配合基本能锁定“poller供不应求”这个大方向。2.3 解决方案给poller减负而不是一味加人最容易想到的方法是把StartPollers调大。在zabbix_server.conf里把默认5改成20甚至50重启后poller进程数确实上去了。但如果数据库、网络和监控项本身没有优化加人只能暂时缓解甚至会让系统线程切换开销变大反而更慢。正确做法是三层递进。第一层调整采集频率。不是所有指标都需要30秒刷一次。CPU、内存可以1分钟磁盘利用率5分钟足够像登录用户数这种10分钟都行。把大多数非核心监控项从30秒改成300秒每秒检查数能直接降一个数量级。我在实际优化中经常靠这一步就把poller占用从100%拉到30%以下。第二层开启主动模式。Zabbix agent的主动检查不占用server的poller进程因为主动模式下agent自己按间隔把数据推给server的trapper进程处理。你只需要在agent配置里设置ServerActivezabbix.server.ip并把监控项类型改为“Zabbix agent主动式”。在大量主机需要采集相似指标的场景下主动模式能让poller压力几乎清零。第三层用Zabbix Proxy做分布式。把2000台主机拆给几个proxy由proxy去执行poller任务server只负责汇总数据。这个方案特别适合跨机房、跨网段的监控。虽然要额外搭建proxy主机但一劳永逸后续扩容也更弹性。3. 原因二数据库慢查询拖死poller这是最容易忽略的一环3.1 现象poller忙到飞起数据库也在“打摆子”第二类高发原因藏在数据库侧。很多人认为poller只是发请求、收结果CPU占用高就一定是采集逻辑的问题其实Zabbix的poller在执行完检查后需要把采集结果批量写入history表同时还要读取配置缓存。如果数据库响应慢poller进程就会卡在insert或select上看起来CPU占用高实则大部分时间都在等I/O。这里有个典型误区poller等待数据库时操作系统层面的进程状态可能显示为Duninterruptible sleep或SCPU使用率不一定爆表。但在Zabbix内部这个poller依然被判定为“busy”因为它手里的任务还没结束。于是你看到zabbix[process,poller,avg,busy]接近100%可top里poller的CPU只有20%。这种案例我遇到太多次第一反应差点把StartPollers又翻倍幸好先看了数据库。3.2 怎么定位是数据库的锅先看MySQL或PostgreSQL的慢查询日志。以MySQL为例SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 2;跑几分钟后去查看慢日志文件如果发现大量SQL集中在history表插入、trends表更新、housekeeper删除历史数据那基本就实锤了。另外还可以关注数据库连接数和负载SHOW GLOBAL STATUS LIKE Threads_connected; SHOW ENGINE INNODB STATUS;SHOW ENGINE INNODB STATUS结果里的History list length如果短期暴涨说明有大量未purge的历史事务通常是历史表太大或插入并发太高。3.3 解决方案给数据库“减脂增肌”Zabbix历史数据增长得飞快如果不做处理任何版本的数据库都扛不住。我在生产环境里做过的优化思路可以总结成四点。一是开启历史表自动分区。MySQL版本支持分区后Zabbix官方其实更推荐TimescaleDBPostgreSQL的扩展。如果你用的是PostgreSQL可以在Zabbix 6.0以上版本直接启用TimescaleDB它会把history表按时间自动分区并支持压缩和保留策略写入性能能提升数倍查询老数据也更快。如果是MySQL可以通过事件调度器定期创建分区但需要自己维护麻烦一些。二是合理设置历史和趋势的保留周期。很多人会把History保留90天其实没必要。History作为原始采样数据保留7到14天完全够排查问题长期趋势交给Trends表它按小时聚合数据量小得多。在Zabbix前端每个监控项的History和Trends存储周期可以单独设置批量改模板也方便。我的一般经验是History 7天、Trends 365天性能和审计需求都能兼顾。三是不要在业务高峰期跑Housekeeper。Zabbix用Housekeeper删除过期历史数据这是一个极其吃资源的过程尤其在数据量大的库上。默认会每1小时跑一次但你可以把维护周期调整到凌晨低峰期同时在数据库端配合按分区drop的方式清理历史表而不是让Housekeeper逐行delete。这个操作能显著降低锁竞争poller自然跟着喘过气来。四是优化数据库本身。innodb_buffer_pool_size要能覆盖大部分热点数据连接数不要设太小binlog可以适当精简。很多云数据库默认配置是“能用但很紧”一旦写入量上来就成瓶颈。把这些基础参数调大往往能带来意想不到的收益。4. 原因三网络抖动与主机超时poller被“拖死”4.1 现象不可达主机成功拖垮所有poller第三类原因最隐蔽也最让人抓狂。Zabbix的被动采集是同步模型server发一个请求给agent然后原地等待响应。这个等待有上限就是server配置里的Timeout参数。如果同时有很多主机因为宕机、网络故障、agent被卸载等原因处于不可达状态poller就会挨个尝试连它们每个都要等到超时才放弃。我经历过一次典型故障某次网络变更误伤了一个网段的100台主机Zabbix里的监控全部变成不可达。之前配置的Timeout15于是这15秒内所有poller进程都卡在这100台主机的连接上无法执行其他监控项。结果就是可用主机的数据延迟告警、poller进程忙到不行但真正干活的时间几乎没有。这种“看起来CPU占用高实际都在等”的情况非常容易被误判成监控项太多。4.2 定位方法队列和日志都能说明问题如果前端Queue里出现的全是“Unreachable”状态或者日志里刷connection timed out就要怀疑这类原因了。还可以做一个抽样测试zabbix_get -s 10.0.0.10 -k agent.ping -t 3如果命令卡住两秒以上甚至直接报错说明网络或agent响应有问题。再把问题主机集中到一个测试场景里用top观察poller进程你会看到它们全处于等I/O状态而CPU占用不高。这时候如果去看内部项zabbix[process,poller,busy]又会发现它显示极高让人非常迷惑。4.3 解决方案让poller别再“死等”第一个方法是调短超时。Timeout在zabbix_server.conf里很多人误以为设得越大越不容易误报实际上超时时间越长单个不可达主机占用poller的时间就越长。我建议内网监控控制在3到5秒跨机房可以放到10秒但不要超过15秒。配合UnreachableDelay45这个参数一旦主机第一次失败下次探测会在45秒后再尝试而不是每个周期都密集打。UnreachablePeriod也可以综合调整。第二个方法还是主动模式。主动模式下数据由agent主动推给serverserver只负责接收。如果某台主机的agent不可达受影响的只是它自己的数据不会让其他主机的poller陪葬。这也是我在高可用要求比较高的业务监控里越来越倾向把所有主机切到主动模式的原因。第三个方法是用Zabbix Proxy分层。每个proxy负责一个物理区域网络抖动被隔离在局部。server与proxy之间通常走稳定线路受agent网络波动的影响就小很多。即使某个区域网络炸了其他区域的poller依旧正常工作。第四个小技巧能填IP地址的主机尽量填IP别用DNS主机名。Zabbix server在采集前会做DNS解析解析失败或超时也是常见的隐性超时。改成IP后这一层等待直接消失。我在实际环境里就遇到过因为内部DNS解析偶尔慢导致poller周期性飙高的案例。5. 原因四配置缓存过小与配置重载“风暴”5.1 现象配置一变poller就抽风这类问题很怪异平时poller占用稳定在30%但只要一改模板、批量导入主机poller占用立马冲到100%过十几分钟又自己降下来。如果你遇到这种“脉冲式”飙升多半跟配置缓存和配置同步有关系。Zabbix server启动时会从数据库读取所有监控项配置并在内存中维护一份配置缓存。poller每次轮询时不是直接查数据库而是从这份缓存中取监控项定义。如果CacheSize设置得太小缓存放不下全量配置就会频繁做逐出和重载。每次重载都是一次全量内存操作poller访问时如果撞上缓存锁等待执行效率就会断崖式下降。更别提在前端批量改几百个监控项后数据库配置版本号一变server要触发整库配置缓存重建那段时间poller忙到爆炸几乎是必然的。5.2 怎么判断缓存是不是瓶颈可以看Zabbix内部监控项zabbix[cache,config,pfree]它表示配置缓存的空闲百分比。如果这个值长期低于20%说明CacheSize确实吃紧。还有一个简单方式直接观察zabbix_server日志如果出现类似“config cache is full”的提示那就没跑了赶紧调大配置缓存。我习惯把这些内部指标加到Zabbix server自己的监控模板里做一张趋势图。平时多看看既能提前发现内存池不足的苗头也能在故障时快速回看时间轴判断是不是某次配置变更触发的。5.3 解决方案缓存加大重载避峰在zabbix_server.conf里找到CacheSize默认值只有8M这个大小在生产环境真的是杯水车薪。监控项超过一两万个就该把CacheSize调到128M甚至更大。同理HistoryCacheSize也可能影响写入队列如果数据量很大建议一并调大比如设成64M。修改后必须重启zabbix_server否则不生效。配置重载方面尽量避开业务高峰。Zabbix的配置同步会在检测到配置版本变化后自动触发。如果你是通过API脚本批量上报、批量修改建议在代码里加一个限速比如每分钟最多修改200个监控项同时把批量操作放到凌晨。如果一定要在白天改尽量选择“只影响目标主机”的方式变更避免改一个模板连带着上千台主机一起重建配置缓存。Zabbix 7.0对配置同步逻辑做了优化但依然扛不住“配置风暴”。顺带提一句如果你正在用Zabbix 7.0做钉钉联动告警配置重载带来的抖动会直接引发告警风暴所以更要把这些基础参数提前调理好。另外配置缓存重载期间产生的高占用有时和大量外部脚本监控项有关它们会占用较长CPU时间。可以把这类脚本监控项单独拆到一个模板里错峰启用减少对核心poller的冲击。6. 原因五模板设计失控监控项“爆炸式增长”6.1 现象模板模板抄完就爆第五类原因最“脏活累活”也是最容易被忽略的长期隐患模板设计不合理导致监控项数量远超实际需要。很多人从网上搜到一个模板看指标挺全就直接导入绑定到几十上百台主机上。结果模板里可能有几十个监控项是特定硬件才有的大部分主机根本拿不到数据还有LLD低级别发现规则比如磁盘发现、网络发现在没有过滤条件的情况下每台主机都可能动态生成二三十个监控项。数量一旦翻倍poller的工作量自然翻倍。更糟的情况是同一个监控键在多个模板里重复主机一旦关联了多个模板就会产生大量重复监控项。每轮poller都去执行同样的命令拿到同样的数据白白烧CPU。还有一些脚本类监控项例如在agent的UserParameter里写了一个长耗时脚本脚本本身要执行3秒才能返回一个poller就会被它卡住3秒。这类监控项数量一多poller想不100%都难。6.2 怎么审查监控项是否失控进入前端的时候先看单台主机的“监控项”列表按状态筛选“已启用”再排序看数量。一台普通Linux服务器如果监控项超过300项多半就有模板污染嫌疑。再点开LLD规则看看发现出来的数据是不是有一堆用不上的磁盘、网卡或服务。用SQL去统计也很方便SELECT hostid, COUNT(*) AS item_count FROM items WHERE status 0 GROUP BY hostid ORDER BY item_count DESC LIMIT 20;注意不同Zabbix大版本的items表字段会有差异但只要正常安装这套查询思路基本可行。把排名靠前的主机拉出来对比就能发现是不是某些模板导致的。6.3 解决方案模板治理要当成代码库来管大家一定要明白模板是给人复用的但不是越多越好。我自己的模板管理原则可以总结成三条。第一最小化原则一个操作系统基础模板只保留CPU、内存、磁盘、网络和关键日志等核心指标其他通通放进业务模板。第二模板分层基础模板、中间件模板、业务应用模板严格区分主机只绑定它实际需要的层不搞“全家桶”。第三LLD过滤必须写比如网络发现规则里加过滤器只匹配^eth.*或^ens.*磁盘发现只匹配/data|/opt否则自动发现的结果会让你惊掉下巴。LLD过滤器具体怎么写以磁盘发现为例在发现规则的原型里可以设置Filter变量是{#FSNAME}正则表达式填^/data$|^/opt$然后选择“匹配”或“不匹配”。这样每台主机只生成真正需要的监控项poller压力能降一个量级。模板治理不是一次性工作建议每隔一个季度用上面那条SQL审计一次。发现僵尸监控项、重复键该禁用禁用该删就删。之前有个客户环境就是从这些“漏网之鱼”里清掉了近万条无效监控项之后poller占用直接掉了40%数据库负载也明显下降。7. 排查工具与避坑经验总结7.1 从现象到根因我惯用的5步排查流程遇到poller 100%我不会一上来就改配置。先按顺序走一遍能少走很多弯路。第一步用top按CPU排序确认是单个poller进程高还是整个zabbix_server都高同时看主机load判断是不是CPU密集型问题。第二步看Zabbix内部性能监控项。执行zabbix_get -s 127.0.0.1 -k zabbix[process,poller,avg,busy]和zabbix_get -s 127.0.0.1 -k zabbix[queue,60]。如果poller busy高且queue大进入第三步。第三步看数据库慢查询和当前连接数。有慢SQL就优先处理数据库问题没有慢SQL再看网络。第四步看Queue里是否堆满Unreachable状态或者日志里全是timeout。是的话检查网络链路、主机可达性优化超时参数。第五步查监控项数量和模板。翻前端主机监控项列表和LLD规则找出异常膨胀项按照第2和第6章的思路清理。这套流程看起来繁琐但实际执行下来多数案例在第三步、第四步就能定位。7.2 常用命令与参数速查表我把排查过程中高频用到的命令和参数整理成一张表方便贴在终端旁边目标命令或配置说明查看poller进程top -b -n 1 | grep zabbix看CPU占用和进程状态查看平均忙碌比例zabbix_get -s 127.0.0.1 -k zabbix[process,poller,avg,busy]大于90%说明poller忙查看队列积压zabbix_get -s 127.0.0.1 -k zabbix[queue,60]持续大于0需要关注配置缓存空闲率zabbix_get -s 127.0.0.1 -k zabbix[cache,config,pfree]小于20%需调大CacheSize测试目标主机响应zabbix_get -s host -k system.uptime -t 3卡住说明网络或agent慢数据库慢查询SET GLOBAL slow_query_logON; SET GLOBAL long_query_time2;按需开启记得关闭超时相关核心参数Timeout3,UnreachableDelay45,UnreachablePeriod10在zabbix_server.conf中调整缓存池参数CacheSize128M,HistoryCacheSize64M调大后必须重启server这张表里的命令在Zabbix 6.0/7.0上都能直接用区别只是版本对内部监控项的命名略有变化。7.3 我踩过的坑和最后一点建议写到这里分享几个我真实踩过的坑大家引以为戒。第一个坑一上来把StartPollers从5改成50。结果poller多了数据库连接数暴涨历史表写入锁冲突最终poller等待数据库的时间比之前更长。所以遇到poller 100%先看监控项数量和SQL再考虑加人。第二个坑Timeout设置成30秒。本意是让慢设备能有机会返回数据结果一次网络抖动导致几百台关机主机占满了全部poller所有在线设备的采集全部延迟30秒以上。后来我把内网超时统一调成3秒配合UnreachableDelay监控立刻清爽了。第三个坑从网上下载的“全功能模板”绑定后一个晚上生成了几十万条LLD监控项第二天Zabbix前端差点打不开。从那以后我给自己立了规矩外部模板只用来参考上线前必须把LLD过滤规则和监控项清单过一遍。最后再说一个小建议在Zabbix server上给自己配好关于poller忙等和队列积压的告警。我个人习惯是把zabbix[process,poller,avg,busy]大于85%持续5分钟作为一个告警条件把这个值连同zabbix[queue,60]一起画进仪表盘。因为poller 100%这种事往往不是今天突然爆发的前面一定有趋势。早发现早处理总比半夜被手机打爆强。希望这份避坑指南能帮你少走点弯路也欢迎你把自己遇到的奇奇怪怪的poller问题拿来交流。
返回列表