第五章:事件调度

欢迎回到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.pswp.cn/bicheng/89447.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/89447.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/89447.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web3 常用前端库介绍

一、Web3 前端开发:连接用户与区块链的桥梁 随着 Web3 生态的蓬勃发展,前端开发从传统的页面渲染进化为区块链交互的核心枢纽。Web3 前端库作为连接用户与区块链的桥梁,承担着钱包集成、合约交互、数据可视化等关键功能。本文将系统解析主流 …

cnpm命令报internal/modules/cjs/loader.js:797 throw err; ^ Error: Cannot find

在运行一个项目的时候,需要升级电脑各组件的版本,结果导致cnpm命令无法正常使用,cnpm任何命令都会报如下这个错:找了半天,发现是由于cnpm与npm的版本不一致导致的,所以需要卸载并重新安装cnpm,重…

15、鸿蒙Harmony Next开发:创建自定义组件

目录 自定义组件的基本用法 自定义组件的基本结构 struct Component freezeWhenInactive build()函数 Entry EntryOptions Reusable 成员函数/变量 自定义组件的参数规定 build()函数 自定义组件生命周期 自定义组件的创建和渲染流程 自定义组件重新渲染 自定义…

深入理解Map.Entry.comparingByValue()和Map.Entry.comparingByKey()

文章目录深入理解Map.Entry.comparingByValue()和Map.Entry.comparingByKey()1. 方法定义comparingByKey()comparingByValue()2. 基本用法2.1 使用comparingByKey()2.2 使用comparingByValue()3. 方法重载版本comparingByKey(Comparator)comparingByValue(Comparator)4. 高级用…

Mac下载mysql

安装 brew list --versions | grep mysql查看已安装的mysql版本brew search mysql查看支持的mysql版本brew info mysql查看mysql版本信息brew install mysql进行安装/opt/homebrew/opt/mysql/bin/mysqld --initialize-insecure --user$(whoami) --basedir$(brew --prefix mysql…

PageHelper使用说明文档

文章目录一、简介二、集成步骤三、使用方法四、注意事项五、高级用法一、简介 PageHelper 是一个开源的 MyBatis 分页插件,它可以帮助我们在使用 MyBatis 进行数据库操作时方便地实现分页功能。通过简单的配置和少量的代码修改,就可以在查询数据时实现分…

grpo nl2sql qwen3 模型强化学习训练有效果的成立条件有哪些

在使用GRPO(强化学习算法)对Qwen3模型在NL2SQL(自然语言到SQL转换)任务上进行强化学习(RL)训练时,其效果成立的核心条件可归纳为以下几个关键维度,这些条件相互关联,共同…

面向向量检索的教育QA建模:九段日本文化研究所日本语学院的Prompt策略分析(6 / 500)

面向向量检索的教育QA建模:九段日本文化研究所日本语学院的Prompt策略分析(6 / 500) 系列说明 500 所日本语言学校结构化建模实战,第 6 篇。每篇拆解 1 所学校在 Prompt-QA 系统中的建模策略,分享工程经验,…

墨刀原型图的原理、与UI设计图的区别及转换方法详解-卓伊凡|贝贝

墨刀原型图的原理、与UI设计图的区别及转换方法详解-卓伊凡|贝贝最近有个设计由于时间比较仓促直接用 原型做的,但是原型做的大家都知道是没法用的,以下讲解原型和ui的区别,其次我们下面有三种方法把墨刀的原型变成UI图。一、墨刀原型图的原理…

前端 nodejs vue2 开发环境和微信开发环境 故障终极处理

现象某个vue2旧项目 引入vue-ls 组件等组件,冲突失败后删除,导致开发环境 vxe-table加载失败,还原后还是不行。前段项目崩溃。报警sass 某个方法 Deprecated ,之前不会处理方式_失败回退代码项目代码 删除 node_modules, 删除 …

【后端】.NET Core API框架搭建(9) --配置使用Log4Net日志

目录 1.添加包 2.新建公用类 3.新建配置 4.注册 4.1.类库项目设置 5.使用 在 .NET Core 项目中使用 Log4Net 做日志记录,具有很多优势。尽管 .NET Core 自带了 ILogger 接口(如使用内置的 ConsoleLogger、DebugLogger 等),但…

Agent交互细节

本文参考了https://www.bilibili.com/video/BV1v9V5zSEHA/视频及原作者代码实践 本文主要实践在第3节1、MCP MCP官方地址:https://modelcontextprotocol.io/introduction MCP 是一个开放协议,它规范了应用程序向 LLM 提供上下文的方式。 架构&#xff1a…

AI+医疗!VR和MR解剖学和针灸平台,智能时代如何重塑健康未来

在智能时代,“AI医疗”正从精准诊断入手,推动医疗系统变革,通过个性化健康管理、智能诊疗辅助等方式重塑健康未来!将人工智能(AI)与虚拟实境(VR)应用到中医教学,透过该系…

Sersync和Rsync部署

学习参考连接 以下是我在学习过程中借鉴的经验和下载资源链接,感谢几位大佬的帮助,也供各位参考。 Rsync踩坑: https://blog.csdn.net/XiaoXiaoYunXing/article/details/120160395 Sersync下载源 http://down.whsir.com/downloads/sersy…

Django基础(四)———模板常用过滤器

前言上篇文章给大家介绍了DTL模板的部分知识点这篇文章继续带大家深入理解Django框架中的模板过滤器一、模板常用过滤器1.add将传进来的参数添加到原来的值上面。这个过滤器会尝试将值和 参数转换成整形然后进行相加。如果转换成整形过程中失败了,那么会将值和参数进…

国内MCP服务器搜索引擎有哪些?MCP导航站平台推荐

在人工智能技术蓬勃发展的今天&#xff0c;AI模型与外部工具和服务的交互能力正成为推动技术进步的关键。AIbase&#xff08;<https://mcp.aibase.cn/>&#xff09;作为一个专注于MCP(Model Context Protocol&#xff0c;模型上下文协议)服务器的集合平台&#xff0c;为全…

Python中with的作用和用法

在这里我们来详细解释一下Python中非常重要的 with 语句。 我会从 “为什么需要它” 开始&#xff0c;然后讲解 “它是什么以及如何使用”&#xff0c;最后深入到 “它的工作原理” 和 “如何自定义”。1. 为什么需要 with 语句&#xff1f;(The Problem) 在编程中&#xff0c;…

缓存雪崩、缓存穿透,缓存击穿

Redis是一个完全开源免费的高性能非关系型&#xff08;NOSQL&#xff09;的key-value数据库。 Redis不可能把所有的数据都缓存起来(内存昂贵且有限)&#xff0c;所以Redis需要对数据 设置过期时间&#xff0c;并采用的是惰性删除定期删除两种策略对过期键删除。Redis对过期键的…

springmvc跨域解决方案

在Spring MVC中处理跨域请求&#xff08;CORS&#xff0c;Cross-Origin Resource Sharing&#xff09;通常涉及到配置HTTP响应头&#xff0c;以允许来自不同源的请求。Spring MVC提供了多种方式来配置CORS&#xff0c;包括全局配置和局部配置。 使用CrossOrigin注解 在控制器的…

btstack移植之安全配对(二)

3.13.3 Legacy配对首先&#xff0c;我们回复的paring response中&#xff0c;可以看到我们不支持secure connection&#xff0c;所以我们走的是legacy配对模式。图3-74 secure连接不支持然后&#xff0c;master在pairing confirm包中回复了confirm value。图3-75 master发送con…