Appearance
系统监控脚本
本节实现一个完整的系统资源监控脚本,能够实时采集 CPU、内存、磁盘和网络信息,并在超出阈值时发出告警。
功能设计
- 监控 CPU 使用率
- 监控内存使用率
- 监控磁盘使用率
- 监控关键进程存活
- 超阈值发送告警邮件或写日志
- 支持定时循环运行
完整脚本
bash
#!/usr/bin/env bash
#
# 系统监控脚本
# 用法:./monitor.sh [--interval 秒数] [--log 日志文件]
#
set -euo pipefail
# ============================================================
# 配置区
# ============================================================
INTERVAL=60 # 监控间隔(秒)
LOG_FILE="/var/log/system_monitor.log"
ALERT_EMAIL="admin@example.com"
# 告警阈值
CPU_THRESHOLD=80 # CPU 使用率阈值(%)
MEM_THRESHOLD=85 # 内存使用率阈值(%)
DISK_THRESHOLD=90 # 磁盘使用率阈值(%)
# 需要监控的进程
WATCH_PROCESSES=("nginx" "mysql" "redis-server")
# ============================================================
# 工具函数
# ============================================================
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
alert() {
local message="$1"
log "⚠️ 告警:$message"
# 发送邮件(需要配置 mailutils)
# echo "$message" | mail -s "系统告警 - $(hostname)" "$ALERT_EMAIL"
}
# ============================================================
# 监控函数
# ============================================================
# 获取 CPU 使用率
get_cpu_usage() {
# 采样两次取平均值
local cpu1 cpu2
cpu1=$(grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$3+$4+$5)} END {print int(usage)}')
sleep 1
cpu2=$(grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$3+$4+$5)} END {print int(usage)}')
echo $(( (cpu1 + cpu2) / 2 ))
}
# 获取内存使用率
get_mem_usage() {
free | awk 'NR==2 {printf "%.0f", $3*100/$2}'
}
# 获取磁盘使用率(根分区)
get_disk_usage() {
df / | awk 'NR==2 {print $5}' | tr -d '%'
}
# 检查进程是否存活
check_process() {
local proc="$1"
pgrep -x "$proc" > /dev/null 2>&1
}
# 监控 CPU
monitor_cpu() {
local usage
usage=$(get_cpu_usage)
log "CPU 使用率:${usage}%"
if (( usage > CPU_THRESHOLD )); then
alert "CPU 使用率过高:${usage}%(阈值:${CPU_THRESHOLD}%)"
# 输出 CPU 占用 TOP 5 进程
log "CPU TOP 5 进程:"
ps aux --sort=-%cpu | awk 'NR<=6 {print}' | tee -a "$LOG_FILE"
fi
}
# 监控内存
monitor_memory() {
local usage total used free_mem
usage=$(get_mem_usage)
total=$(free -m | awk 'NR==2 {print $2}')
used=$(free -m | awk 'NR==2 {print $3}')
free_mem=$(free -m | awk 'NR==2 {print $4}')
log "内存:总计 ${total}MB | 使用 ${used}MB | 空闲 ${free_mem}MB | 使用率 ${usage}%"
if (( usage > MEM_THRESHOLD )); then
alert "内存使用率过高:${usage}%(阈值:${MEM_THRESHOLD}%)"
log "内存 TOP 5 进程:"
ps aux --sort=-%mem | awk 'NR<=6 {print}' | tee -a "$LOG_FILE"
fi
}
# 监控磁盘
monitor_disk() {
log "磁盘使用情况:"
df -h | grep -v tmpfs | tee -a "$LOG_FILE"
# 检查每个挂载点
while IFS= read -r line; do
local usage mount
usage=$(echo "$line" | awk '{print $5}' | tr -d '%')
mount=$(echo "$line" | awk '{print $6}')
if (( usage > DISK_THRESHOLD )); then
alert "磁盘分区 $mount 使用率过高:${usage}%(阈值:${DISK_THRESHOLD}%)"
fi
done < <(df | grep -v tmpfs | tail -n +2)
}
# 监控关键进程
monitor_processes() {
for proc in "${WATCH_PROCESSES[@]}"; do
if check_process "$proc"; then
log "进程 $proc:运行中 ✓"
else
alert "进程 $proc 未运行!"
# 可以在此添加自动重启逻辑
# systemctl restart "$proc"
fi
done
}
# 系统负载
monitor_load() {
local load1 load5 load15 cpu_cores
read -r load1 load5 load15 _ < /proc/loadavg
cpu_cores=$(nproc)
log "系统负载:1分钟=${load1} 5分钟=${load5} 15分钟=${load15}(CPU核心数:${cpu_cores})"
}
# ============================================================
# 主循环
# ============================================================
main() {
log "==================================================="
log "系统监控启动 | 主机:$(hostname) | 间隔:${INTERVAL}秒"
log "==================================================="
while true; do
log "--- 开始巡检 ---"
monitor_cpu
monitor_memory
monitor_disk
monitor_processes
monitor_load
log "--- 巡检完成 ---"
sleep "$INTERVAL"
done
}
# 处理参数
while [[ $# -gt 0 ]]; do
case "$1" in
--interval) INTERVAL="$2"; shift 2 ;;
--log) LOG_FILE="$2"; shift 2 ;;
*) echo "未知参数:$1"; exit 1 ;;
esac
done
main使用方法
bash
# 赋予执行权限
chmod +x monitor.sh
# 直接运行(默认每 60 秒监控一次)
./monitor.sh
# 自定义间隔和日志文件
./monitor.sh --interval 30 --log /tmp/monitor.log
# 后台运行
nohup ./monitor.sh > /dev/null 2>&1 &
# 配合 cron 使用(每 5 分钟运行一次)
# */5 * * * * /path/to/monitor.sh扩展思路
- 集成钉钉/企业微信 Webhook 发送告警消息
- 将监控数据写入 InfluxDB 并用 Grafana 展示
- 增加网络流量监控(
/proc/net/dev) - 增加 TCP 连接数监控(
ss -s)