当前时间: 2026-08-17 18:12:09
分类:办公文件
评论(0)
十个顶层模块,拼出 Zabbix 源码全貌Zabbix 源码 90 讲 · Day 03
源码基线:Zabbix 7.0.28
Revision: 86f12eab509
假设你接到一个很小的需求:把 Zabbix Server 未显式配置时的 StartPollers 默认值从 5 调高,并同步配置样例。 第一次改源码的人很容易搜索到 conf/zabbix_server.conf: 于是他把这里StartPollers=5改成 10,重新编译,再启动一个没有显式设置 StartPollers 的 Server——Poller 数量仍然是 5。 这不是编译缓存,也不是配置没有刷新。conf/ 保存的是示例配置;真正的程序默认值在 src/zabbix_server/server.c 的 config_forks[] 中,参数解析表也在同一个入口文件里。搜到了同名参数,不等于找到了决定运行行为的位置。 Day 02 已经固定了版本坐标。今天要解决下一件事:面对一棵确定为 7.0.28 的源码树,第一步应该走进哪个区域? “十个模块”不是十个同构文件夹 标题里的“十个顶层模块”,更严谨地说,是源码定位时的十个职责区域。它们不一定都会编译成独立程序,也不一定只包含一个物理目录: configure.ac 与 m4/ 合并为构建检测区; build/ 与 bin/ 合并为 Windows/MinGW 构建区; 根目录的 Makefile.am 单独作为构建编排区; src/libs/、src/go/ 等仍属于 src/,不另行计数。 当前工作区中的 docs/wechat/ 是本系列文章和图片的保存位置,不属于 Zabbix 上游源码模块;.agents/ 等工作区元数据同样不计入产品源码。 图 1:十个区域按运行与数据、接口与交付、构建与平台分层;这是定位地图,不是运行时数据流图。 第一层:运行行为与数据结构 01 src/:程序真正运行的地方 src/ 不只是 Zabbix Server,也不全是 C 代码。它包含: src/zabbix_server/、src/zabbix_proxy/、src/zabbix_agent/ 等组件入口; src/zabbix_get/、src/zabbix_sender/、src/zabbix_js/ 等工具; src/libs/ 中按 zbx<领域> 命名的大量公共实现; src/go/ 中的 Agent 2、Web Service 和插件; src/zabbix_java/ 中的 Java Gateway。 入口文件通常负责参数解析、初始化和进程分派,真实业务能力经常继续下沉到 src/libs/。只在 src/zabbix_server/server.c 中搜索到底,很容易错过公共库里的实现。 根目录的 src/Makefile.am 也表明,实际进入构建的子目录会随 AGENT、SERVER、PROXY、AGENT2、WEBSERVICE 和 JAVA 等条件变化,并不是把 src/ 下所有内容无条件打进一个程序。 02 ui/:页面、API 与控制面 ui/ 是部署型 PHP 应用,包含 app/、include/、js/、widgets/、静态资源以及 Composer 依赖。页面、权限、JSON-RPC API、SCIM 和 Dashboard Widget 问题优先从这里开始。 但它不是每个监控值的实时传输路径。页面保存配置后,Server 还要从数据库同步到运行缓存;采集失败也不能只因为页面正常就排除后端问题。 03 database/:首次安装的数据库入口 database/ 按 MySQL、PostgreSQL、Oracle 和 SQLite 保存初始 schema.sql、数据文件和方言差异,还包含 TimescaleDB 与 Elasticsearch 相关内容。 它回答“全新数据库应是什么结构”,却不是所有数据库逻辑的总仓库。运行期 SQL 在 C/PHP 代码里,完整升级链还要查 src/libs/zbxdbupgrade/。因此,改字段不能只改一份 MySQL schema,更不能把当前 schema.sql 当作完整升级历史。 第二层:接口、样例与交付材料 04 include/:公共契约,不是主要实现 include/ 保存公共 C 类型、常量、宏、跨库接口、模块 API 和版本头,例如 version.h、module.h 与大量 zbx*.h。 看到函数声明时,下一步通常要回到 src/libs/ 或组件目录找实现。include/common/config.h 还是配置阶段的生成物,源码分析应同时注意它的模板和条件编译来源。 05 conf/:示例配置,不是唯一事实源 conf/ 包含 Server、Proxy、经典 Agent 的示例配置和 UserParameter 示例。它很适合确认参数名称、注释和写法,但不能单独证明: Agent 2、Web Service 或 UI 是否使用同一套配置入口。 这正是开头修改 StartPollers 失败的原因。 06 sass/:前端样式的源头 主题颜色、组件样式、图标与字体生成素材位于 sass/。根 Makefile.am 的 css 和 icons 目标会把生成结果写入或复制到 ui/assets/。 所以改页面逻辑去 ui/,改纯样式或图标先看 sass/;浏览器最终加载的则是生成后的前端资源。 07 misc/ + man/:部署和运维配套 misc/ 中有多发行版 init 脚本、SNMP trap 接入脚本和地图图片等素材;man/ 提供 Server、Proxy、Agent、Get、Sender 和 Web Service 的命令手册页。 这些内容对部署与使用很重要,却不是核心 daemon 逻辑的实现位置。历史 init 样例和 man page 也不能替代当前入口源码与配置解析代码的核验。 第三层:源码怎样变成产物 08 configure.ac + m4/:决定“能不能编” configure.ac 定义组件开关和配置总流程,m4/ 保存 MySQL、PostgreSQL、TLS、SNMP、LDAP、libcurl 等依赖检测宏。遇到依赖找不到、功能宏没有启用或平台能力判断错误时,先查这一层。 它们负责检测与开关,不负责列出每个目标的全部源文件;修改手写规则后,也不应只去改生成的 configure。 09 Makefile.am:决定“哪些源码进入目标” 根目录与各子目录的 Makefile.am 负责编排递归目录、目标、源文件和链接库。根文件中的几行已经说明,仓库目录图与编译依赖图不是同一张图: SUBDIRS = include src database man misc EXTRA_DIST = README.md bin build ui include conf sass ui/ 出现在 EXTRA_DIST 而不在递归 SUBDIRS 中,不代表它不属于产品,只表示它不走同一条 C/Automake 递归构建路径。新增 C 文件后真正需要更新的通常是相应 Makefile.am,而不是只改生成的 Makefile.in。 10 build/ + bin/:Windows 与 MinGW 路径 build/ 保存 Windows/MSVC、MinGW 的 Makefile、资源描述和平台配置;bin/ 当前主要包含 Windows 开发头文件,并不是一个放满 Linux 编译产物的通用目录。 所以,“Unix 构建缺依赖”和“Windows 工程没纳入源文件”虽然都表现为编译失败,进入的源码区域并不相同。 遇到问题,先做目录第一跳 图 2:根据责任域选择第一个目录,再沿声明、实现、调用者和构建关系继续深入。 这张路由图不是说一个问题只会涉及一个目录,而是先找最有可能产生事实的第一落点: 运行行为先进入 src/,再判断是组件入口、公共库还是 Go 组件; 页面和 API 进入 ui/,纯样式再转向 sass/; 初装表结构进入 database/,升级与运行期操作继续追到实现代码; 公共声明在 include/,实现通常回到 src/; 配置样例在 conf/,默认值、解析与校验必须核对组件源码; 编译问题先分清依赖检测、目标编排还是 Windows 构建路径。 先选责任域,可以减少搜索噪声;随后再全仓搜索符号,才不会把“搜索命中”误当成“答案命中”。 回放 StartPollers 需求 conf/zabbix_server.conf 只负责同步样例说明; Server 的内部默认值在 src/zabbix_server/server.c 的 config_forks[] 中; 同一文件的配置参数表把 StartPollers 映射到 ZBX_PROCESS_TYPE_POLLER; Proxy 有自己的示例配置和 src/zabbix_proxy/proxy.c,是否一起修改必须由需求明确,不能因为同名就自动扩散; 没有新增源文件时,不需要无故修改 Makefile.am;这个需求也不应牵连 ui/ 或 database/。 真正高效的源码阅读,不是搜得更多,而是知道每一次命中承担什么职责。 今天只需要记住五句话 第一,根目录不是平铺的文件仓库,而是一组职责不同的阅读区域。 第二,src/ 是运行实现的大本营,但入口文件和公共实现仍要分开看。 第三,database/、include/ 和 conf/ 分别偏向初装结构、公共契约和配置样例,不能替代运行实现。 第四,目录是否进入顶层 SUBDIRS,不等于它在产品中是否重要。 第五,先选责任域,再搜符号,最后沿调用链和构建关系深入。 留给读者的小练习 在当前源码中搜索一次 StartPollers,然后写下三行定位卡: 请分别解释 conf/zabbix_server.conf、src/zabbix_server/server.c 和 Proxy 对应文件承担什么职责,以及为什么 ui/、database/、Makefile.am 不是这个需求的第一跳。 下一篇预告 同一个 src/ 中已经出现 C、Go 和 Java,ui/ 又以 PHP、JavaScript 为主,这不是偶然拼接。 下一篇《C、Go、PHP、Java 为什么共存于同一仓库》,我们将解释各语言对应的组件职责、构建与部署边界,以及面对不同问题时应该选择哪套阅读入口。
上一篇从“个人助手”到“组织能力”:生成式 AI 在法务部的关键落点 | 全球法务 观察 · Vol.15
下一篇小助理给自己安排了一个 AI 小助理