前言

服务器资源监控是运维基本功。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

解决方案

  1. 跳板机模式:所有机器都能连的中转点
  2. 组网工具: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分流

扩容原则

  1. 不要等到爆了再扩,预留缓冲
  2. 分析是突发还是趋势
  3. 优先优化,再考虑扩容
  4. 水平扩展优于垂直扩展

总结

资源 关键指标 告警阈值 查看命令
CPU 使用率、负载 >70%警告,>90%严重 top, mpstat
内存 available >80%警告,>90%严重 free -h
磁盘 使用率、inode >80%警告,>90%严重 df -h, df -i
网络 连接数、带宽 根据业务定 ss -s, iftop

监控体系搭建建议

  1. 脚本级:简单场景,crontab + 脚本
  2. 工具级:单机用htop、glances
  3. 平台级:多机用Prometheus + Grafana
  4. 商业级:云厂商监控或Datadog、New Relic

监控的目的是提前发现问题,不是出问题后才看。建好告警规则,设置合理阈值,才能真正发挥作用。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐