一、为什么需要Erlang监控系统

在分布式系统中,服务的高可用性和稳定性是至关重要的。想象一下,如果你的线上服务突然崩溃,而你却毫不知情,等到用户投诉才发现问题,那可就太被动了。Erlang作为一门专为高并发、分布式场景设计的语言,天生就具备强大的容错能力,但光有容错还不够,我们还需要实时监控系统的运行状态,及时发现问题并处理。

这时候,Erlang自带的两个工具库——OS_MonSASL就派上用场了。OS_Mon主要负责监控操作系统级别的资源,比如CPU、内存、磁盘等;而SASL(System Architecture Support Libraries)则更关注Erlang虚拟机(BEAM)内部的状态,比如进程崩溃、应用启动/停止等事件。

二、OS_Mon:监控系统资源

OS_Mon是Erlang/OTP中用于监控操作系统资源的工具集。它提供了一系列的模块,比如cpu_supmem_supdisk_log等,可以让我们轻松获取系统资源的使用情况。

示例:使用cpu_sup监控CPU使用率

%% 启动OS_Mon应用
application:start(os_mon).

%% 获取CPU使用率
{_, CpuUsage} = cpu_sup:util().

%% 打印CPU使用率
io:format("当前CPU使用率: ~p%~n", [CpuUsage]).

注释说明:

  1. application:start(os_mon):启动os_mon应用,这是使用OS_Mon功能的前提。
  2. cpu_sup:util():调用cpu_sup模块的util/0函数,返回CPU使用率的百分比。
  3. io:format/2:格式化输出CPU使用率。

示例:监控内存使用情况

%% 获取内存使用情况
{TotalMemory, UsedMemory} = mem_sup:get_memory_data().

%% 计算内存使用率
MemoryUsage = (UsedMemory / TotalMemory) * 100.

%% 打印内存使用率
io:format("内存使用率: ~p%~n", [MemoryUsage]).

注释说明:

  1. mem_sup:get_memory_data():返回系统总内存和已用内存(单位:KB)。
  2. 通过简单的计算,可以得到内存使用率。

三、SASL:监控Erlang虚拟机内部状态

SASL是Erlang中用于系统架构支持的工具库,它提供了日志记录、错误报告、应用监控等功能。通过配置SASL,我们可以捕获Erlang虚拟机的关键事件,比如进程崩溃、应用启动/停止等。

示例:配置SASL日志

首先,我们需要在sys.config文件中配置SASL

[
  {sasl, [
    {sasl_error_logger, {file, "sasl.log"}},
    {errlog_type, error}
  ]}
].

注释说明:

  1. sasl_error_logger:指定日志输出方式,这里设置为输出到文件sasl.log
  2. errlog_type:设置日志级别,error表示只记录错误事件。

示例:捕获进程崩溃事件

当Erlang进程崩溃时,SASL会记录相关事件。我们可以通过以下代码模拟一个崩溃的进程:

%% 创建一个会崩溃的进程
spawn(fun() -> 
    io:format("进程即将崩溃~n"),
    1 / 0  %% 触发除零错误
end).

注释说明:

  1. spawn/1:创建一个新的Erlang进程。
  2. 1 / 0:故意触发除零错误,导致进程崩溃。

查看sasl.log文件,可以看到类似以下的日志:

=CRASH REPORT==== 15-Jul-2023::10:30:45 ===
  crasher:
    initial call: erl_eval:expr/5
    pid: <0.123.0>
    exception error: bad argument in an arithmetic expression
      called as 1 / 0
    ancestors: [<0.122.0>]
    message_queue_len: 0
    links: []
    dictionary: []
    trap_exit: false
    status: running
    heap_size: 1598
    stack_size: 27
    reductions: 100

四、结合OS_Mon和SASL实现全面监控

单独使用OS_MonSASL已经能解决一部分问题,但如果能把两者结合起来,就能实现更全面的监控。

示例:定时监控系统资源并记录日志

%% 定义一个定时任务,每隔5秒检查一次系统资源
start_monitor() ->
    timer:apply_interval(5000, ?MODULE, log_system_status, []).

%% 记录系统状态
log_system_status() ->
    {_, CpuUsage} = cpu_sup:util(),
    {TotalMemory, UsedMemory} = mem_sup:get_memory_data(),
    MemoryUsage = (UsedMemory / TotalMemory) * 100,

    %% 将监控数据写入日志文件
    error_logger:info_msg(
        "系统状态: CPU=~p%, 内存=~p%~n", 
        [CpuUsage, MemoryUsage]
    ).

注释说明:

  1. timer:apply_interval/3:每隔5秒执行一次log_system_status/0函数。
  2. error_logger:info_msg/2:将监控数据以info级别写入日志。

五、应用场景与技术优缺点

应用场景

  1. 高可用服务:需要实时监控系统资源和服务状态,确保服务稳定运行。
  2. 故障排查:通过日志快速定位问题,比如进程崩溃或资源耗尽。
  3. 性能优化:长期记录系统资源使用情况,分析性能瓶颈。

技术优缺点

优点:

  • 轻量级OS_MonSASL是Erlang/OTP自带的工具,无需额外依赖。
  • 实时性:能够实时捕获系统事件和资源状态。
  • 灵活性:可以通过配置调整监控粒度和日志级别。

缺点:

  • 功能有限:相比专业的监控系统(如Prometheus),功能较为基础。
  • 日志管理:日志文件需要手动维护,长期运行可能导致文件过大。

注意事项

  1. 日志轮转:建议配置日志轮转,避免日志文件无限增长。
  2. 监控频率:过于频繁的监控可能影响系统性能,需根据实际需求调整。
  3. 错误处理:监控脚本本身要有容错机制,避免因监控失败导致主服务受影响。

六、总结

通过OS_MonSASL,我们可以轻松实现Erlang系统的全面监控。OS_Mon负责监控系统资源,SASL负责捕获Erlang虚拟机内部事件,两者结合能够帮助我们及时发现并解决问题。虽然功能上不如专业监控系统强大,但对于大多数Erlang应用来说已经足够。

如果你正在开发Erlang项目,不妨试试这两个工具,相信它们会让你的系统更加稳定可靠!