Shell脚本如何监控内存使用率

wen 实用脚本 1

Shell脚本如何监控内存使用率:从入门到生产级实战

📖 目录导读

  1. 为什么需要监控内存使用率?
  2. 核心监控指标与命令速查
  3. 基础脚本:一页代码搞定内存告警
  4. 进阶优化:历史记录与可视化报表
  5. 生产环境部署:定时任务+邮件告警
  6. 避坑指南:常见错误与性能陷阱
  7. QA问答:你可能遇到的5个高频问题

为什么需要监控内存使用率?

内存是服务器性能的“温度计”,当内存使用率持续超过80%,系统会触发OOM Killer(内存溢出杀手)自动杀死进程,导致服务中断,Shell脚本能让我们在故障发生前收到预警,特别是对于没有商业监控工具的中小团队,一行脚本就能救回一个深夜宕机的项目。

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: 确保安装了mailutilsmailx,执行:
apt install mailutils(Ubuntu) 或 yum install mailx(CentOS)
配置SMTP服务器(建议使用腾讯云企业邮箱或SendGrid)。

Q3: 脚本运行时报错bc: command not found怎么办?

A: bc是一个基础计算器,安装方法:
apt install bcyum 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点拯救你的服务器。

抱歉,评论功能暂时关闭!