Server 系统性能监控自动报警脚本配置

2026-03-21 11:15:42 1006阅读

Server 系统性能监控自动报警脚本配置指南

在现代运维实践中,服务器系统性能的稳定性直接关系到业务连续性与用户体验。当 CPU 使用率持续飙升、内存耗尽或磁盘空间告急时,人工巡检往往滞后于故障发生。因此,构建一套轻量、可靠、可扩展的自动化监控与报警脚本,成为中小规模服务环境中的关键能力。本文将完整介绍如何基于 Linux 环境,使用 Shell 与 Python 协同实现系统级指标采集、阈值判断与多通道报警(邮件+本地日志),无需依赖第三方监控平台,全程可本地部署、自主可控。

一、监控指标设计与采集逻辑

我们聚焦三大核心维度:CPU 平均负载、内存使用率、根分区磁盘使用率。所有数据均通过系统内置命令实时获取,避免额外依赖:

  • CPU 负载:取 /proc/loadavg 中 5 分钟平均值,对比逻辑处理器数量;
  • 内存使用率:解析 /proc/meminfo,计算 Used / Total × 100%
  • 磁盘使用率:调用 df -P / 获取根分区挂载点使用百分比。

所有采集操作均控制在毫秒级,单次执行无显著资源开销。

二、Shell 主控脚本:定时触发与状态分发

以下为主控脚本 monitor.sh,负责每 5 分钟调度一次检测,并根据返回码决定是否触发报警:

#!/bin/bash
# monitor.sh —— 系统性能主监控脚本
# 运行方式:chmod +x monitor.sh && ./monitor.sh

# 配置项(可根据实际调整)
ALERT_CPU_LOAD="3.0"      # CPU 5分钟负载阈值(按核数倍数设定)
ALERT_MEM_PERCENT="85"    # 内存使用率阈值(%)
ALERT_DISK_PERCENT="90"   # 根分区磁盘使用率阈值(%)
LOG_FILE="/var/log/system_monitor.log"
ALERT_SCRIPT="/opt/scripts/send_alert.py"

# 记录日志函数
log_info() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" >> "$LOG_FILE"
}
log_alert() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [ALERT] $1" >> "$LOG_FILE"
}

# 获取当前 CPU 负载(5分钟平均)
get_cpu_load() {
    awk '{print $2}' /proc/loadavg | tr -d '\n'
}

# 获取内存使用率(整数百分比)
get_mem_usage() {
    local total=$(awk '/MemTotal:/ {print $2}' /proc/meminfo)
    local free=$(awk '/MemFree:/ {print $2}' /proc/meminfo)
    local available=$(awk '/MemAvailable:/ {print $2}' /proc/meminfo)
    # 采用 MemAvailable 更准确反映可用内存
    if [ -n "$available" ]; then
        echo $(( (total - available) * 100 / total ))
    else
        echo $(( (total - free) * 100 / total ))
    fi
}

# 获取根分区磁盘使用率(整数)
get_disk_usage() {
    df -P / | awk 'NR==2 {gsub(/%/,"",$5); print $5}'
}

# 执行检测并返回状态码:0=正常,1=需报警
run_check() {
    local cpu=$(get_cpu_load)
    local mem=$(get_mem_usage)
    local disk=$(get_disk_usage)

    log_info "CPU=$cpu, MEM=${mem}%, DISK=${disk}%"

    # 判断是否超限(支持浮点比较)
    awk -v c="$cpu" -v a="$ALERT_CPU_LOAD" \
        -v m="$mem" -v am="$ALERT_MEM_PERCENT" \
        -v d="$disk" -v ad="$ALERT_DISK_PERCENT" \
        'BEGIN { exit (c > a || m > am || d > ad) ? 1 : 0 }'
}

# 主流程
if run_check; then
    log_info "All metrics within normal range."
else
    log_alert "Threshold exceeded: CPU=$cpu, MEM=${mem}%, DISK=${disk}%"
    # 调用 Python 报警模块(支持邮件/钉钉等扩展)
    if [ -x "$ALERT_SCRIPT" ]; then
        "$ALERT_SCRIPT" \
            --cpu "$cpu" \
            --mem "$mem" \
            --disk "$disk" \
            --alert-time "$(date '+%Y-%m-%d %H:%M:%S')"
    fi
fi

三、Python 报警模块:多通道通知与容错处理

send_alert.py 实现结构化报警发送,当前支持本地日志与 SMTP 邮件双通道,代码简洁、异常捕获完备:

#!/usr/bin/env python3
# send_alert.py —— 报警通知模块
# 需安装:pip3 install smtplib email

import argparse
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime
import logging

# 日志配置
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [ALERT] %(message)s',
    handlers=[logging.FileHandler('/var/log/system_alert.log')]
)

def send_email(cpu, mem, disk, alert_time):
    # 邮件配置(请按需修改)
    smtp_server = "localhost"  # 可替换为真实 SMTP 地址
    smtp_port = 25
    sender = "monitor@localhost"
    recipients = ["admin@example.com"]

    subject = f"[ALERT] Server Resource Threshold Exceeded at {alert_time}"
    body = f"""\
Server performance alert detected:

Time: {alert_time}
CPU Load (5min): {cpu}
Memory Usage: {mem}%
Root Disk Usage: {disk}%

Please check system health immediately.
"""
    try:
        msg = MIMEMultipart()
        msg["From"] = sender
        msg["To"] = ", ".join(recipients)
        msg["Subject"] = subject
        msg.attach(MIMEText(body, "plain"))

        with smtplib.SMTP(smtp_server, smtp_port) as server:
            server.send_message(msg)
        logging.info(f"Email alert sent to {recipients}")
    except Exception as e:
        logging.error(f"Failed to send email: {e}")

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--cpu", required=True, type=str)
    parser.add_argument("--mem", required=True, type=str)
    parser.add_argument("--disk", required=True, type=str)
    parser.add_argument("--alert-time", required=True, type=str)
    args = parser.parse_args()

    logging.info(f"Alert triggered: CPU={args.cpu}, MEM={args.mem}%, DISK={args.disk}%")

    # 当前启用邮件通道;如需禁用,注释下一行即可
    send_email(args.cpu, args.mem, args.disk, args.alert_time)

if __name__ == "__main__":
    main()

四、部署与运行保障

将两个脚本保存后,赋予执行权限,并通过 crontab 设置周期任务:

# 添加至 crontab(每 5 分钟执行一次)
*/5 * * * * /opt/scripts/monitor.sh

建议创建专用用户运行脚本,限制其仅具备必要读取权限(如 /proc//var/log/)。同时配置 logrotate 对日志文件进行定期轮转,防止磁盘占满。

五、结语

本文提供的监控报警方案以最小依赖、最大透明为设计原则,全部组件均可审计、可调试、可定制。它不替代专业 APM 工具,但在快速响应初期异常、降低人工值守成本方面表现优异。随着业务演进,您可轻松扩展指标类型(如网络连接数、特定进程存活状态)或接入 Webhook 推送至企业微信、飞书等平台。真正的运维效能,始于对系统脉搏的持续感知——而这一切,从一段清晰、稳健、自洽的脚本开始。

文章版权声明:除非注明,否则均为Dark零点博客原创文章,转载或复制请以超链接形式并注明出处。

目录[+]