找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

514

积分

0

好友

68

主题
发表于 前天 22:58 | 查看: 14| 回复: 0

在一次故障复盘会上,“为什么没有提前发现磁盘已满?”的质问让我意识到,被动监控告警存在盲区,主动巡检才是防患于未然的关键。经过两年打磨,这套自动化巡检脚本已每日自动检查上百台服务器,成功预警数十个潜在故障。本文将完整分享这套已在生产环境稳定运行的脚本集,助力你构建主动式运维体系。

为什么需要自动化巡检?

监控系统的局限性

尽管企业普遍部署了Zabbix、Prometheus等监控系统,但它们仍存在一些固有盲区:

  • 配置遗漏:新增的服务或服务器可能被遗忘在监控之外。
  • 阈值僵化:设置不当的告警阈值可能导致误报或漏报。
  • 渐变问题:磁盘使用率从70%缓慢增至95%,可能在触发阈值前就已构成风险。
  • 细节缺失:文件描述符耗尽、僵尸进程、特定日志错误等细粒度状态。
  • 业务逻辑盲点:进程存在但已僵死,无法响应业务请求。
  • 监控自身故障:Agent异常或网络问题可能导致监控失效。

自动化巡检的核心价值

作为监控系统的有效补充,Shell巡检脚本具备独特优势,是运维/DevOps实践中不可或缺的一环。

  1. 主动探查:系统化遍历所有关键指标,不依赖预设的告警规则。
  2. 全面覆盖:整合系统、网络、应用、日志等多维度检查。
  3. 高度定制:可根据具体业务需求灵活调整检查项。
  4. 有迹可循:生成详细的巡检报告,便于问题追溯与复盘。
  5. 成本低廉:纯Shell实现,无需部署额外的监控Agent。
  6. 离线能力:即使监控系统失效,基础巡检仍可独立工作。

7个生产级巡检脚本详解

脚本1:系统健康状态全面检查

这是最核心的巡检脚本,负责检查系统的CPU、内存、磁盘、网络等基础资源。

功能特点:

  • 全面检查系统核心资源使用情况。
  • 自动告警异常指标,支持彩色输出。
  • 生成包含时间戳的详细巡检报告。
  • 所有告警阈值均可配置。
#!/bin/bash
################################################################################
# 脚本名称: system_health_check.sh
# 功能描述: 系统健康状态全面检查
# 版本信息: v2.0
################################################################################
# 配置区域
HOSTNAME=$(hostname)
DATE=$(date "+%Y-%m-%d %H:%M:%S")
REPORT_FILE="/var/log/system_check_$(date +%Y%m%d_%H%M%S).log"
# 告警阈值配置
CPU_WARNING=80          # CPU使用率告警阈值(%)
MEM_WARNING=85          # 内存使用率告警阈值(%)
DISK_WARNING=85         # 磁盘使用率告警阈值(%)
LOAD_WARNING=4          # 系统负载告警阈值(根据CPU核心数调整)
INODE_WARNING=80        # Inode使用率告警阈值(%)
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 日志函数
log() {
    echo "[$(date +\"%Y-%m-%d %H:%M:%S\")] $1" | tee -a "$REPORT_FILE"
}
log_section() {
    echo "" | tee -a "$REPORT_FILE"
    echo "============================================================" | tee -a "$REPORT_FILE"
    echo " $1" | tee -a "$REPORT_FILE"
    echo "============================================================" | tee -a "$REPORT_FILE"
}
log_warning() {
    echo -e "${YELLOW}[WARNING] $1${NC}" | tee -a "$REPORT_FILE"
}
log_error() {
    echo -e "${RED}[ERROR] $1${NC}" | tee -a "$REPORT_FILE"
}
log_ok() {
    echo -e "${GREEN}[OK] $1${NC}" | tee -a "$REPORT_FILE"
}
# 1. 基本信息收集
check_basic_info() {
    log_section "1. 系统基本信息"
    log "主机名: $HOSTNAME"
    log "检查时间: $DATE"
    log "系统版本: $(cat /etc/redhat-release 2>/dev/null || cat /etc/issue | head -1)"
    log "内核版本: $(uname -r)"
    log "系统架构: $(uname -m)"
    log "运行时长: $(uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}')"
    log "当前用户: $(whoami)"
    log "登录用户数: $(who | wc -l)"
}
# 2. CPU使用率检查
check_cpu() {
    log_section "2. CPU使用率检查"
    # 获取CPU核心数
    CPU_CORES=$(grep -c ^processor /proc/cpuinfo)
    log "CPU核心数: $CPU_CORES"
    # 获取CPU使用率(取5秒平均值)
    CPU_IDLE=$(top -bn2 -d 1 | grep "Cpu(s)" | tail -1 | awk '{print $8}' | cut -d'%' -f1)
    CPU_USAGE=$(echo "scale=2; 100 - $CPU_IDLE" | bc)
    log "CPU使用率: ${CPU_USAGE}%"
    if (( $(echo "$CPU_USAGE > $CPU_WARNING" | bc -l) )); then
        log_warning "CPU使用率超过${CPU_WARNING}%,当前${CPU_USAGE}%"
        # 显示CPU占用最高的5个进程
        log "TOP 5 CPU消耗进程:"
        ps aux | sort -rn -k3 | head -5 | awk '{printf "  PID: %-8s User: %-10s CPU: %-6s CMD: %s\n", $2,$1,$3,$11}' | tee -a "$REPORT_FILE"
    else
        log_ok "CPU使用率正常: ${CPU_USAGE}%"
    fi
    # 检查系统负载
    LOAD_1=$(uptime | awk -F'load average:' '{print $2}' | awk -F',' '{print $1}' | xargs)
    LOAD_5=$(uptime | awk -F'load average:' '{print $2}' | awk -F',' '{print $2}' | xargs)
    LOAD_15=$(uptime | awk -F'load average:' '{print $2}' | awk -F',' '{print $3}' | xargs)
    log "系统负载: 1分钟=${LOAD_1}, 5分钟=${LOAD_5}, 15分钟=${LOAD_15}"
    # 负载告警(1分钟负载超过CPU核心数的2倍)
    LOAD_THRESHOLD=$(echo "$CPU_CORES * 2" | bc)
    if (( $(echo "$LOAD_1 > $LOAD_THRESHOLD" | bc -l) )); then
        log_warning "系统负载过高! 1分钟负载${LOAD_1}超过阈值${LOAD_THRESHOLD}"
    fi
}
# 3. 内存使用检查
check_memory() {
    log_section "3. 内存使用检查"
    # 获取内存信息(兼容不同Linux版本)
    MEM_TOTAL=$(free -m | awk 'NR==2{print $2}')
    MEM_USED=$(free -m | awk 'NR==2{print $3}')
    MEM_FREE=$(free -m | awk 'NR==2{print $4}')
    MEM_AVAILABLE=$(free -m | awk 'NR==2{print $7}')
    # 计算使用率
    MEM_USAGE=$(echo "scale=2; $MEM_USED / $MEM_TOTAL * 100" | bc)
    log "内存总量: ${MEM_TOTAL}MB"
    log "已用内存: ${MEM_USED}MB"
    log "可用内存: ${MEM_AVAILABLE}MB"
    log "内存使用率: ${MEM_USAGE}%"
    if (( $(echo "$MEM_USAGE > $MEM_WARNING" | bc -l) )); then
        log_warning "内存使用率超过${MEM_WARNING}%,当前${MEM_USAGE}%"
        # 显示内存占用最高的5个进程
        log "TOP 5 内存消耗进程:"
        ps aux | sort -rn -k4 | head -5 | awk '{printf "  PID: %-8s User: %-10s MEM: %-6s CMD: %s\n", $2,$1,$4,$11}' | tee -a "$REPORT_FILE"
    else
        log_ok "内存使用率正常: ${MEM_USAGE}%"
    fi
    # Swap检查
    SWAP_TOTAL=$(free -m | awk 'NR==3{print $2}')
    SWAP_USED=$(free -m | awk 'NR==3{print $3}')
    log "Swap总量: ${SWAP_TOTAL}MB"
    log "Swap使用: ${SWAP_USED}MB"
    if [ "$SWAP_TOTAL" -gt 0 ] && [ "$SWAP_USED" -gt 100 ]; then
        log_warning "Swap使用量较高: ${SWAP_USED}MB, 可能存在内存压力"
    fi
}
# 4. 磁盘使用检查
check_disk() {
    log_section "4. 磁盘使用检查"
    # 检查各分区使用率
    log "磁盘分区使用情况:"
    df -h | grep -vE '^Filesystem|tmpfs|cdrom|loop' | awk '{print "  " $0}' | tee -a "$REPORT_FILE"
    # 告警检查
    HAS_DISK_WARNING=0
    while read line; do
        USAGE=$(echo $line | awk '{print $5}' | sed 's/%//')
        MOUNT=$(echo $line | awk '{print $6}')
        if [ "$USAGE" -gt "$DISK_WARNING" ]; then
            log_warning "磁盘分区 $MOUNT 使用率${USAGE}%超过阈值${DISK_WARNING}%"
            HAS_DISK_WARNING=1
            # 显示该分区最大的5个目录
            log "  $MOUNT 分区占用空间最大的5个目录:"
            du -sh ${MOUNT}/* 2>/dev/null | sort -rh | head -5 | awk '{print "    " $0}' | tee -a "$REPORT_FILE"
        fi
    done < <(df -h | grep -vE '^Filesystem|tmpfs|cdrom|loop')
    if [ $HAS_DISK_WARNING -eq 0 ]; then
        log_ok "所有磁盘分区使用率正常"
    fi
    # Inode使用率检查
    log ""
    log "Inode使用情况:"
    df -i | grep -vE '^Filesystem|tmpfs|cdrom|loop' | awk '{print "  " $0}' | tee -a "$REPORT_FILE"
    while read line; do
        INODE_USAGE=$(echo $line | awk '{print $5}' | sed 's/%//')
        MOUNT=$(echo $line | awk '{print $6}')
        if [ "$INODE_USAGE" -gt "$INODE_WARNING" ]; then
            log_warning "分区 $MOUNT 的Inode使用率${INODE_USAGE}%超过阈值${INODE_WARNING}%"
        fi
    done < <(df -i | grep -vE '^Filesystem|tmpfs|cdrom|loop')
}
# 5. 网络状态检查
check_network() {
    log_section "5. 网络状态检查"
    # 网络接口状态
    log "网络接口状态:"
    ip -br addr | awk '{print "  " $0}' | tee -a "$REPORT_FILE"
    # 网络连接统计
    log ""
    log "TCP连接状态统计:"
    netstat -an | awk '/^tcp/ {print $6}' | sort | uniq -c | sort -rn | awk '{print "  " $0}' | tee -a "$REPORT_FILE"
    # 检查TIME_WAIT过多
    TIME_WAIT_COUNT=$(netstat -an | grep TIME_WAIT | wc -l)
    log "TIME_WAIT连接数: $TIME_WAIT_COUNT"
    if [ "$TIME_WAIT_COUNT" -gt 5000 ]; then
        log_warning "TIME_WAIT连接数过多: $TIME_WAIT_COUNT"
    fi
    # 监听端口检查
    log ""
    log "当前监听端口:"
    netstat -tuln | grep LISTEN | awk '{print "  " $0}' | tee -a "$REPORT_FILE"
}
# 6. 进程和服务检查
check_processes() {
    log_section "6. 进程和服务检查"
    # 总进程数
    PROCESS_COUNT=$(ps aux | wc -l)
    log "当前进程总数: $PROCESS_COUNT"
    # 僵尸进程检查
    ZOMBIE_COUNT=$(ps aux | awk '{print $8}' | grep -c Z)
    log "僵尸进程数: $ZOMBIE_COUNT"
    if [ "$ZOMBIE_COUNT" -gt 0 ]; then
        log_warning "发现僵尸进程!"
        ps aux | grep 'Z' | grep -v grep | awk '{print "  PID: " $2 " PPID: " $3 " CMD: " $11}' | tee -a "$REPORT_FILE"
    fi
    # 检查关键服务(根据实际业务调整)
    log ""
    log "关键服务状态检查:"
    # 定义需要检查的服务列表
    CRITICAL_SERVICES=("sshd" "crond" "rsyslog")
    for service in "${CRITICAL_SERVICES[@]}"; do
        if systemctl is-active --quiet $service 2>/dev/null; then
            log_ok "  $service: 运行中"
        else
            # 兼容非systemd系统
            if ps aux | grep -v grep | grep -q $service; then
                log_ok "  $service: 运行中"
            else
                log_error "  $service: 未运行"
            fi
        fi
    done
}
# 7. 系统日志检查
check_logs() {
    log_section "7. 系统日志检查"
    # 检查最近的错误日志
    log "最近1小时系统错误日志:"
    if [ -f /var/log/messages ]; then
        ERROR_COUNT=$(grep -i "error\|fail\|critical" /var/log/messages | tail -20 | wc -l)
        if [ "$ERROR_COUNT" -gt 0 ]; then
            log_warning "发现 $ERROR_COUNT 条错误日志"
            grep -i "error\|fail\|critical" /var/log/messages | tail -10 | awk '{print "  " $0}' | tee -a "$REPORT_FILE"
        else
            log_ok "无严重错误日志"
        fi
    fi
    # OOM检查
    log ""
    log "OOM(内存溢出)检查:"
    OOM_COUNT=$(dmesg | grep -i "out of memory" | wc -l)
    if [ "$OOM_COUNT" -gt 0 ]; then
        log_warning "发现 $OOM_COUNT 次OOM事件"
        dmesg | grep -i "out of memory" | tail -5 | awk '{print "  " $0}' | tee -a "$REPORT_FILE"
    else
        log_ok "无OOM事件"
    fi
}
# 8. 生成巡检报告摘要
generate_summary() {
    log_section "8. 巡检报告摘要"
    # 统计告警和错误
    WARNING_COUNT=$(grep -c "\[WARNING\]" "$REPORT_FILE")
    ERROR_COUNT=$(grep -c "\[ERROR\]" "$REPORT_FILE")
    log "巡检完成时间: $(date +\"%Y-%m-%d %H:%M:%S\")"
    log "告警数量: $WARNING_COUNT"
    log "错误数量: $ERROR_COUNT"
    if [ "$ERROR_COUNT" -gt 0 ]; then
        log_error "发现 $ERROR_COUNT 个严重问题,请立即处理!"
    elif [ "$WARNING_COUNT" -gt 0 ]; then
        log_warning "发现 $WARNING_COUNT 个告警,建议关注"
    else
        log_ok "系统状态良好,无异常"
    fi
    log ""
    log "完整报告已保存至: $REPORT_FILE"
}
# 主函数
main() {
    echo "=========================================="
    echo "    服务器健康状态巡检脚本 v2.0"
    echo "=========================================="
    echo ""
    # 检查是否为root用户
    if [ "$(id -u)" -ne 0 ]; then
        echo "警告: 非root用户运行,部分检查可能无法执行"
    fi
    # 执行所有检查
    check_basic_info
    check_cpu
    check_memory
    check_disk
    check_network
    check_processes
    check_logs
    generate_summary
    echo ""
    echo "=========================================="
    echo "    巡检完成!"
    echo "=========================================="
}
# 脚本入口
main "$@"

使用方法:

# 赋予执行权限
chmod +x system_health_check.sh
# 手动执行
./system_health_check.sh
# 定时执行(例如,每天早上8点)
echo "0 8 * * * /path/to/system_health_check.sh" | crontab -

脚本2:磁盘空间深度检查

此脚本专注于磁盘空间的详细分析,能快速定位空间占用的“元凶”。 核心功能:

  • 检查所有分区的磁盘及Inode使用率。
  • 自动分析各分区占用空间最大的目录和文件。
  • 检测大文件及日志增长情况。
  • 提供具体的磁盘清理建议。

脚本3:网络连接和端口检查

专门用于检查网络状态、连接数、端口监听情况及连通性。 核心功能:

  • 检查网络接口状态与统计信息(丢包、错误)。
  • 统计TCP连接各状态数量,识别TIME_WAIT过多等问题。
  • 验证关键端口监听状态。
  • 测试网络连通性(DNS、网关、外网)。

脚本4:应用进程健康检查

检查关键业务进程的运行状态、资源占用及HTTP接口响应。 核心功能:

  • 检查预设关键进程是否存在、是否为僵尸进程。
  • 监控进程的CPU、内存、线程数、文件描述符使用情况。
  • 验证进程监听的端口状态。
  • 对配置的HTTP接口进行可用性及响应时间检查。

脚本5:安全基线检查

检查服务器的安全配置,符合安全运维最佳实践。 核心功能:

  • 账户安全检查(空密码、UID为0的账户、sudo权限)。
  • SSH服务安全配置审计(Root登录、密码认证、端口等)。
  • 关键系统文件权限检查。
  • 防火墙及SELinux状态检查。
  • 系统更新情况核查。

脚本6:数据库健康检查(MySQL)

专门检查MySQL数据库的运行状态、性能指标和配置。 核心功能:

  • 数据库连接与基础信息检查。
  • 连接数使用情况与性能分析(QPS、TPS)。
  • InnoDB存储引擎状态检查(缓冲池命中率等)。
  • 主从复制状态监控。
  • 表空间使用情况分析。

脚本7:批量服务器巡检调度器

这是一个管理脚本,可并发对多台服务器执行巡检并汇总结果,是实现运维/DevOps自动化的重要工具。 核心功能:

  • 通过SSH并发在多台服务器上执行指定的巡检脚本。
  • 收集各服务器的巡检结果并生成统一的HTML汇总报告。
  • 支持自定义并发数,避免对目标服务器造成过大压力。
  • 可扩展集成邮件通知等功能。

servers.txt示例:

# Web服务器
192.168.1.10
192.168.1.11
192.168.1.12
# 应用服务器
192.168.1.20
192.168.1.21
# 数据库服务器
192.168.1.30
192.168.1.31

最佳实践与注意事项

1. 巡检频率建议

场景 推荐频率 主要脚本
日常健康检查 每天1次(如早8点) 脚本1
磁盘空间监控 每天1次 脚本2
网络状态检查 每周1次 脚本3
进程健康检查 每小时1次(针对核心业务) 脚本4
安全基线检查 每周1次 脚本5
数据库健康检查 每天1次 脚本6
重大活动保障 每5-15分钟(密集巡检) 脚本1,4,6

2. 告警阈值调优

  • 初始阶段:使用脚本内提供的保守默认阈值(如CPU>80%),并收集1-2周的基线数据。
  • 调优阶段:根据实际业务波动范围调整阈值,避免“狼来了”效应,更加关注指标的趋势性变化。

3. 巡检报告管理

  • 定期清理:使用find命令自动清理过期报告,例如find /var/log -name "system_check_*.log" -mtime +30 -delete
  • 报告分析:建立周报/月报制度,定期复盘巡检发现的问题,将趋势性问题(如磁盘使用率持续上升)纳入改进计划。

4. 与监控系统集成

巡检脚本应与现有的数据库/中间件监控体系(如Zabbix、Prometheus)形成互补,而非替代。例如,可以将巡检结果转换为JSON格式,通过API推送至监控平台,或在监控大屏上统一展示巡检状态,实现更立体的运维监控。

5. 实施路线图建议

  • 第一阶段(1-2周):在测试环境部署脚本1,验证效果并调整阈值,建立初步的巡检流程。
  • 第二阶段(2-4周):在生产环境全量部署基础健康检查脚本,并根据业务特点引入其他专项检查脚本。
  • 第三阶段(1-2个月):部署批量巡检调度器,建立完整的报告分析、问题跟踪与处理闭环流程。

总结

本文提供的7个Shell脚本构成了一个从基础到专项、从单点到批量的服务器自动化巡检工具箱。它们覆盖了系统资源、磁盘、网络、进程、安全及数据库等核心维度。通过将这些脚本与定时任务、批量调度相结合,可以高效构建起主动式的运维巡检体系,从而将运维人员从重复的手工检查中解放出来,更专注于故障预防与性能优化,真正实现从“被动救火”到“主动运维”的转变。所有脚本均可直接复用,建议根据实际业务场景进行必要的定制化调整。




上一篇:K8s持久化存储核心实战:Volume、PV、PVC与StorageClass配置与避坑指南
下一篇:Hystrix与Sentinel深度对比:动态熔断配置实战指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-8 07:59 , Processed in 0.102962 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表