当前位置: 首页 > news >正文

[Nagios Core] 事件调度 | 检查执行 | 插件与进程

第五章:事件调度

欢迎回到Nagios Core!

在上一章第四章:配置加载中,我们了解了Nagios如何读取配置文件以知晓需要监控的对象,比如我们的朋友"Web Server 1"。此时Nagios内存中已构建完整的基础设施拓扑图。

仅仅知道存在什么是不够的。Nagios需要主动执行操作,而且必须在正确的时间执行。何时检查"Web Server 1"的可达性?何时检查HTTP服务?何时保存当前状态?

这就是事件调度的用武之地。

什么是事件调度?

将Nagios Core引擎视为拥有主日历和闹钟的系统。事件调度就是管理这个日历的机制,负责跟踪所有未来需要执行的任务并在预定时间触发它们。

本质上,Nagios是一个高度组织化的事件调度器。它维护着未来定时事件的队列,这些事件代表着Nagios需要执行的所有操作

  • 对主机和服务执行主动检查
  • 在问题发生或解决时发送通知
  • 执行状态保存、日志轮转等维护任务
  • 检查被动检查结果的"新鲜度"
  • 执行计划停机开始/结束任务
  • 以及其他更多功能!

正是这种调度机制驱动着Nagios的所有活动。

用例:为"Web Server 1"调度检查

基于前几章加载的配置,Nagios已知晓"Web Server 1"及其HTTP和Ping服务,包括它们的check_interval(如每5分钟检查)和check_period(如24x7)。

事件调度组件利用这些信息向日历添加事件:

  1. 立即(或启动/重载后不久)计算"Web Server 1"及其服务的首次检查时间
  2. 将"Web Server 1主机检查"和"Web Server 1: HTTP服务检查"、"Web Server 1: Ping服务检查"事件加入队列
  3. 当检查事件到期时触发执行
  4. 检查运行并处理结果后(后续章节详述),调度系统计算下次检查时间(如5分钟后)并新增检查事件

这种调度、触发和重新调度的持续循环确保按配置定期检查所有对象。

核心概念:事件队列与主循环

事件调度围绕两个核心理念构建:

  1. 事件队列存储所有未来事件的中心数据结构,按执行时间排序。Nagios使用高效优先队列实现(内部称squeue),专为快速事件添加和检索优化
  2. 主执行循环:Nagios引擎持续运行的循环,每个周期中:
    • 查看队列首部事件
    • 等待至事件到期
    • 取出事件并执行关联任务
    • 循环事件计算下次执行时间并重新入队

幕后工作机制

以下是Nagios完成配置加载后的核心调度流程:

在这里插入图片描述

  1. 初始化(init_timing_loop):为所有配置对象计算初始next_check时间,创建timed_event对象入队
  2. 主循环(event_execution_loop):进入无限循环
  3. 查看(peek):获取队列首部事件时间
  4. 等待/轮询:使用iobroker_poll系统调用休眠至事件到期或外部输入到达
  5. 取出处理(pop & handle):取出事件并通过handle_timed_event处理
  6. 事件特定逻辑:根据事件类型调用对应函数(如run_scheduled_service_check
  7. 重新调度:对循环事件计算下次执行时间并重新入队
  8. 循环往复:持续处理后续事件

(FIFO)

代码解析

核心调度逻辑位于base/events.c及相关头文件:

// 简化版timed_event结构(来自include/nagios.h)
typedef struct timed_event_struct {int     event_type;      // 事件类型time_t  run_time;        // Unix时间戳void    *event_data;     // 关联数据指针int     recurring;       // 是否循环unsigned long event_interval; // 循环间隔// 其他字段...
} timed_event;// 全局事件队列
extern squeue_t *nagios_squeue;

事件调度关键函数:

// 创建新事件并入队(base/events.c简化版)
timed_event *schedule_new_event(int event_type, ...) {timed_event *new_event = calloc(1, sizeof(timed_event));// 设置事件字段...add_event(nagios_squeue, new_event);return new_event;
}// 主事件循环(base/events.c简化版)
int event_execution_loop(void) {while(1) {// 获取下个事件时间temp_event = squeue_peek(nagios_squeue);// 计算等待时间poll_time_ms = ...;// 等待事件或外部输入iobroker_poll(nagios_iobs, poll_time_ms);// 处理到期事件if (should_run_event(temp_event)) {handle_timed_event(temp_event);remove_event(nagios_squeue, temp_event);// 重新调度循环事件if(temp_event->recurring) reschedule_event(nagios_squeue, temp_event);}}
}// 事件处理器(base/events.c简化版)
int handle_timed_event(timed_event *event) {switch(event->event_type) {case EVENT_SERVICE_CHECK:run_scheduled_service_check(...);break;// 其他事件类型处理...}
}

实现了一个事件调度系统的核心功能,用于管理和执行定时或周期性任务(如服务检查)。

系统通过事件队列管理待执行任务,主循环持续检查while(1){}并执行到期事件

事件创建与入队

schedule_new_event()函数负责创建新事件:

  • 使用calloc动态分配内存,创建timed_event结构体
  • 初始化事件类型等参数(代码中...表示省略的细节)
  • 通过add_event()将事件插入优先级队列nagios_squeue
  • 返回创建的事件指针,供后续操作使用

主事件循环

event_execution_loop()是持续运行的核心循环: while(1){}

  • squeue_peek()查看队列中下一个即将触发的事件(不取出)
  • 计算该事件的剩余等待时间poll_time_ms
  • iobroker_poll()同时监控外部输入和等待事件到期
  • should_run_event()判断事件是否到期,到期则调用handle_timed_event()执行
  • 执行后通过remove_event()移出队列,若是周期性事件则用reschedule_event()重新入队

事件处理逻辑

handle_timed_event()根据事件类型执行具体操作:

  • EVENT_SERVICE_CHECK类型触发run_scheduled_service_check()
  • 其他事件类型通过类似switch-case分支处理
  • 实际系统中会包含更多事件类型(代码中//其他事件类型处理...示意)

实现效果

通过事件调度系统,Nagios能够:

  1. 将"Web Server 1"的配置转换为可执行的定时事件
  2. 通过主循环持续监控和执行检查
  3. 按配置间隔自动重新调度后续检查
  4. 保持对所有监控资源的持续监测

主循环机制

  • 主循环机制是程序不断重复执行的核心流程,用于处理输入、更新状态和输出结果,直到满足退出条件。

  • eg. int event_execution_loop(void) { while(1) {}}:无限循环查询,通过break跳出

  • 例如游戏循环会持续检测玩家操作、计算画面变化并刷新显示。

总结

事件调度是Nagios Core引擎的核心驱动力,通过精心设计的时间队列管理和主循环机制,确保监控配置的主动实施。下一章我们将探讨检查执行的具体过程

第六章:检查执行


第六章:检查执行

在上一章第五章:事件调度中,我们了解到Nagios如何利用主日历来决定事件发生的时间——包括何时需要检查我们的朋友"Web Server 1"是否仍然可达或HTTP服务是否正常运作。

现在Nagios已经知道监控什么(对象定义),知道如何查找这些定义(配置加载),也知道*何时执行检查*(事件调度)。

但它究竟如何执行检查?如何发送ping请求或尝试连接Web服务器?

这就是检查执行系统的职责所在。

什么是检查执行?

检查执行系统是Nagios Core中负责实际执行已定义监控任务的核心组件。它就像行动执行者。当调度器发出"立即检查Web Server 1的HTTP服务!"指令时,检查执行系统接收命令并付诸实施。

关键在于,Nagios Core本身并不包含执行ping操作、检查网页或查看磁盘空间的代码。

相反,它依赖于称为插件外部程序(通常是小型脚本或可执行文件)。检查执行系统的主要职责包括:

  1. 根据对象定义确定特定检查所需的正确插件命令和参数
  2. 运行这个外部插件程序
  3. 捕获插件执行结果

我们可以将其理解为:

Nagios将特定工具(插件)交给临时工作进程,并指示"去检查这个目标并反馈结果!"

用例分析:检查"Web Server 1: HTTP"

让我们追踪当事件调度系统触发"Web Server 1"HTTP服务检查时发生的事件链:

  1. 调度器触发"Web Server 1: HTTP"服务检查的事件处理器
  2. 处理器查找该服务的配置信息(来自已加载的对象定义)。找到我们在第三章:对象定义中定义的check_command指令,即check_http。完整命令行可能类似/usr/local/nagios/libexec/check_http -H 192.168.1.100
  3. 检查执行系统准备执行该命令
  4. 在运行Nagios Core的系统上启动/usr/local/nagios/libexec/check_http作为独立进程
  5. 系统等待check_http插件完成
  6. 插件运行时,检查执行系统捕获其标准输出(如"HTTP OK: HTTP/1.1 200 OK - 154 bytes in 0.052 second performance data…")和标准错误(如果有)
  7. 插件退出时,检查执行系统捕获退出代码。该代码遵循Nagios插件标准:
    • 0: 正常
    • 1: 警告
    • 2: 严重
    • 3: 未知
  8. 收集的输出、标准错误和退出代码组合成"检查结果"
  9. 该结果传回Nagios主引擎进行下一阶段处理:检查结果处理

这个循环过程会为调度引擎安排的所有活动主机和服务检查重复执行。

⭕核心:插件与进程执行

检查执行系统的核心思想包括:

  • 插件:实际执行监控的工作单元。它们是独立的程序BashPythonPerl脚本或编译二进制文件),接收参数(如主机IP、端口号、阈值)并执行特定检查。其输出和退出代码是向Nagios反馈的标准方式。Nagios Core自带标准插件集(nagios-plugins),但支持用户自定义开发
  • 外部进程执行:出于安全性和稳定性考虑,Nagios从不在主进程内部运行插件。而是通过系统调用将每个插件作为独立子进程启动。这意味着即使插件崩溃或挂起,也不会影响整个Nagios引擎
  • 命令构造:Nagios从配置中获取check_command和定义参数(如第三章:对象定义中check_ping!100,20%!500,60%),扩展任何宏(如$HOSTNAME$$SERVICESTATE$),构建最终执行的命令行字符串
  • 结果捕获:Nagios需要通过管道连接插件的标准输出和标准错误流来读取打印内容,同时使用系统调用(waitpid)获取插件退出状态(linux下一切皆文件【Linux】重定向 | 为什么说”一切皆文件?“)

频繁运行大量外部进程可能消耗系统资源。–池化解决

Nagios Core采用专用系统高效管理这些插件执行,通常通过准备就绪的工作进程池(Workers)来启动检查。

⭕幕后工作原理

当事件处理器决定运行检查时(如第五章:事件调度中提到的handle_timed_event函数,特别是调用run_scheduled_service_checkrun_scheduled_host_check的部分),检查执行的简化流程如下:

在这里插入图片描述

  1. 事件(如计划检查或按需检查)通知主引擎需要执行特定主机/服务检查
  2. 引擎查找相关对象定义及其关联的check_command
  3. 准备需要执行的完整命令行字符串,包括扩展宏
  4. 主引擎不直接执行命令,而是通过消息或请求将任务分派给工作进程(如base/nagios.cinclude/workers.h代码片段所示,详细内容将在下一章讨论)。该请求包含命令行检查超时被检主机/服务信息
  5. 工作进程接收任务请求
  6. 工作进程使用底层系统调用(forkexecpipewaitpid启动指定插件命令作为自身子进程。建立管道捕获插件的标准输出和标准错误
  7. 插件程序运行,执行检查(如连接目标主机/端口),向标准输出打印结果,并以适当状态码退出
  8. 工作进程读取插件写入标准输出和标准错误管道的内容。同时等待插件进程结束并获取退出状态
  9. 工作进程将收集的输出、标准错误、退出状态和计时信息打包成结构化结果
  10. 工作进程通过进程间通信通道(如套接字)将结构化检查结果返回主引擎
  11. 主引擎接收结果并传递给检查结果处理系统更新状态、记录事件并可能发送通知

这种架构(特别是工作进程机制)使Nagios能够(多进程)并发运行成百上千次检查,同时保持主调度和事件处理循环的持续运行

代码

Nagios Core的实际底层进程执行逻辑主要依赖runcmd库(lib/runcmd.hlib/runcmd.c),该库提供安全执行外部命令并捕获输出和退出状态的方法

但在标准Nagios Core设置中,主引擎不直接调用runcmd执行检查,而是通过工作进程系统在内部使用runcmd

查看主引擎用于向工作进程请求检查执行任务的接口(定义于include/workers.h):

// 摘自 include/workers.h(简化版)// 保存工作进程执行任务后返回结果的结构体
typedef struct wproc_result {unsigned int job_id;unsigned int type;       // 任务类型(WPJOB_CHECK、WPJOB_NOTIFY等)char *command;           // 实际执行的命令行char *outstd;            // 命令的标准输出char *outerr;            // 命令的标准错误int wait_status;         // waitpid的原始状态(包含退出码)int exited_ok;           // 进程是否正常退出int early_timeout;       // 是否提前超时// ... 其他时间和状态字段 ...
} wproc_result;// 主引擎请求工作进程执行检查任务的函数
// 注意:这是主引擎概念上的简化函数调用
// 实际接口使用消息队列或套接字
// 摘自 include/workers.h(概念简化版)
extern int wproc_run_check(check_result *cr, char *cmd, nagios_macros *mac);
// 该函数向工作进程发送执行'cmd'命令的请求
// 'cr'是用于存储结果指针的结构体,'mac'是环境宏

wproc_result结构体是关键——它是工作进程执行命令后返回给主引擎的信息包,包含所有必要数据:执行的命令、插件标准输出(outstd)、标准错误(outerr)和退出状态(源自wait_status)。

概念上的wproc_run_check(或run_scheduled_*_check使用的类似内部函数)接收检查细节,并将其发送到工作系统进行异步执行。

工作进程内部,实际运行插件命令和捕获输出的代码使用runcmd库。

runcmd_open函数是启动命令的起点:

// 摘自 lib/runcmd.h(简化版)
/*** 从命令行字符串启动命令* @param[in] cmd 要执行的命令* @param[out] pfd 子进程stdout文件描述符* @param[out] pfderr 子进程stderr文件描述符* // ... 其他参数 ...* @return 子进程pid,或负错误码*/
extern int runcmd_open(const char *cmd, int *pfd, int *pfderr, /* ... */);/*** 等待命令退出并获取状态* @param[in] pid runcmd_open启动的子进程ID* @param[out] status 来自waitpid()的等待状态* @return 成功返回pid,错误返回-1*/
extern pid_t runcmd_wait(pid_t pid, int *status);
  • 工作进程接收到检查任务后,使用runcmd_open启动插件。

  • 该函数fork新进程,为标准输出和标准错误建立管道(返回文件描述符pfdpfderr),并执行插件命令。

  • 工作进程从pfdpfderr读取数据直到关闭(表示插件完成输出),然后对返回的pid使用runcmd_wait(封装waitpid)获取插件退出status

  • 捕获的数据随后存入前文提到的wproc_result结构体并返回主引擎。

lib/wproc.c文件包含工作进程的实现代码,包括监听任务请求的循环和调用runcmd_open读取结果的代码。

示例lib/wproc.c中的print_input函数展示了进程(如Nagios主引擎)如何从工作进程套接字读取结构化结果(简化为键值对的wproc_result消息)。

用例

通过使用检查执行系统(由工作进程使用runcmd等工具协调),Nagios Core成功运行"Web Server 1"的check_http插件,获取关键信息:文本输出(“HTTP OK: …”)和退出代码(0表示正常,其他值表示问题)。

这些信息是Nagios引擎更新内存状态数据(状态数据管理)和status.dat文件的原始材料,最终显示在CGI界面中。

总结

检查执行机制通过运行实际外部插件,将监控配置转化为具体行动。

它将对象定义中的check_command转换为可执行进程,管理其执行(通常通过辅助工作进程),并捕获关键输出和退出代码。

这些结果是Nagios判断主机和服务状态的核心依据。

然而我们多次提到"工作进程"却未完整解释。Nagios如何管理与这些独立辅助进程的启动和通信?这正是下一章要探讨的内容。

第七章:工作进程

http://www.lryc.cn/news/588341.html

相关文章:

  • 【Linux】Linux 操作系统 - 28 , 进程间通信(四) -- IPC 资源的管理方式_信号量_临界区等基本概念介绍
  • Excel常用快捷键与功能整理
  • 《恋与深空》中黑白羽毛是谁的代表物?
  • 【前端】【分析】前端功能库二次封装:组件与 Hook 方式的区别与好处分析
  • 体验RAG GitHub/wow-rag
  • 国内MCP服务器搜索引擎有哪些?MCP导航站平台推荐
  • 基于cornerstone3D的dicom影像浏览器 第一章,新建vite项目,node版本22
  • 了解 Java 泛型:简明指南
  • yolo8+声纹识别(实时字幕)
  • ArkTs实现骰子布局
  • Pandas-特征工程详解
  • WinUI3开发_Combobox实现未展开时是图标下拉菜单带图标+文字
  • Java-ThreadLocal
  • Apache-web服务器环境搭建
  • 机器学习(ML)、深度学习(DL)、强化学习(RL):人工智能的三驾马车
  • 基于Snoic的音频对口型数字人
  • PyTorch 数据加载全攻略:从自定义数据集到模型训练
  • 7月14日作业
  • 选择一个系统作为主数据源的优势与考量
  • 【数据结构】基于顺序表的通讯录实现
  • Hello, Tauri!
  • The Network Link Layer: WSNs 泛洪和DSR动态源路由协议
  • Python:打造你的HTTP应用帝国
  • 院级医疗AI管理流程—基于数据共享、算法开发与工具链治理的系统化框架
  • VScode链接服务器一直卡在下载vscode服务器/scp上传服务器,无法连接成功
  • Fiddler——抓取https接口配置
  • linux服务器换ip后客户端无法从服务器下载数据到本地问题处理
  • TextIn:文档全能助手,让学习效率飙升的良心软件~
  • Git commit message
  • 2.逻辑回归、Softmax回归