资讯动态

Zabbix源码仓库核心目录结构解析:从根目录到排错实战

发布时间:2026/9/7 20:27:55 来源:尧图企业网站定制
聊到 Zabbix大多数人第一反应是装环境、配监控项、搞告警、调模板能把前端页面玩明白已经算老手。但真到踩坑的时候——比如 history syncer 进程利用率飙到 75% 以上、Server 启动贼慢、自定义监控项在预处理链里卡住、想给 Agent 写个私有插件——你就不得不打开源码仓库去看代码。Zabbix 仓库的核心代码目录结构就是一张绕不开的地图。这篇文章我不讲安装部署直接从源码根目录开始把 Zabbix 仓库的核心代码目录结构摊开讲一遍说清楚每个目录是干什么的、代码之间怎么调用、排错和二次开发时应该重点看哪里。适合刚接触 Zabbix 源码的运维、打算做深度定制的开发以及所有被 Zabbix 的诡异问题折磨过的人。我平时主要看 6.0 LTS 和 7.0 的分支这两代源码布局基本一致。仓库整体是典型的“C 核心 PHP 前端 数据库脚本 监控模板”四层结构核心部分用 C 写Agent 2 从 5.0 开始用 Go 重写前端保持 PHP。这种混合架构不是随手定的它会直接影响你排查问题和二次开发的方式。下面我从顶层目录开始一层层拆。1. 项目概述Zabbix源码仓库的整体布局1.1 仓库顶层目录速览直接打开 Zabbix 官方仓库的根目录你会看到下面这些一级目录和文件。我把它们按“跟自己关联度”分个级方便你按需看目录/文件作用使用频度src/C/Go 核心源码Server、Proxy、Agent、Java Gateway 都在这里极高include/C 语言头文件所有模块的对外结构体和函数声明高create/数据库建库脚本、初始化数据、升级补丁高ui/Web 前端 PHP 代码登录后的所有页面高conf/各组件默认配置文件模板高templates/官方监控模板 XML 文件中misc/辅助脚本、SNMP Trap 处理、示例告警脚本等中sass/前端 SCSS 样式源文件低tests/单元测试和集成测试中docker/Docker 镜像构建相关文件低.github/GitHub Actions 的 CI 配置低man/命令行手册页低根目录还有几个构建相关文件比如configure.ac、Makefile.am、CMakeLists.txt和bootstrap.sh。这些是编译安装的入口如果你编译过 Zabbix应该见过./configure --enable-server --with-mysql这类命令configure.ac就是生成configure脚本的源头。1.2 为什么源码要这样分层很多人第一次逛 Zabbix 仓库会觉得乱因为 C 代码、SQL 脚本、PHP 页面、XML 模板混在一起不像一些纯后端项目那样只在src/里打转。但如果你真正运行过这套系统就会理解它的分层逻辑。Zabbix Server 本体是一个长时间运行的守护进程性能敏感的部分必须用 C 写所以核心逻辑集中在src/数据模型跨了 MySQL、PostgreSQL、Oracle、SQLite 多种数据库于是建表和升级脚本被单独拎到create/前端是给人类操作用的迭代快、模块多用 PHP 放在ui/里开发和发布都独立监控模板本质是配置数据用 XML 格式放在templates/方便用户直接导入。这个分层还有一个好处当你只需要改前端逻辑时完全不用碰 C 代码和数据库脚本当你需要调优采集性能时也不会被 PHP 代码干扰。换句话说Zabbix 的目录结构从根上就是按“进程边界、数据边界、交互边界”来切的。理解了这一点后面所有细节都能串起来。2. 核心代码目录拆解src/ 与 include/2.1 src/ 下的进程实体src/是 Zabbix 仓库最核心的目录里面不是一个大而全的 main而是按进程拆成了多个子目录子目录对应组件语言src/zabbix_server/Zabbix Server 主进程Csrc/zabbix_proxy/Zabbix Proxy 代理进程Csrc/zabbix_agent/老版 AgentAgent 1Csrc/go/新版 Agent 2 以及各类 Go 插件Gosrc/zabbix_get/命令行取数调试工具Csrc/zabbix_sender/命令行主动上报工具Csrc/zabbix_java/Java Gateway用来监控 JMX 应用Java如果你装过 Zabbix肯定知道zabbix_server、zabbix_proxy、zabbix_agent2这些二进制它们对应的源码入口基本就落在这几个子目录里。这里有一个非常容易踩的坑Agent 1 和 Agent 2 不是同一个代码仓库里的两个版本而是完全不同的实现。Agent 1 是纯 C 写的逻辑简单、依赖少Agent 2 从 5.0 开始用 Go 写天然支持插件化像 Redis、MySQL、PostgreSQL、Docker、Modbus 这些监控项都是通过src/go/plugins/下面的插件实现的。所以在源码里查 Agent 问题先分清楚你用的是哪个 Agent再去对应目录找不然会绕远路。2.2 zabbix_server 里的 worker 与代码文件Zabbix Server 不是单线程跑到底它是经典的多进程架构。zabbix_server.conf里的StartPollers、StartTrappers、StartDiscoverers、StartPreprocessors这些参数控制的就是各类 worker 进程的数量。在src/zabbix_server/下你能看到和这些 worker 一一对应的源码文件poller.c数据采集 poller负责主动去采集 Agent、SNMP、IPMI 等指标httppoller.cHTTP Agent 类型的采集也负责 Web 场景监控trapper.c接收 Agent 主动上报的数据也接收zabbix_sender发来的数据pinger.cICMP Ping 类型的采集配合 fping 使用discoverer.c网络自动发现lld.c低层发现LLD的处理逻辑很多模板的动态发现都走这里preprocessor.c预处理 worker负责 JSONPath、正则替换、PromQL 计算等预处理链housekeeper.c清理历史数据、过期事件escalator.c告警升级动作monitor.cServer 自监控也就是你看到 “history syncer over 75%” 这类内部监控项的来源vmware.cVMware 虚拟机数据收集。看这些文件名再对照zabbix_server.conf里的启动参数你基本就能画出 Server 内部的工作流poller 把采到的数据写进共享内存各 worker 之间通过共享内存和信号量通信然后 history syncer 把缓存里的历史数据批量刷进数据库configuration syncer 负责把数据库配置同步到内存缓存。这个架构还有一个特点是“集中式调度 分布式执行”。Server 进程本身不直接跑所有逻辑而是通过管理进程拉起和监控这些 worker 的数量、健康状况。这也是为什么当你卡在某个具体功能时直接去搜对应的.c文件通常比在server.c里大海捞针高效得多。2.3 include/ 头文件与构建脚本include/目录放的是 C 语言头文件命名和src/的库模块基本一一对应。比如include/zbxjson.h、include/zbxalgo.h、include/zbxdb.h、include/zbxmodule.h。如果你想开发一个 loadable module动态加载模块include/zbxmodule.h就是你最先要看的文件里面定义了模块初始化、采集函数、清理函数等 API。构建脚本方面老版本用 autotools新版本逐步在往 CMake 迁移。源码根目录的configure.ac和Makefile.am是 autotools 的核心CMakeLists.txt是 CMake 的入口。编译时会根据--enable-server、--enable-agent2、--enable-proxy、--with-mysql、--with-pgsql等参数裁剪功能模块。如果你是在内外网隔离环境做离线部署源码仓库的构建脚本就格外重要。因为离线编译不能依赖在线下载依赖包你得提前准备本地 yum/apt 源或者预先编译好二进制包。我建议离线部署时先把configure.ac里关于依赖库的hint参数看清楚比如--with-mysql会去检查mysql_config路径--with-libpthread、--with-libcurl同理。没有哪个目录能替代你提前把依赖列表核对的功夫。3. 库文件层src/libs/ 里的核心模块3.1 核心库清单与职责src/libs/是 Zabbix 源码里最精华的部分也是很多人忽略的部分。Server、Proxy、Agent 不是各自把功能写死的而是把通用逻辑抽成了静态库供不同进程复用。下面是几个必须认识的库库目录职责应用场景zbxalgo基础算法库哈希表、AVL 树、二叉堆、链表、排序配置缓存、LLD 数据处理zbxjsonJSON 解析和生成JSON 监控项、JDBC 监控项、前端 APIzbxcommsTCP/TLS 通信封装Server 与 Agent、Proxy 与 Server 之间通信zbxconf配置文件解析读取zabbix_server.conf、zabbix_agent2.confzbxdb数据库统一访问层支持 MySQL、PostgreSQL、Oracle、SQLite 的底层封装zbxdbcache配置缓存逻辑把数据库的配置加载到共享内存zbxhistory历史数据存储抽象历史数据写入和查询的分发层zbxeval表达式求值触发器表达式、宏函数计算zbxpreproc预处理链实现JSONPath、PromQL、正则替换等zbxprometheusPrometheus 协议采集直接抓取 Prometheus 暴露的指标zbxicmppingICMP Ping 封装Ping 监控项zbxipcservice进程间通信Server 内部各 worker 之间的消息传递zbxshmem共享内存封装配置缓存、历史缓存、趋势缓存实际存储zbxsys系统信息采集CPU、内存、磁盘、网络等基础数据看到zbxprometheus很多人会问“Zabbix 不是和 Prometheus 竞争吗怎么还支持 Prometheus”答案就在这个库目录里。Zabbix 通过zbxprometheus直接拉取 Prometheus 格式的指标相当于把 Prometheus 的 exporter 纳入自己的采集体系。它和 Prometheus 核心的区别在于Zabbix 是“一个中心化 Server 数据库存储管理”Prometheus 是“拉取 本地时序存储 查询引擎”。源码层面的体现就是zbxprometheus只负责指标解析而数据存储和告警管理还是走 Zabbix 自己的链路。3.2 配置缓存与共享内存zbxdbcache zbxshmemZabbix Server 启动时不会每次都去数据库里查一个 item 应该怎么采集。相反它会启动一个“配置同步器”把items、triggers、hosts、actions这些数据加载到内存里形成一份配置快照。这份快照就存在zbxshmem管理的共享内存里而“怎么从数据库表映射到内存结构”的逻辑就在zbxdbcache里。这就是为什么zabbix_server.conf里的CacheSize参数这么关键。如果你有上万台设备、几十万个监控项默认的几 MB 配置缓存很容易被撑爆导致 config sync 反复重建。以前我遇到过一次 Server 周期性 CPU 飙升最后定位到就是配置缓存满了configuration syncer一直在做全量 rebuild。改大CacheSize后立刻恢复正常。zbxdbcache的设计也解释了为什么某些配置修改需要“等待 10 秒甚至更久才生效”因为配置不是即时写到内存的而是按刷新间隔同步的。看到源码里CONFIG_CONFIG_CACHE_UPDATE这种宏你就明白改动从“数据库”到“内存”是异步的。3.3 一次采集数据的完整代码路径把src/libs/的模块串起来一次标准的数据采集链路大概是这样zabbix server的 poller 根据配置缓存向目标 Agent 发起请求网络传输走zbxcomms协议解析在src/libs/zbxprotocol或对应的 agent 协议处理Agent 端采集系统数据走zbxsys第三方应用数据走插件或自定义脚本返回的数据回到 Server 端先经过zbxpreproc的预处理链然后由zbxeval去计算触发器表达式数值进入历史缓存shared memory 管理后台的 history syncer 取走并调用zbxdb的写入接口落库如果配置了趋势存储另一个线程通过zbxtrends同步趋势数据。在这个链路里任何一个环节慢了最终都会体现为“采集延迟”或“history syncer 利用率高”。我在实际排查时不是从 UI 菜单看报告而是从monitor.c产生的内部监控项里找数据比如zabbix[process,history_syncer,avg]再顺着代码去找对应的缓存和 DB 写入线程。4. 数据库脚本目录create/ 与升级机制4.1 支持的数据库与目录差异Zabbix 支持多种数据库但这个支持不是写一套 SQL 到处跑而是在create/下分目录维护了不同数据库的方言create/mysql/MySQL/MariaDB 脚本create/postgresql/PostgreSQL 脚本create/oracle/Oracle 脚本create/sqlite3/SQLite 脚本主要给 Proxy 和轻量场景create/timescaledb/PostgreSQL TimescaleDB 时序扩展的脚本。每种数据库目录下都有几个核心 SQL 文件文件作用schema.sql建表语句全部业务表结构都在这里data.sql初始的权限、用户、媒体类型、默认配置等基础数据images.sql监控页面的图标数据patches/或对应版本目录各版本之间的表结构升级补丁如果你要研究 Zabbix 的数据模型直接读create/mysql/schema.sql比看文档更快。比如hosts表、items表、history系列表、trends表、events、alerts、escalations所有关系一目了然。我遇到过不少人对“history”和“trends”的区别搞不清看 schema 就懂了history存的是带时间戳的原始采集值量极大trends存的是聚合统计每分钟最大值、最小值、平均值、计数量小很多。这也是为什么 Zabbix 建议把 history 保留短、trends 保留长。4.2 升级补丁机制Zabbix 的版本升级不是“删库重来”而是靠patches/目录下的补丁逐个版本叠加。数据库里有一张dbversion表记录了当前 schema 的版本号Server 启动时会根据当前版本号找到对应的补丁脚本自动执行或者管理员也可以手动执行databaseupgrade。从源码角度看create/目录里按版本目录组织的补丁文件就是一张“版本演进地图”。如果你被老版本升级到新版本的问题卡住比如某张表字段对不上可以先去看 patches 里有没有针对该版本的修改语句很多时候能直接找到根因。这比在问答社区里搜“unknown column”更靠谱因为补丁脚本就是标准答案。4.3 分区表、TimescaleDB 与历史数据落库大型环境中 history 数据量巨大单靠普通表很容易把数据库压垮。Zabbix 的应对方式有两类一类是官方在create/timescaledb/下提供的 TimescaleDB 扩展把历史表改成超表hyper table自动按时间分区另一类是自建分区通常通过history表的按时间分区脚本实现。前者在 6.0/7.0 上支持得越来越成熟后者在老项目中比较常见。在源码结构里zbxhistory模块会根据数据库类型决定写哪张历史表。你如果改过history表的表名或加了分表需要同步修改这个模块的 SQL 映射否则数据会写不进去。很多“history syncer 一直 75% 以上”的案例最终都指向数据库端写入慢而数据库端的问题往往是分区策略不对、索引缺失或者历史表膨胀。5. 前端代码目录ui/ 的结构与二次开发入口5.1 PHP MVC 布局Zabbix 的前端放在ui/下用 PHP 实现整体是 MVC 思路。打开ui/你会看到几个关键目录目录作用ui/app/controllers/控制器处理用户请求、组织页面逻辑ui/app/models/模型和数据库交互ui/app/views/视图渲染 HTML 页面ui/include/公共函数库、类库、数据库操作封装ui/conf/前端配置文件zabbix.conf.phpui/local/本地化翻译文件ui/modules/可扩展模块目录ui/vendor/Composer 管理的第三方依赖现代 Zabbix 前端的 URL 基本都是zabbix.php?actionxxx这种形式每个 action 对应一个控制器。比如你想知道“主机列表”页面在哪就去ui/app/controllers/下找 CControllerHostList 这个类。视图则在ui/app/views/下找host.list.php。这种“action 路由 Controller View”的结构和大多数 PHP MVC 框架一致改个页面思路很快。5.2 include/、conf/、local/、vendor/ 等关键目录ui/include/是前端最常改的地方之一。里面的classes/目录放了很多核心类比如图表、地图、屏幕、认证、API 都在这附近。你如果要做前端功能扩展不用从零写先看看include/classes/里有没有现成的基类通常能省不少事。ui/conf/zabbix.conf.php就是前端的配置文件它由安装向导生成。源码里一般有个zabbix.conf.php.example模板。部署多个前端节点时这台服务器上的配置和数据库配置都在这个文件里和 C 端的zabbix_server.conf是分开的。我见过不少人把前端连不上数据库的问题当成 Server 配置问题结果两边DBHost、DBName不吻合前端连不上、后台却在正常采集。ui/vendor/里是 Composer 安装的第三方库官方升级时一般会锁定版本。如果你要改前端渲染逻辑优先在ui/app/views和ui/include/classes里做不要动vendor/否则升级会被覆盖。这算是我踩过几次坑后的血泪教训。5.3 官方模板 templates/ 和自定义模块 ui/modulestemplates/目录存放官方所有监控模板 XML比如template_linux_by_zabbix_agent2.xml、template_mysql_by_zabbix_agent2.xml。这些模板可以直接导入前端也可以作为二次开发的起点。很多团队的做法是复制官方模板再改而不是从零创建因为官方模板里的 item、trigger、graph 已经充分考虑了最佳实践。如果你想做更规范的前端扩展Zabbix 从 5.x 开始支持模块机制入口就是ui/modules/。一个模块可以注册自己的菜单、页面、API甚至覆盖部分原生行为。它比直接改控制器更干净升级时不容易被覆盖。官方在源码里保留了模块示例我在写自定义页面时基本是先复制模块目录再改命名空间。6. 实战场景从目录结构反推排错与二次开发6.1 history syncer 进程利用率超过 75% 的排查思路这个告警现在非常常见而且从名字就能看出来它来自 Server 自监控。出现这个告警说明历史数据写入数据库的速度跟不上采集速度积压的历史缓存越来越多。我的一般排查路径是先看zabbix[history_cache]相关内部监控项确认是否有大量积压再去数据库端查写入性能重点看history表对应的大表有没有分区、慢查询是否集中在history_uint、history_str等表回到源码确认 history syncer 的行为zbxhistory模块会在内存里攒一批数据后批量 insert而不是一条一条写。如果数据库单条 insert 太慢批量 flush 也会被拖死调整zabbix_server.conf里的StartHistoryPollers不是StartHistorySTime准确点说调大HistoryCacheSize只能缓解积压真正要解决的是数据库写入瓶颈。很多时候把历史数据的保留天数缩短、开启分区索引比盲目调大 cache 更有效。官方模板会按设备规模给出参考参数但要结合自己的库表大小去调整。6.2 Server 启动慢、前端页面转圈时的定位方法Zabbix Server 启动慢最典型的原因是配置缓存加载太慢尤其是监控项特别多的环境。源码里dbconfig.c或对应配置同步模块负责把数据库配置全量拉取到内存这一步耗时取决于items、triggers等表的数据量以及数据库连接质量。你可以在 Server 日志里看到 “syncing configuration data” 这类阶段打印配合-R diaginfo这类运行时诊断可以拿到更多信息。前端页面转圈则要区分是“页面渲染慢”还是“后端接口慢”。前端依赖 PHP API 去查数据库如果数据库慢查询多页面自然卡。你可以从ui/app/controllers/里找到对应 action然后从控制器里的 SQL 去数据库里手动执行看执行计划。很多前端的慢不是 PHP 代码写的差而是缺少索引或者一次查出太多行。6.3 二次开发该从哪里下手如果你只是给 Agent 加一个自定义监控项先别急着改 C 代码。Zabbix 提供 UserParameter 和 loadable module 两种官方扩展点。前者零成本后者性能好。要看清楚 loadable module 的规范include/zbxmodule.h是核心官方仓库里也保留了模块示例。如果你要改 Agent 2对应的逻辑在src/go/下。Agent 2 的插件接口对 Go 开发者很友好写一个插件大致就是实现Export、Collect这类方法然后在src/go/plugins/下加一个目录。这个目录安排非常清爽比在 C 代码里改采集函数要省心得多。但是改完之后要注意编译流程Agent 2 的 Go 模块依赖可能是固定的编译环境需要联网拉取 Go modules离线环境下要么提前go mod vendor要么提前准备本地模块缓存。如果目标是做前端定制我建议顺序是先看ui/app/controllers/和ui/app/views/了解页面流再看ui/include/classes/复用已有类最后用ui/modules做独立扩展。尽量不要改核心目录不然升级的时候会非常痛苦。我个人在实际操作中的体会是Zabbix 源码仓库虽然大但不是没有规律。先读create/里的 schema 把数据模型理清再看src/libs/zbxdbcache和src/libs/zbxhistory理解数据是怎么缓存和落库的然后回src/zabbix_server看各种 worker 怎么启动和调度最后看ui/的路由和控制器。按这个顺序过一遍你在监控界面看到的很多参数比如 CacheSize、HistoryCacheSize、StartPollers、预处理链都能在源码里找到对应的宿体。希望这篇目录结构拆解能帮你少走我当年走过的弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价