题目
编写进程资源监控脚本并在超阈值时告警
信息
- 类型:问答
- 难度:⭐⭐
考点
进程监控,资源阈值判断,邮件告警,脚本健壮性
快速回答
该脚本需要实现以下核心功能:
- 使用
ps或top获取指定进程的CPU/内存占用 - 设置可配置的阈值参数
- 超过阈值时发送告警邮件(使用
mail命令) - 包含错误处理和参数校验机制
示例命令调用:./monitor.sh -p nginx -c 50 -m 70 -e admin@example.com
解析
需求分析
需要编写一个可配置的监控脚本,当指定进程的CPU或内存使用率超过预设阈值时,自动发送告警邮件。重点考察:
- 进程资源获取的准确性
- 阈值比较逻辑
- 邮件功能的集成
- 脚本的健壮性和可配置性
实现方案
基础代码框架
#!/bin/bash
# 默认参数
PROCESS=""
CPU_THRESHOLD=80
MEM_THRESHOLD=90
EMAIL=""
# 解析参数
while getopts ":p:c:m:e:" opt; do
case $opt in
p) PROCESS="$OPTARG" ;;
c) CPU_THRESHOLD="$OPTARG" ;;
m) MEM_THRESHOLD="$OPTARG" ;;
e) EMAIL="$OPTARG" ;;
?) echo "Invalid option: -$OPTARG"; exit 1 ;;
esac
done
# 参数校验
if [ -z "$PROCESS" ] || [ -z "$EMAIL" ]; then
echo "Usage: $0 -p process_name -e email [-c cpu_threshold] [-m mem_threshold]"
exit 1
fi
# 获取进程资源使用率
pid=$(pgrep -f "$PROCESS" | head -1)
if [ -z "$pid" ]; then
echo "ERROR: Process '$PROCESS' not found"
exit 1
fi
# 使用ps获取CPU和内存百分比
stats=$(ps -p "$pid" -o %cpu,%mem --no-headers)
cpu_usage=$(echo "$stats" | awk '{print $1}')
mem_usage=$(echo "$stats" | awk '{print $2}')
# 浮点数比较(使用bc)
cpu_alert=$(echo "$cpu_usage > $CPU_THRESHOLD" | bc -l)
mem_alert=$(echo "$mem_usage > $MEM_THRESHOLD" | bc -l)
# 告警逻辑
if [ "$cpu_alert" -eq 1 ] || [ "$mem_alert" -eq 1 ]; then
subject="ALERT: $PROCESS resource usage exceeded"
body="Process: $PROCESS (PID: $pid)\n"
body+="CPU Usage: ${cpu_usage}% (Threshold: ${CPU_THRESHOLD}%)\n"
body+="Memory Usage: ${mem_usage}% (Threshold: ${MEM_THRESHOLD}%)"
echo -e "$body" | mail -s "$subject" "$EMAIL"
echo "Alert sent to $EMAIL"
fi关键点说明
1. 资源获取方式
- 使用
ps -p pid -o %cpu,%mem获取特定进程资源 - 替代方案:
top -b -n1 -p pid(需额外解析) - 注意:
%cpu是累计CPU时间除以进程运行时间,可能超过100%(多核场景)
2. 浮点数比较
- Shell本身不支持浮点比较,需借助
bc或awk - 示例:
echo "$cpu_usage > 50.5" | bc -l返回1(true)或0(false)
3. 邮件发送
- 依赖系统
mail命令,需提前配置SMTP - 替代方案:
sendmail或ssmtp - 最佳实践:邮件主题包含关键信息,正文结构化
4. 健壮性增强
- 使用
getopts处理参数,支持带空格的进程名 - 检查进程是否存在:
pgrep -f匹配完整命令 - 验证数值参数:添加
[ "$CPU_THRESHOLD" -eq "$CPU_THRESHOLD" ] 2>/dev/null
常见错误
- 进程匹配问题:使用
pgrep而非ps | grep避免匹配到grep自身 - 多进程处理:当前脚本监控第一个匹配进程,应循环处理所有PID:
pgrep -f "$PROCESS" | while read pid; do # 监控每个pid stats=$(ps -p "$pid" -o %cpu,%mem --no-headers) ... done - 阈值类型错误:未校验参数是否为数字,导致bc报错
扩展优化
- 频率控制:添加时间戳记录,避免重复告警
- 多监控项:增加磁盘IO、线程数等监控
- 聚合报告:改为周期性运行,生成汇总报告
- 替代工具:生产环境建议使用Prometheus+Grafana等专业方案
完整增强版示例
#!/bin/bash
# 添加参数校验函数
validate_number() {
if ! [[ "$2" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
echo "ERROR: Invalid $1 value '$2'"
exit 1
fi
}
# 解析参数(略)...
# 增强校验
validate_number "CPU threshold" "$CPU_THRESHOLD"
validate_number "Memory threshold" "$MEM_THRESHOLD"
# 获取所有匹配进程
pids=$(pgrep -f "$PROCESS")
if [ -z "$pids" ]; then
echo "ERROR: Process '$PROCESS' not running"
exit 1
fi
# 监控每个进程
while read pid; do
stats=$(ps -p "$pid" -o %cpu,%mem,cmd --no-headers)
# 解析数据(略)...
# 触发告警(略)...
done <<< "$pids"