ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Erlang/OTP OS_Mon 应用指南:CPU、磁盘、内存与系统消息监控服务的架构、配置与源码解析

Erlang/OTP OS_Mon 应用指南:CPU、磁盘、内存与系统消息监控服务的架构、配置与源码解析 编程语言语言运行时标准库编译器并发编程【免费下载链接】otpErlang/OTP项目地址https://gitcode.com/gh_mirrors/ot/otp点击查看免费下载导读OS_MonOperating System Monitor是 Erlang/OTP 中负责操作系统资源监控的标准应用为分布式 Erlang 系统提供 CPU 负载与利用率cpu_sup、磁盘空间disksup、内存使用memsup以及操作系统系统消息接入os_sup四类服务。本文以 lib/os_mon/doc/os_mon_app.md 为主线结合仓库内 lib/os_mon/src 的源码与测试用例完整讲解 OS_Mon 的启动决策机制、四个start_*配置参数及其在.config文件与运行时的用法并深入每个服务的阈值/间隔参数、告警机制与平台差异。读完本文你将能够在自己的 OTP 节点上按需启用或禁用监控服务读懂error_logger中与 OS_Mon 相关的警告含义并掌握通过 SASLalarm_handler接收磁盘、内存告警的完整链路。OS_Mon 是什么四大监控服务一览OS_Mon 应用提供以下四类操作系统监控服务来源os_mon_app.md 的 Description 部分与 os_mon.app.src 中声明的模块列表一致服务模块功能可用平台cpu_suplib/os_mon/src/cpu_sup.erlCPU 负载load average与 CPU 利用率监督Unixdisksuplib/os_mon/src/disksup.erl磁盘空间监督Unix、Windowsmemsuplib/os_mon/src/memsup.erl内存监督系统级与进程级Unix、Windowsos_suplib/os_mon/src/os_sup.erl操作系统系统消息接入转发至 error_loggerSolaris、Windows每个服务都是一个独立的 gen_server 进程注册名分别为cpu_sup、disksup、memsup和os_sup_server见 os_mon.erl 的server_name/1以及 os_mon.app.src 中registered字段。此外OS_Mon 内部还有一个始终启动的辅助服务os_mon_sysinfoWindows 平台下用于系统信息采集见下文。从 os_mon.erl 的监督树可以看出os_mon应用本身是一个 OTPapplicationsupervisor的组合start/2回调启动名为os_mon_sup的顶层监督者然后在init/1中按平台选择重启策略Windows{one_for_one, 5, 3600}其他平台{one_for_one, 4, 3600}即单个子进程崩溃后只重启该子进程one_for_one在 3600 秒内最多允许 4 次Windows 为 5 次重启超过则监督者放弃。平台可用性并非所有服务在所有系统上都存在OS_Mon 的可用服务集合由源码中的services/1函数按操作系统类型决定os_mon.erlservices({unix, sunos}) - [cpu_sup, disksup, memsup, os_sup]; services({unix, _}) - % Other unix. [cpu_sup, disksup, memsup]; services({win32, _}) - [disksup, memsup, os_sup, sysinfo].可见Solaris{unix, sunos}四个服务全部可用是唯一默认启用os_sup的 Unix 平台其他 UnixLinux、FreeBSD、macOS 等只有cpu_sup、disksup、memsup没有os_supWindows{win32, _}没有cpu_sup但有disksup、memsup、os_sup由nteventlog模块实现并且额外包含sysinfoos_mon_sysinfo服务。即使某服务在平台上可用OS_Mon 也允许通过配置参数选择不启动它——这正是下一节start_*参数的用途。分布式场景下的优雅降级dummy 值与警告日志OS_Mon 在设计上充分考虑分布式 Erlang 系统的使用场景。原文档明确指出在某个节点上尝试使用一个不可用的服务OS_Mon 未运行、该服务不支持当前 OS、或该服务未启动不会被当作错误。此时行为是通过error_logger输出一条警告消息返回一个哑值dummy value具体返回什么由各服务的 man page即各模块的 moduledoc规定例如cpu_sup:avg1/0在不可用时返回 0disksup:get_disk_data/0返回[{none,0,0}]。这一机制在 os_mon.erl 的call/3函数中实现所有服务的公共 API 最终都通过os_mon:call(Service, Request)转发当gen_server:call因进程不存在而抛出exit:{noproc, _}时os_mon会区分两种情形应用列表中存在os_mon即应用已启动但服务未启动/不可用打印OS_MON (~p) called by ~p, unavailableos_mon根本未启动打印OS_MON (~p) called by ~p, not started。两种情形下都调用Service:dummy_reply(Request)返回哑值而不是抛出异常。这样运行在不同节点上的应用无需在每个节点都启用全部 OS_Mon 服务也能安全地调用这些 API。OS_Mon 应用级配置四个 start_* 参数参数含义与默认值当os_mon应用启动时默认启动当前操作系统上所有可用的服务os_sup除外。这一行为由四个布尔型配置参数控制来源os_mon_app.md 的 Configuration 部分默认值在 os_mon.app.src 的env字段中声明配置参数类型含义默认值start_cpu_supbool()是否启动cpu_suptruestart_disksupbool()是否启动disksuptruestart_memsupbool()是否启动memsuptruestart_os_supbool()是否启动os_supfalse从源码角度这些参数对应的映射关系定义在 os_mon.erlstart_param(cpu_sup) - start_cpu_sup; start_param(disksup) - start_disksup; start_param(memsup) - start_memsup; start_param(os_sup) - start_os_sup; start_param(sysinfo) - none.注意os_mon_sysinfo没有对应的开关参数none因此它在支持的平台上总是随应用启动。启动决策的两层逻辑os_mon.erl 的startp/1完整实现了平台可用性 → 配置参数的两层判断先检查该服务是否属于当前 OS 的services(os:type())列表不在列表中直接返回false若可用再检查是否存在启动配置参数无参数则返回true如sysinfo有参数则读取application:get_env(os_mon, Param)只有显式为{ok, true}才启动其他情况未配置、配置为false、配置了非法值一律不启动。随后childspec/2os_mon.erl根据startp的结果决定是否把对应子进程规格加入监督树。例如os_sup的规格在 Windows 下用nteventlog作为模块在其他平台Solaris用os_sup本身重启超时 10000 ms其余服务为 2000 ms。通过 .config 文件配置OS_Mon 的配置参数可通过标准 Erlang 配置文件.config设置。仓库中 lib/kernel/doc/references/config.md 给出了完整的文件语法[{Application1, [{Par11, Val11}, ...]}, ... {ApplicationN, [{ParN1, ValN1}, ...]}].即一个.config文件是一个列表外层元素是应用名atom内层是该应用的{参数名, 值}列表。例如只启动磁盘与内存监控、关闭 CPU 监控的os_mon.config[{os_mon, [{start_cpu_sup, false}, {start_disksup, true}, {start_memsup, true}, {start_os_sup, false}]}].启动时用erl -config os_mon文件名需为os_mon.config加载。配置文件的优先级为命令行参数 配置文件 应用资源文件.app 中的 env。仓库根目录还提供了一个示例系统级配置 sys.config在嵌入式embedded模式下系统会从$ROOT/releases/Vsn/sys.config读取配置。运行时修改application:set_env配置文件的值在应用启动前生效对于运行中的节点可以用application:set_env/3动态修改但对start_*参数而言修改只影响下一次应用启动这些参数只在init/1构建监督树时被读取一次。测试套件 lib/os_mon/test/os_mon_SUITE.erl 的config/1用例就完整验证了这一行为ok application:start(os_mon), true lists:all(IsReg, [cpu_sup, disksup, memsup]), ok application:stop(os_mon), ok application:set_env(os_mon, start_cpu_sup, false), ok application:start(os_mon), true lists:all(IsReg, [disksup, memsup]), true IsNotReg(cpu_sup),该用例逐一将start_cpu_sup、start_disksup、start_memsup设为false后重启应用并断言对应服务进程没有注册。值得注意的是all/0os_mon_SUITE.erl只在 Solaris 上运行config用例——因为该用例用lists:all断言三个服务都在运行而 Windows 上cpu_sup本来就不存在。应用升级与运行时依赖OS_Mon 还带有 lib/os_mon/src/os_mon.appup.src 应用升级文件支持运行中热升级同时声明了运行时依赖stdlib-5.0、sasl-4.2.1、kernel-9.0、erts-14.0os_mon.app.src并依赖kernel、stdlib、sasl三个应用其中sasl提供alarm_handler供磁盘/内存告警使用。服务级配置深入cpu_supcpu_sup是 Unix 专属的 CPU 监控进程提供nprocs/0、avg1/0、avg5/0、avg15/0、util/0、util/1等 APIcpu_sup.erl其全部公共 API 均通过os_mon:call/3转发内部与一个端口程序port program通信。负载值load average的度量与换算模块文档cpu_sup.erl对负载值做了详细说明负载值正比于可运行 Unix 进程在运行队列中被调度前需要等待的时间返回值除以 256 即为rup/top显示的数值。例如rup显示 0.50 对应返回值 128显示 2.00 对应返回值 512avg1/0等函数在不可用时返回 0。由于负载值不限定在固定区间若希望以机器容量百分比理解负载官方给出如下换算公式PercentLoad 100 * (1 - D/(D Load))其中D决定某个负载值对应哪个百分比取D 50时负载 128 对应 60%256 对应 80%512 对应 90%。cpu_sup同时区分系统负载与CPU 利用率两个概念利用率util/0,1取值 0-100用忙 CPU 周期数除以总周期数衡量会掩盖机器饱和的事实——一个恰好不会空闲的服务器利用率是 100%再多收 50% 请求仍显示 100%而用上述百分比公式计算时负载会从 80% 升到 87%。因此文档强调利用率更适合叫CPU 利用率而非系统负载。平台与实现约束avg*系列在所有 Unix 上可用util/0,1仅在 Solaris、Linux、FreeBSD、OpenBSD 上可用在 Linux 上cpu_sup依赖/proc文件系统读取/proc/loadavg等若/proc不可访问则cpu_sup会终止cpu_sup.erl。根据 notes.md 的版本记录OS_Mon 2.4.7 起在 Android 上改用sysinfo系统调用获取基础 CPU 统计以绕过 SELinux 对/proc的限制从 2.1.5 起Linux 上的 CPU 利用率通过端口程序而非os:cmd测量以提升性能见 notes.md 中 2.1.5 条目。服务级配置深入disksupdisksup在 Unix 和 Windows 上可用disksup.erl周期性检查磁盘当某个磁盘或分区使用量超过阈值时通过 SASLalarm_handler:set_alarm/1设置告警{{disk_almost_full, MountedOn}, []}告警在触发条件消失后自动清除。检查范围按平台不同Unix检查所有本地挂载的磁盘包括 swap 盘若存在WIN32只检查类型为FIXED_DISK的逻辑盘。配置参数配置参数类型含义默认值disk_space_check_intervaltime()周期性磁盘检查的时间间隔30 分钟disk_almost_full_thresholdfloat()触发disk_almost_full告警的磁盘使用率阈值占总空间的百分比0.8080%disksup_posix_onlybool()是否只使用 POSIX 兼容命令执行检查false其中time()类型disksup.erl既支持整数分钟也支持{TimeUnit, Time}二元组形式TimeUnit为erlang:time_unit/0中的时间单位间隔至少 1 毫秒——OS_Mon 2.8 起disk_space_check_interval可以设置到小于一分钟见 notes.md 的 2.8 条目。disksup_posix_only true适用于嵌入式系统中df等工具被裁剪的情况该参数在已知不兼容 POSIX 的平台Windows、SunOS上被忽略。disksup的公共 API 包括get_disk_data/0返回最近一次检查结果格式为{Id, TotalKiB, Capacity}三元组列表不可用时返回[{none,0,0}]以及get_disk_info/0,1立即获取当前磁盘用量OS_Mon 2.9 引入见 notes.md。运行时可分别用get_check_interval/0,1与get_almost_full_threshold/0,1查询和调整间隔与阈值。服务级配置深入memsupmemsup在 Unix 和 Windows 上可用memsup.erl周期性执行内存检查并设置两类告警系统内存告警当已分配的系统内存超过阈值时设置{system_memory_high_watermark, []}进程内存告警当某个 Erlang 进程Pid分配的内存超过阈值时设置{process_memory_high_watermark, Pid}。告警通过alarm_handler:set_alarm/1上报给 SASL 告警处理器m:alarm_handler原因消失后自动清除。get_memory_data/0返回最近一次周期检查的结果get_system_memory_data/0返回与操作系统强相关的内存明细该调用是同步采集、开销更大。在 Unix 上总内存 物理页数 × 页大小可用内存 可用物理页数 × 页大小。配置参数配置参数类型含义默认值memory_check_intervalint() 0周期内存检查的时间间隔分钟1 分钟system_memory_high_watermarkfloat()系统内存告警阈值系统内存的百分比0.80process_memory_high_watermarkfloat()单进程内存告警阈值系统内存的百分比0.055%memsup_helper_timeoutint() 0等待一次内存检查结果的超时时间秒超时后经error_logger输出OS_MON (memsup) timeout挂起的同步调用返回哑值30 秒memsup_system_onlybool()是否只检查系统内存、跳过进程级检查false性能提示memsup_system_only true在并发进程很多的系统上尤其值得开启因为每次进程内存检查都要遍历整个进程列表见 memsup.erl。memsup的内存检查可能因系统过载导致/proc伪文件短暂不可用而超时Linux 上曾有案例此时返回哑值而不崩溃——这正是 OS_Mon 2.0 起统一可恢复错误不终止服务设计的一部分。运行时可用的 API 包括get_check_interval/0、set_check_interval/1、get_sysmem_high_watermark/0、set_sysmem_high_watermark/1、get_procmem_high_watermark/0、set_procmem_high_watermark/1、get_helper_timeout/0、set_helper_timeout/1与get_os_wordsize/0。memsup还曾在 2.10.1 修复过内存告警的计算基准有available_memory时优先使用它而不是总用free_memory见 notes.md 的 2.10.1 条目。服务级配置深入os_supos_sup是 OS 到 error_logger 的消息转发服务仅在 Solaris 与 Windows 上可用os_sup.erl。收到操作系统消息后会调用一个用户自定义回调函数回调可以自行完成过滤、格式化并选择适合业务的日志后端。警告os_sup不能在同一个硬件上运行多个实例。如果同一台机器上运行两个或更多 Erlang 节点必须将 OS_Mon 配置为只在其中一个节点启动os_supstart_os_sup false于其余节点。Solaris 运行方式Solaris 上消息来自syslogdsyslog 守护进程。启用该服务涉及需要 root 权限的操作修改可执行文件的属主与权限、为syslogd创建一份修改过的配置副本服务终止时必须恢复原始配置。启用/禁用既可以在os_sup进程内部完成也可以在外部完成见下方os_sup_enable。收到的系统事件格式官方不定义。Windows 运行方式Windows 上消息来自 eventlog 文件由nteventlog模块实现os_suplib/os_mon/src/nteventlog.erl。作为 OS_Mon 监督树的一部分nteventlog的 start 函数无需手动调用。OS 消息被格式化为五元组{Time, Category, Facility, Severity, Message}字段类型/取值Time{MegaSecs, Secs, MicroSecs}即now/0风格的时间戳Categorystring()通常为System、Application或Security注意与 NT eventlog 查看器中的 category 概念不同Facilitystring()消息来源通常是产生消息的应用名即查看器中的 sourceSeveritystring()取值Error、Warning、Informational、Audit_Success、Audit_Faulure或未知 NT 版本时的Severity_UnknownMessagestring()与 NT eventlog 查看器格式一致的格式化消息二进制数据不导入配置参数配置参数类型含义默认值os_sup_mfa{Module, Function, Args}收到 OS 消息Msg后调用的回调函数调用方式为apply(Module, Function, [Msg | Args]){os_sup, error_report, [Tag]}os_sup_errortagatom()使用默认回调时发送到 error_logger 的错误报告类型std_erroros_sup_enablebool()Solaris 专用是否在os_sup内部执行启用/禁用true还是外部执行falsetrue推荐false因为 Erlang 模拟器通常不应以 root 运行os_sup_ownstring()Solaris 专用存放syslogd备份副本、Erlang 专用配置文件和接收消息的命名管道FIFO的目录/etcos_sup_syslogconfstring()Solaris 专用syslogd配置文件的完整路径/etc/syslog.conf默认回调{os_sup, error_report, [Tag]}会把事件通过error_logger:error_report(Tag, Msg)发送给错误日志系统Tag即os_sup_errortag的值。要自定义处理逻辑可把os_sup_mfa指向自己的模块函数例如[{os_mon, [{start_os_sup, true}, {os_sup_mfa, {my_logger, handle_os_msg, []}}, {os_sup_errortag, my_os_event}]}].告警消费接入 SASL alarm_handlerdisksup与memsup的告警都通过 SASL 的alarm_handler上报这是 OS_Mon 与上层应用对接的标准入口。一个典型场景是应用启动时注册自己的告警处理回调gen_event:swap_handler(alarm_handler, {alarm_handler, swap}, {my_alarm_handler, []}).随后disksup/memsup周期性检查触发告警时你的回调会收到如下形式的告警{{disk_almost_full, /data}, []} % 磁盘使用率超过阈值 {system_memory_high_watermark, []} % 系统内存超过阈值 {process_memory_high_watermark, Pid} % 单进程内存超过阈值当告警条件不再成立时这些告警会被自动清除。这一联动关系在 disksup.erl 与 memsup.erl 的模块文档中均有明确说明。配置错误处理坏参数值不致命OS_Mon 2.0 起统一了配置参数校验行为见 notes.md 的 2.0 条目非法参数值不再被静默忽略旧disksup行为或导致应用终止旧memsup、os_sup行为而是输出警告并使用默认值。这一逻辑体现在 os_mon.erl 的get_env/2中读取application:get_env(os_mon, Param)有值时调用Service:param_type(Param, Value)校验合法则返回该值非法则输出OS_MON (~p), ignoring bad configuration parameter (~p~p)警告并返回Service:param_default(Param)未配置时直接返回默认值。各服务的param_type/2与param_default/1回调即各服务模块文档中配置参数表在源码层面的落地。小结OS_Mon 的配置决策树综合全文os_mon应用启动时对每个服务的决策可以概括为该服务是否在当前 OS 的services(os:type())列表中平台可用性若是是否存在对应的start_*配置参数sysinfo无此参数恒启动若存在application:get_env(os_mon, Param)是否为{ok, true}三层判断全部通过服务进程才被加入os_mon_sup监督树并随应用启动。对disksup/memsup其运行参数检查间隔、告警阈值等可在运行期通过set_*API 动态调整对cpu_sup负载换算公式PercentLoad 100 * (1 - D/(D Load))与 256 刻度除以 256 即rup显示值是理解其返回值的核心对os_sup务必牢记同机多节点只在一处启用的限制。进一步阅读应用总览文档lib/os_mon/doc/os_mon_app.md版本变更记录lib/os_mon/doc/notes.md应用实现lib/os_mon/src/os_mon.erl、lib/os_mon/src/os_mon.app.src各服务实现lib/os_mon/src/cpu_sup.erl、lib/os_mon/src/disksup.erl、lib/os_mon/src/memsup.erl、lib/os_mon/src/os_sup.erl、lib/os_mon/src/nteventlog.erl配置测试用例lib/os_mon/test/os_mon_SUITE.erl配置文件语法lib/kernel/doc/references/config.md系统级配置示例sys.config赞分享编程语言语言运行时标准库编译器并发编程【免费下载链接】otpErlang/OTP项目地址https://gitcode.com/gh_mirrors/ot/otp点击查看免费下载相关推荐Erlang/OTP OS_Mon 监控子系统完全解读CPU/磁盘/内存监控的设计演进与配置实战Erlang/OTP OS_Mon 监控子系统完全解读CPU/磁盘/内存监控的设计演进与配置实战 导读 OS_Mon 是 Erlang/OTP 自带的操作系统编程语言语言运行时标准库编译器并发编程Fay框架服务器资源监控CPU、内存与磁盘Fay框架服务器资源监控CPU、内存与磁盘 在数字人应用开发中服务器资源监控是保障系统稳定运行的关键环节。Fay框架作为集成语言模型与数字角色的开源数字人框Warp终端主题定制终极指南打造你的专属智能开发环境Warp终端主题定制终极指南打造你的专属智能开发环境 还在为单调的终端界面烦恼吗Warp终端不仅是一款革命性的智能开发工具更提供了强大的主题定制功能让你桌面应用开发者工具人工智能AI 应用AI Agent代码智能体创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表