
1. 为什么需要系统资源监控脚本在Linux服务器运维中系统资源监控是保证服务稳定性的第一道防线。我管理过上百台生产服务器最深刻的教训就是当收到用户投诉时问题往往已经发生了半小时以上。传统的监控工具如Zabbix、Prometheus虽然功能强大但在以下场景中显得笨重临时测试环境需要快速部署监控老旧设备无法承担额外监控服务开销需要定制化的告警逻辑比如只关注特定时段的CPU峰值一个轻量级的Shell脚本就能完美解决这些问题。上周我帮客户部署的监控脚本在内存泄漏导致OOM前成功触发告警避免了线上事故。这种脚本的核心价值在于实时性通过crontab可以实现分钟级监控低开销纯Shell实现不依赖额外服务可定制告警阈值、通知方式自由定义2. 基础监控命令深度解析2.1 CPU使用率获取的三种姿势最常用的top -bn1命令其实有坑首次运行会有不准确的初始值。经过多次测试我发现这些方法更可靠# 方法1mpstat需安装sysstat cpu_usage$(mpstat 1 1 | awk /Average/{print 100-$NF}) # 方法2/proc/stat计算推荐 read cpu a b c idle rest /proc/stat total$((abcidle)) cpu_usage$((100*(total-idle)/total)) # 方法3vmstat快速采样 cpu_usage$(vmstat 1 2 | tail -1 | awk {print 15})提示生产环境中建议使用方法2它不依赖额外工具且计算准确。注意/proc/stat的数值是自启动累计值需要两次采样计算差值。2.2 内存监控的隐藏陷阱free -m的输出看似简单但缓存(buffer/cache)的处理是关键。很多脚本错误地把可用内存算作free列实际上应该total_mem$(free -m | awk /Mem:/{print $2}) used_mem$(free -m | awk /Mem:/{print $3}) buff_cache$(free -m | awk /Mem:/{print $6}) real_used$((used_mem - buff_cache)) mem_usage$((real_used * 100 / total_mem))这个算法更真实反映应用内存压力避免缓存干扰判断。上周有个案例某服务器free显示只剩200MB但实际应用内存充足就是缓存占了3GB。2.3 磁盘容量检查的高级技巧df -h的常规用法有几个缺陷可能包含tmpfs等虚拟文件系统挂载点路径含空格时会解析错误改进方案# 只监控物理磁盘排除tmpfs, overlay等 df -h | awk /^\/dev\//{print $5 $6} | while read usage mount; do usage${usage%\%} if [ $usage -gt 90 ]; then echo 警报$mount 使用率 $usage% fi done对于LVM卷组还需要vgs和lvs命令补充检查。曾遇到一个坑物理卷已满但df显示充足导致数据写入失败。3. 工业级告警脚本实现3.1 参数化设计模板好的监控脚本应该像这样可配置#!/bin/bash # 配置区用户自定义 THRESHOLD_CPU90 THRESHOLD_MEM85 THRESHOLD_DISK90 ALERT_EMAILadminexample.com LOG_FILE/var/log/system_monitor.log3.2 多级告警机制实现简单的阈值触发太粗糙我推荐分级告警check_cpu() { local level$1 if [ $cpu_usage -ge $level ]; then local msgCPU使用率 ${cpu_usage}% 超过阈值 ${level}% echo $(date) - $msg $LOG_FILE send_alert CPU警报 $msg fi } # 分级检查 check_cpu 80 # 警告级 check_cpu 90 # 严重级 check_cpu 95 # 紧急级3.3 告警收敛与防抖动直接邮件轰炸是不可接受的必须实现时间窗口收敛相同告警1小时内不重复发送状态恢复通知问题解决后发送恢复提示抖动过滤短暂峰值不触发告警示例实现last_alert_time0 alert_cooldown3600 # 1小时冷却 send_alert() { local now$(date %s) if [ $((now - last_alert_time)) -gt $alert_cooldown ]; then mail -s $1 $ALERT_EMAIL $2 last_alert_time$now fi }4. 生产环境部署指南4.1 crontab配置的隐藏坑新手常犯的错误配置* * * * * /path/to/script.sh # 错误会重复执行正确做法是加锁防止并发* * * * * flock -xn /tmp/system_monitor.lock -c /path/to/script.sh4.2 日志轮转策略不加控制的日志会撑爆磁盘用logrotate配置# /etc/logrotate.d/system_monitor /var/log/system_monitor.log { daily rotate 7 compress missingok notifempty }4.3 性能优化技巧当监控大量服务器时这些优化很关键用awk替代grep|cut管道减少子进程创建如用${var%\%}替代echo $var | tr -d %合并磁盘检查单次df读取处理所有分区实测优化后脚本执行时间从800ms降到120ms。5. 异常案例处理手册5.1 虚假CPU高峰排查遇到CPU持续告警时按此流程排查top -H -p PID定位具体线程perf top -p PID分析热点函数cat /proc/PID/stack查看调用栈曾发现一个假警报定时任务导致updatedb全盘扫描CPU短暂冲高属正常现象。5.2 内存泄漏诊断当内存持续增长时# 1. 按内存排序进程 ps -eo pid,comm,%mem --sort-%mem | head # 2. 检查slab内存 cat /proc/meminfo | grep Slab # 3. 追踪进程内存分配 valgrind --toolmemcheck --leak-checkfull ./process5.3 磁盘空间幽灵占用当df显示已用空间与du统计不符时检查被删除但未释放的文件lsof | grep deleted排查Docker等容器日志find /var/lib/docker/containers -name *.log -size 1G6. 脚本安全加固方案6.1 权限最小化原则# 错误做法 chmod 777 script.sh # 正确配置 chown root:root script.sh chmod 750 script.sh6.2 输入验证与消毒所有外部输入必须验证validate_threshold() { if ! [[ $1 ~ ^[0-9]$ ]] || [ $1 -gt 100 ]; then echo 错误阈值$1 2 exit 1 fi }6.3 敏感信息保护告警邮件中的服务器信息需要脱敏# 替换IP最后一位 server_ip$(hostname -I | awk {print $1}) masked_ip$(echo $server_ip | sed s/\.[0-9]*$/.xxx/)7. 扩展监控维度7.1 温度监控服务器硬件温度也不容忽视# 需要lm-sensors temp$(sensors | awk /Package id/{print $4} | tr -d °C) if [ $temp -gt 90 ]; then echo CPU温度过高${temp}°C fi7.2 网络连接监控检测异常连接数# ESTABLISHED连接数 conn_count$(ss -s | awk /TCP:/{print $4}) if [ $conn_count -gt 1000 ]; then echo 连接数异常$conn_count fi7.3 进程存活检查关键进程监控模板check_process() { if ! pgrep -x $1 /dev/null; then echo 进程 $1 未运行 systemctl restart $1 fi }经过多年实战检验这套监控方案在几十家企业环境中稳定运行。最关键的体会是监控脚本不是写完就完需要根据业务特点持续调整阈值和检查项。比如电商系统需要特别关注大促时段的CPU波动而文件存储服务器则要重点监控inode使用情况。