前言
服务器资源监控是运维基本功。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 eth
0
# 每个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分流
扩容原则:
不要等到爆了再扩,预留缓冲分析是突发还是趋势优先优化,再考虑扩容水平扩展优于垂直扩展
总结
监控体系搭建建议:
脚本级:简单场景,crontab + 脚本
工具级:单机用htop、glances
平台级:多机用Prometheus + Grafana
商业级:云厂商监控或Datadog、New Relic
监控的目的是提前发现问题,不是出问题后才看。建好告警规则,设置合理阈值,才能真正发挥作用。