服务器资源监控与容量规划实战
服务器资源监控是运维基本功。CPU飙高、内存吃紧、磁盘快满……这些问题如果没有提前发现,等出故障再处理就被动了。除了实时监控,还需要做容量规划,预判什么时候该扩容。本文整理服务器资源监控的方法和容量规划的思路,附带实用脚本和告警配置。资源关键指标告警阈值查看命令CPU使用率、负载>70%警告,>90%严重内存available>80%警告,>90%严重free -h磁盘使用率、inode>80%警
·
前言
服务器资源监控是运维基本功。CPU飙高、内存吃紧、磁盘快满……这些问题如果没有提前发现,等出故障再处理就被动了。除了实时监控,还需要做容量规划,预判什么时候该扩容。
本文整理服务器资源监控的方法和容量规划的思路,附带实用脚本和告警配置。
1. CPU监控
1.1 核心指标
| 指标 | 含义 | 关注点 |
|---|---|---|
| user | 用户态CPU | 应用程序消耗 |
| system | 内核态CPU | 系统调用、IO等 |
| iowait | IO等待 | 磁盘IO瓶颈 |
| steal | 被偷取 | 虚拟化超卖 |
| load average | 负载 | 等待CPU的任务数 |
1.2 查看命令
# 实时查看
top
htop
# CPU使用率
mpstat -P ALL 1
# 负载历史
uptime
cat /proc/loadavg
# 详细统计
vmstat 1
# 按进程查看
pidstat -u 1
1.3 告警阈值建议
| 指标 | 警告 | 严重 |
|---|---|---|
| CPU使用率 | >70% | >90% |
| Load Average | >核心数*0.7 | >核心数 |
| iowait | >20% | >50% |
| steal | >5% | >20% |
1.4 监控脚本
#!/bin/bash
# cpu_monitor.sh
CPU_WARN=70
CPU_CRIT=90
LOAD_FACTOR=0.7
# 获取CPU使用率
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print 100 - $8}' | cut -d. -f1)
# 获取CPU核心数和负载
cores=$(nproc)
load=$(cat /proc/loadavg | awk '{print $1}')
load_threshold=$(echo "$cores * $LOAD_FACTOR" | bc)
# CPU使用率检查
if [ "$cpu_usage" -gt "$CPU_CRIT" ]; then
echo "[CRITICAL] CPU使用率: ${cpu_usage}%"
elif [ "$cpu_usage" -gt "$CPU_WARN" ]; then
echo "[WARNING] CPU使用率: ${cpu_usage}%"
else
echo "[OK] CPU使用率: ${cpu_usage}%"
fi
# 负载检查
load_int=$(echo "$load" | cut -d. -f1)
threshold_int=$(echo "$load_threshold" | cut -d. -f1)
if [ "$load_int" -gt "$cores" ]; then
echo "[CRITICAL] 系统负载: $load (核心数: $cores)"
elif [ "$load_int" -gt "$threshold_int" ]; then
echo "[WARNING] 系统负载: $load (核心数: $cores)"
else
echo "[OK] 系统负载: $load (核心数: $cores)"
fi
2. 内存监控
2.1 核心指标
| 指标 | 含义 |
|---|---|
| total | 总内存 |
| used | 已使用(不含buffer/cache) |
| free | 完全空闲 |
| available | 可用内存(最重要) |
| buffer/cache | 缓存,可被回收 |
| swap | 交换分区使用 |
2.2 查看命令
# 内存概览
free -h
# 详细信息
cat /proc/meminfo
# 按进程排序
ps aux --sort=-%mem | head -20
# 实时监控
watch -n 1 free -h
# 查看内存占用最高的进程
top -o %MEM
2.3 理解available vs free
$ free -h
total used free shared buff/cache available
Mem: 31Gi 12Gi 1.2Gi 1.5Gi 17Gi 16Gi
free只有1.2G,看起来很紧张- 但
available有16G,因为buff/cache可以回收 - 关注available,不是free
2.4 监控脚本
#!/bin/bash
# memory_monitor.sh
MEM_WARN=70
MEM_CRIT=85
SWAP_WARN=30
# 获取内存使用率(基于available)
mem_info=$(free | grep Mem)
total=$(echo $mem_info | awk '{print $2}')
available=$(echo $mem_info | awk '{print $7}')
used=$((total - available))
mem_usage=$((used * 100 / total))
# 获取Swap使用率
swap_info=$(free | grep Swap)
swap_total=$(echo $swap_info | awk '{print $2}')
swap_used=$(echo $swap_info | awk '{print $3}')
if [ "$swap_total" -gt 0 ]; then
swap_usage=$((swap_used * 100 / swap_total))
else
swap_usage=0
fi
# 内存检查
if [ "$mem_usage" -gt "$MEM_CRIT" ]; then
echo "[CRITICAL] 内存使用率: ${mem_usage}%"
elif [ "$mem_usage" -gt "$MEM_WARN" ]; then
echo "[WARNING] 内存使用率: ${mem_usage}%"
else
echo "[OK] 内存使用率: ${mem_usage}%"
fi
# Swap检查
if [ "$swap_usage" -gt "$SWAP_WARN" ]; then
echo "[WARNING] Swap使用率: ${swap_usage}%"
# 找出使用Swap的进程
echo "使用Swap的进程:"
for pid in $(ls /proc | grep -E '^[0-9]+$'); do
swap=$(cat /proc/$pid/status 2>/dev/null | grep VmSwap | awk '{print $2}')
if [ -n "$swap" ] && [ "$swap" -gt 0 ]; then
name=$(cat /proc/$pid/comm 2>/dev/null)
echo " $name (PID: $pid): ${swap}kB"
fi
done | sort -t: -k2 -rn | head -5
fi
3. 磁盘监控
3.1 核心指标
| 指标 | 含义 |
|---|---|
| 使用率 | 已用空间占比 |
| inode使用率 | 文件数量占比 |
| IO利用率 | 磁盘繁忙程度 |
| IO等待 | 读写延迟 |
3.2 查看命令
# 磁盘空间
df -h
# inode使用
df -i
# 目录大小
du -sh /path/*
du -sh /* | sort -rh | head -10
# IO统计
iostat -x 1
# 实时IO监控
iotop
# 查看大文件
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null
3.3 监控脚本
#!/bin/bash
# disk_monitor.sh
DISK_WARN=70
DISK_CRIT=85
INODE_WARN=70
echo "=== 磁盘空间检查 ==="
df -h | awk 'NR>1' | while read line; do
usage=$(echo $line | awk '{print $5}' | tr -d '%')
mount=$(echo $line | awk '{print $6}')
# 跳过临时文件系统
echo "$mount" | grep -qE '^/(dev|run|sys|proc)' && continue
if [ "$usage" -gt "$DISK_CRIT" ]; then
echo "[CRITICAL] $mount 使用率: ${usage}%"
elif [ "$usage" -gt "$DISK_WARN" ]; then
echo "[WARNING] $mount 使用率: ${usage}%"
fi
done
echo ""
echo "=== inode检查 ==="
df -i | awk 'NR>1' | while read line; do
usage=$(echo $line | awk '{print $5}' | tr -d '%')
mount=$(echo $line | awk '{print $6}')
echo "$mount" | grep -qE '^/(dev|run|sys|proc)' && continue
[ -z "$usage" ] && continue
if [ "$usage" -gt "$INODE_WARN" ]; then
echo "[WARNING] $mount inode使用率: ${usage}%"
fi
done
3.4 自动清理脚本
#!/bin/bash
# disk_cleanup.sh - 磁盘空间不足时自动清理
THRESHOLD=85
current_usage=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$current_usage" -gt "$THRESHOLD" ]; then
echo "磁盘使用率 ${current_usage}%,开始清理..."
# 清理系统日志
journalctl --vacuum-time=7d
# 清理包缓存
yum clean all 2>/dev/null || apt-get clean 2>/dev/null
# 清理/tmp下超过7天的文件
find /tmp -type f -mtime +7 -delete
# 清理应用日志(根据实际情况调整)
find /var/log -name "*.log.*" -mtime +30 -delete
new_usage=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
echo "清理完成,当前使用率: ${new_usage}%"
fi
4. 网络监控
4.1 核心指标
| 指标 | 含义 |
|---|---|
| 带宽使用 | 上传/下载速率 |
| 连接数 | TCP连接数量 |
| 错误包 | 丢包、错误 |
| 延迟 | 网络往返时间 |
4.2 查看命令
# 实时带宽
iftop
nload
sar -n DEV 1
# 连接统计
ss -s
netstat -an | awk '{print $6}' | sort | uniq -c | sort -rn
# 网卡错误
ip -s link show eth0
# 每个IP的连接数
ss -tn | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head
4.3 监控脚本
#!/bin/bash
# network_monitor.sh
CONN_WARN=5000
CONN_CRIT=10000
TIMEWAIT_WARN=3000
# TCP连接数
total_conn=$(ss -tn | wc -l)
established=$(ss -tn state established | wc -l)
timewait=$(ss -tn state time-wait | wc -l)
echo "=== TCP连接状态 ==="
echo "总连接数: $total_conn"
echo "ESTABLISHED: $established"
echo "TIME_WAIT: $timewait"
if [ "$total_conn" -gt "$CONN_CRIT" ]; then
echo "[CRITICAL] TCP连接数过高"
elif [ "$total_conn" -gt "$CONN_WARN" ]; then
echo "[WARNING] TCP连接数较高"
fi
if [ "$timewait" -gt "$TIMEWAIT_WARN" ]; then
echo "[WARNING] TIME_WAIT过多,检查是否有短连接问题"
fi
# 带宽检测(需要安装vnstat或使用/proc/net/dev)
echo ""
echo "=== 网卡流量 ==="
cat /proc/net/dev | grep -E 'eth0|ens' | awk '{print $1, "RX:", $2/1024/1024, "MB, TX:", $10/1024/1024, "MB"}'
5. 综合监控脚本
#!/bin/bash
# server_check.sh - 服务器综合检查
HOSTNAME=$(hostname)
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "=========================================="
echo "服务器巡检报告"
echo "主机名: $HOSTNAME"
echo "时间: $DATE"
echo "=========================================="
# CPU
echo ""
echo "【CPU】"
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{printf "%.1f", 100 - $8}')
load=$(cat /proc/loadavg | awk '{print $1, $2, $3}')
cores=$(nproc)
echo "使用率: ${cpu_usage}%"
echo "负载: $load (${cores}核)"
# 内存
echo ""
echo "【内存】"
free -h | awk '/Mem:/ {printf "总计: %s, 已用: %s, 可用: %s\n", $2, $3, $7}'
mem_usage=$(free | awk '/Mem:/ {printf "%.1f", ($2-$7)/$2*100}')
echo "使用率: ${mem_usage}%"
# 磁盘
echo ""
echo "【磁盘】"
df -h | awk 'NR>1 && !/tmpfs|devtmpfs/ {printf "%s: %s/%s (%s)\n", $6, $3, $2, $5}'
# 网络
echo ""
echo "【网络连接】"
ss -s | head -2
# 进程
echo ""
echo "【Top 5 CPU进程】"
ps aux --sort=-%cpu | head -6 | awk 'NR>1 {printf "%s %.1f%% %s\n", $2, $3, $11}'
echo ""
echo "【Top 5 内存进程】"
ps aux --sort=-%mem | head -6 | awk 'NR>1 {printf "%s %.1f%% %s\n", $2, $4, $11}'
# 系统信息
echo ""
echo "【系统信息】"
echo "运行时间: $(uptime -p)"
echo "内核版本: $(uname -r)"
echo ""
echo "=========================================="
6. 多节点监控
6.1 批量巡检脚本
管理多台服务器时,需要批量执行巡检:
#!/bin/bash
# batch_check.sh - 批量服务器巡检
SERVERS=(
"192.168.1.10"
"192.168.1.11"
"192.168.1.12"
)
for server in "${SERVERS[@]}"; do
echo "====== $server ======"
ssh -o ConnectTimeout=5 "$server" '
echo "CPU: $(top -bn1 | grep "Cpu(s)" | awk "{printf \"%.1f%%\", 100 - \$8}")"
echo "内存: $(free | awk "/Mem:/ {printf \"%.1f%%\", (\$2-\$7)/\$2*100}")"
echo "磁盘: $(df / | awk "NR==2 {print \$5}")"
echo "负载: $(cat /proc/loadavg | awk "{print \$1}")"
' 2>/dev/null || echo "连接失败"
echo ""
done
6.2 跨网络监控方案
服务器分布在不同网络时,直接SSH连接可能有问题:
- 云服务器在公网
- 办公室服务器在NAT后
- 家里的机器没有公网IP
解决方案:
- 跳板机模式:所有机器都能连的中转点
- 组网工具:WireGuard、ZeroTier、星空组网等,把机器组成虚拟局域网
用组网工具后,不管机器实际在哪,都可以用虚拟内网IP直接访问。监控脚本里的IP列表直接写虚拟IP:
SERVERS=(
"10.10.0.1" # 云服务器
"10.10.0.2" # 办公室
"10.10.0.3" # 家里
)
Prometheus监控也一样,配置虚拟IP就能跨网络采集数据。
6.3 Prometheus + Grafana方案
node_exporter配置:
# prometheus.yml
scrape_configs:
- job_name: 'node'
static_configs:
- targets:
- '10.10.0.1:9100'
- '10.10.0.2:9100'
- '10.10.0.3:9100'
常用告警规则:
# alerts.yml
groups:
- name: node
rules:
- alert: HighCpuUsage
expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
annotations:
summary: "CPU使用率过高 {{ $labels.instance }}"
- alert: HighMemoryUsage
expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "内存使用率过高 {{ $labels.instance }}"
- alert: DiskSpaceLow
expr: (1 - node_filesystem_avail_bytes{fstype!~"tmpfs|devtmpfs"} / node_filesystem_size_bytes) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "磁盘空间不足 {{ $labels.instance }} {{ $labels.mountpoint }}"
7. 容量规划
7.1 收集历史数据
#!/bin/bash
# collect_metrics.sh - 每小时收集资源使用数据
LOG_DIR="/var/log/capacity"
mkdir -p "$LOG_DIR"
DATE=$(date '+%Y-%m-%d %H:%M')
# CPU
cpu=$(top -bn1 | grep "Cpu(s)" | awk '{printf "%.1f", 100 - $8}')
# 内存
mem=$(free | awk '/Mem:/ {printf "%.1f", ($2-$7)/$2*100}')
# 磁盘
disk=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
# 记录
echo "$DATE,$cpu,$mem,$disk" >> "$LOG_DIR/metrics.csv"
crontab配置:
0 * * * * /opt/scripts/collect_metrics.sh
7.2 趋势分析
#!/bin/bash
# trend_analysis.sh - 趋势分析
LOG_FILE="/var/log/capacity/metrics.csv"
echo "=== 最近7天资源趋势 ==="
# 计算平均值和最大值
awk -F',' '
BEGIN {
cpu_sum=0; cpu_max=0; cpu_count=0
mem_sum=0; mem_max=0
disk_sum=0; disk_max=0
}
{
if (NR > 1) {
cpu_sum += $2; if ($2 > cpu_max) cpu_max = $2
mem_sum += $3; if ($3 > mem_max) mem_max = $3
disk_sum += $4; if ($4 > disk_max) disk_max = $4
cpu_count++
}
}
END {
printf "CPU: 平均 %.1f%%, 峰值 %.1f%%\n", cpu_sum/cpu_count, cpu_max
printf "内存: 平均 %.1f%%, 峰值 %.1f%%\n", mem_sum/cpu_count, mem_max
printf "磁盘: 平均 %.1f%%, 峰值 %.1f%%\n", disk_sum/cpu_count, disk_max
}' "$LOG_FILE"
# 磁盘增长预测
echo ""
echo "=== 磁盘增长预测 ==="
first_disk=$(head -2 "$LOG_FILE" | tail -1 | cut -d',' -f4)
last_disk=$(tail -1 "$LOG_FILE" | cut -d',' -f4)
days=7
growth_per_day=$(echo "scale=2; ($last_disk - $first_disk) / $days" | bc)
if [ "$(echo "$growth_per_day > 0" | bc)" -eq 1 ]; then
days_to_full=$(echo "scale=0; (85 - $last_disk) / $growth_per_day" | bc)
echo "当前使用: ${last_disk}%"
echo "日增长率: ${growth_per_day}%"
echo "预计 $days_to_full 天后达到85%警戒线"
fi
7.3 扩容决策
| 指标 | 扩容建议 |
|---|---|
| CPU持续>70% | 升级CPU或水平扩展 |
| 内存持续>80% | 增加内存或优化应用 |
| 磁盘增长快 | 扩容或清理+归档 |
| 网络打满 | 升级带宽或CDN分流 |
扩容原则:
- 不要等到爆了再扩,预留缓冲
- 分析是突发还是趋势
- 优先优化,再考虑扩容
- 水平扩展优于垂直扩展
总结
| 资源 | 关键指标 | 告警阈值 | 查看命令 |
|---|---|---|---|
| CPU | 使用率、负载 | >70%警告,>90%严重 | top, mpstat |
| 内存 | available | >80%警告,>90%严重 | free -h |
| 磁盘 | 使用率、inode | >80%警告,>90%严重 | df -h, df -i |
| 网络 | 连接数、带宽 | 根据业务定 | ss -s, iftop |
监控体系搭建建议:
- 脚本级:简单场景,crontab + 脚本
- 工具级:单机用htop、glances
- 平台级:多机用Prometheus + Grafana
- 商业级:云厂商监控或Datadog、New Relic
监控的目的是提前发现问题,不是出问题后才看。建好告警规则,设置合理阈值,才能真正发挥作用。
更多推荐

所有评论(0)