Shell脚本如何监控内存使用率:从入门到生产级实战
📖 目录导读
- 为什么需要监控内存使用率?
- 核心监控指标与命令速查
- 基础脚本:一页代码搞定内存告警
- 进阶优化:历史记录与可视化报表
- 生产环境部署:定时任务+邮件告警
- 避坑指南:常见错误与性能陷阱
- QA问答:你可能遇到的5个高频问题
为什么需要监控内存使用率?
内存是服务器性能的“温度计”,当内存使用率持续超过80%,系统会触发OOM Killer(内存溢出杀手)自动杀死进程,导致服务中断,Shell脚本能让我们在故障发生前收到预警,特别是对于没有商业监控工具的中小团队,一行脚本就能救回一个深夜宕机的项目。

适用场景:
- 云服务器(阿里云、腾讯云、AWS)按量付费,过度使用内存会触发成本飙升
- 高并发Web应用(Nginx+PHP-FPM)内存泄漏排查
- 数据库服务器(MySQL/PostgreSQL)的内存抖动
核心监控指标与命令速查
在编写脚本前,必须理解Linux提供的内存数据来源(以下命令可在任何发行版运行):
# 查看完整内存使用 free -h # 输出样例: # total used free shared buff/cache available # Mem: 7.6G 4.2G 1.1G 456M 2.3G 2.8G
关键列解释:
total:物理内存总量used:已用内存(包含缓存)available:真正可用的内存(推荐作为监控依据)free:完全未使用的内存(数值可能很小,不等于可用)
# 获取特定数据的另一种方式 cat /proc/meminfo | grep -E "^MemTotal|^MemAvailable|^MemFree"
计算公式(行业标准):
真实使用率 = (total - available) / total * 100
❌ 不要用
used/total,因为 used 包含了缓存,这会导致误报。
基础脚本:一页代码搞定内存告警
以下是一个可直接运行的监控脚本,我会用中文注释解释每一行的作用:
#!/bin/bash
# ========================================
# 文件名:mem_monitor.sh
# 功能:内存使用率超过阈值则输出警告
# 用法:bash mem_monitor.sh [阈值百分比]
# ========================================
# 设置默认阈值为80%
THRESHOLD=${1:-80}
# 从 /proc/meminfo 获取关键数据
TOTAL=$(grep "^MemTotal" /proc/meminfo | awk '{print $2}')
AVAILABLE=$(grep "^MemAvailable" /proc/meminfo | awk '{print $2}')
# 计算使用率(保留两位小数)
USAGE=$(echo "scale=2; ($TOTAL - $AVAILABLE) / $TOTAL * 100" | bc)
# 判断是否超过阈值
if [ $(echo "$USAGE > $THRESHOLD" | bc) -eq 1 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 内存告警:使用率 $USAGE% 超过阈值 $THRESHOLD%"
# 这里可以插入邮件发送命令(后续章节提到)
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ✅ 内存正常:使用率 $USAGE%"
fi
运行效果:
# 手动运行,设置阈值为70% bash mem_monitor.sh 70 # 输出: [2025-03-15 14:30:21] ⚠️ 内存告警:使用率 83.45% 超过阈值 70%
进阶优化:历史记录与可视化报表
为了让监控更有价值,我们需要记录历史数据,并生成简单的趋势图,这里用纯Shell+CSV实现:
1 日志记录版
#!/bin/bash
LOG_FILE="/var/log/memory_usage.csv"
echo "时间,总内存(KB),可用内存(KB),使用率(%)" >> $LOG_FILE
# 循环采集(每5秒一次)
while true; do
TOTAL=$(grep "^MemTotal" /proc/meminfo | awk '{print $2}')
AVAILABLE=$(grep "^MemAvailable" /proc/meminfo | awk '{print $2}')
USAGE=$(echo "scale=2; ($TOTAL - $AVAILABLE) / $TOTAL * 100" | bc)
echo "$(date '+%Y-%m-%d %H:%M:%S'),$TOTAL,$AVAILABLE,$USAGE" >> $LOG_FILE
sleep 5
done
2 用awk生成简易趋势图(字符画)
# 读取CSV最后10条记录,生成柱状图
tail -10 /var/log/memory_usage.csv | awk -F',' '{usage=$4; bar=usage/5; printf "%s ", $1; for(i=0;i<bar;i++) printf "█"; print " "usage"%"}'
# 输出(示例):
# 2025-03-15 14:30:21 ████████████████ 83.45%
# 2025-03-15 14:30:26 ██████████████ 78.12%
生产环境部署:定时任务+邮件告警
1 集成邮件发送
# 在基础脚本中增加邮件功能(需安装mailx)
if [ $(echo "$USAGE > $THRESHOLD" | bc) -eq 1 ]; then
echo "服务器$(hostname)内存告警: $USAGE%" | mail -s "[告警] 内存使用率超标" admin@example.com
fi
2 设置crontab定时任务
# 编辑定时任务 crontab -e # 添加以下行(每分钟检查一次) * * * * * /bin/bash /path/to/mem_monitor.sh 80 # 如果想让日志每天轮转,可以再加一行: 0 0 * * * mv /var/log/memory_usage.csv /var/log/memory_usage_$(date -d yesterday +%Y%m%d).csv
3 企业级优化建议
- 阈值分层:70%告警(黄色)、85%告警(红色)、95%自动重启服务
- 进程级排查:在告警时自动输出top内存进程
ps aux --sort=-%mem | head -5
- 排除避讳:使用
/proc/meminfo而非free -m,避免解析文本出错
避坑指南:常见错误与性能陷阱
❌ 错误1:依赖free命令的used字段
- 原因:
used包含buff/cache,实际可用内存更多 - 解决:用
available计算
❌ 错误2:忘记处理单位转换
free -h输出是带单位的(K/M/G),直接参与计算会报错- 解决:始终使用
/proc/meminfo的KB数值
❌ 错误3:每分钟检查一次导致磁盘爆满
- 日志文件很快涨到GB级
- 解决:配合logrotate或限制采集频率(建议5分钟以上)
❌ 错误4:无线循环导致内存泄漏
- 脚本中不要使用
while true而没写退出条件 - 正确做法:定时任务每次单独运行一个脚本
QA问答:你可能遇到的5个高频问题
Q1: 为什么我的脚本显示内存使用率100%,但free -m显示有很多free?
A: 这是因为你用的used/total公式,而used包含了buff/cache,请改用available字段计算,Linux内核会利用空闲内存做缓存,当程序需要时立即释放,所以available才是真实可用。
Q2: 如何在CentOS和Ubuntu上通用地发送邮件?
A: 确保安装了mailutils或mailx,执行:
apt install mailutils(Ubuntu) 或 yum install mailx(CentOS)
配置SMTP服务器(建议使用腾讯云企业邮箱或SendGrid)。
Q3: 脚本运行时报错bc: command not found怎么办?
A: bc是一个基础计算器,安装方法:
apt install bc 或 yum install bc
或者使用awk代替bc:
USAGE=$(awk "BEGIN {printf \"%.2f\", ($TOTAL-$AVAILABLE)/$TOTAL*100}")
Q4: 我要监控多个服务器怎么办?
A: 可以使用SSH批量分发或搭建集中式日志系统,简单做法:在每台服务器部署脚本,将结果通过curl发送到你的API服务,或者使用Ansible批量部署crontab。
Q5: 定时任务每1分钟检查一次太频繁了,怎么优化?
A: 首先评估你的场景:如果是告警类任务,每分钟检查一次完全可以(脚本本身执行<0.1秒),但如果磁盘IO敏感,建议改为每5分钟一次,可以通过*/5 * * * *实现。
延伸阅读:
- 官方文档:Linux内核内存管理
- 相关领域:磁盘监控、CPU监控、网络流量监控的Shell脚本写法类似,只需替换关键命令
- 推荐工具:对于可视化监控,可以考虑结合
Grafana + Prometheus,但初期用Shell足矣
通过上述代码和策略,你可以用10行Shell脚本完成企业级内存监控的80%功能,没有花哨的界面,但每一行都能在凌晨2点拯救你的服务器。