服务器资源监控与容量规划实战

2026年01月20日/ 浏览 12

前言

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

扩容原则

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

总结

监控体系搭建建议

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

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

picture loss