← 返回主页
案例 01
多服务器健康检查巡检脚本

背景描述

运维团队每天需巡检 80+ 台服务器(CPU/内存/磁盘/服务),手工登录逐台检查耗时 3 小时。需开发一键巡检脚本,自动生成巡检报告。

解决方案

编写 Shell 脚本,通过 SSH 批量执行命令采集指标,汇总后生成带颜色标记的 HTML 巡检报告,异常项红色高亮。接入 Cron 每天 7:00 自动执行并邮件发送。

技术要点

  • SSH 免密 + 并发执行(& + wait)加快巡检速度
  • 关键指标采集:CPU 使用率、内存、磁盘、系统负载、关键进程存活
  • HTML 报告:正常绿色、警告黄色、异常红色
  • 异常项自动触发告警通知
#!/bin/bash # 服务器巡检脚本 health_check.sh HOSTS=($(cat /etc/hosts_list)) REPORT="/tmp/health_report_$(date +%Y%m%d).html" echo "服务器巡检报告" > $REPORT echo "

服务器巡检报告 - $(date '+%Y-%m-%d %H:%M')

" >> $REPORT echo "" >> $REPORT check_host() { local host=$1 local result=$(ssh -o ConnectTimeout=5 $host " cpu=\$(top -bn1 | grep 'Cpu' | awk '{print 100-\$8}') mem=\$(free | grep Mem | awk '{printf \"%.1f\", \$3/\$2*100}') disk=\$(df -h / | tail -1 | awk '{print \$5}' | tr -d '%') load=\$(uptime | awk -F'load average:' '{print \$2}') echo \"\$cpu|\$mem|\$disk|\$load\" " 2>/dev/null) if [ -z "$result" ]; then echo "" return fi IFS='|' read -r cpu mem disk load <<< "$result" color_cpu=""; color_mem=""; color_disk="" [ $(echo "$cpu > 80" | bc) -eq 1 ] && color_cpu="red" [ $(echo "$mem > 85" | bc) -eq 1 ] && color_mem="red" [ $disk -gt 85 ] && color_disk="red" echo "" } # 并发巡检(每次 10 台并行) for ((i=0; i<${#HOSTS[@]}; i+=10)); do for ((j=i; j> $REPORT & done wait done echo "
主机CPU%内存%磁盘%负载
$host连接失败
$host ${cpu}% ${mem}% ${disk}% ${load}
" >> $REPORT echo "报告已生成: $REPORT"
案例 02
MySQL 自动备份与异地传输脚本

背景描述

某电商数据库每日数据增量约 20GB,需实现全量备份(每周)+ 增量备份(每日),并自动传输到异地机房。原备份脚本不稳定,经常遗漏备份。

解决方案

使用 XtraBackup 做全量 + 增量备份(比 mysqldump 快 10 倍),rsync 增量传输到异地。脚本内置完整性校验(MD5)、失败重试、告警通知。Cron 定时调度。

技术要点

  • XtraBackup 在线热备,不锁表,适合大型数据库
  • 增量备份基于 LSN(日志序列号),增量仅备份变化数据
  • rsync -avzP --checksum 传输后校验文件完整性
  • 备份保留策略:本地保留 7 天,异地保留 30 天
#!/bin/bash # MySQL 备份脚本 mysql_backup.sh set -e BACKUP_BASE="/backup/mysql" REMOTE="backup@192.168.100.10:/backup/remote" DATE=$(date +%Y%m%d) WEEKDAY=$(date +%u) LOG_FILE="/var/log/mysql_backup.log" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a $LOG_FILE; } # 全量备份(每周日)或增量备份 if [ "$WEEKDAY" -eq 7 ]; then log "执行全量备份..." rm -rf $BACKUP_BASE/full_* FULL_DIR="$BACKUP_BASE/full_$DATE" xtrabackup --backup --target-dir=$FULL_DIR \ --user=backup --password= --socket=/var/lib/mysql/mysql.sock LAST_FULL=$FULL_DIR else log "执行增量备份..." LAST_FULL=$(ls -d $BACKUP_BASE/full_* 2>/dev/null | tail -1) [ -z "$LAST_FULL" ] && { log "ERROR: 无全量备份,跳过增量"; exit 1; } INC_DIR="$BACKUP_BASE/inc_${DATE}_based_$(basename $LAST_FULL)" xtrabackup --backup --target-dir=$INC_DIR \ --incremental-basedir=$LAST_FULL \ --user=backup --password= fi # 校验 + 传输 log "开始异地传输..." rsync -avzP --checksum --delete $BACKUP_BASE/ $REMOTE/ # 清理过期备份 find $BACKUP_BASE -maxdepth 1 -type d -name "full_*" -mtime +30 -exec rm -rf {} \; find $BACKUP_BASE -maxdepth 1 -type d -name "inc_*" -mtime +7 -exec rm -rf {} \; log "备份完成"
案例 03
日志分析告警脚本 — Nginx 错误率监控

背景描述

某站点偶尔出现 5xx 错误,团队希望能及时发现并告警。Prometheus 尚未部署,需要先用 Shell 脚本快速实现 Nginx 日志分析和告警。

解决方案

编写 Shell 脚本,每分钟分析 /var/log/nginx/access.log → 统计 5xx 错误比例 → 超过 5% 阈值自动发送钉钉/邮件告警。使用文件偏移量记录避免重复分析。

技术要点

  • 使用 tail -c +$offset 从上次读取位置继续,避免全量扫描
  • 5xx 错误率 = 5xx 数量 / 总请求数 × 100%
  • 告警收敛:同一告警 15 分钟内不重复发送
  • 钉钉 Webhook 机器人发送 Markdown 格式告警
#!/bin/bash # Nginx 5xx 监控脚本 nginx_5xx_monitor.sh ACCESS_LOG="/var/log/nginx/access.log" OFFSET_FILE="/tmp/nginx_log_offset" THRESHOLD=5 # 5xx 比例阈值(%) DINGTALK_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=" # 获取上次读取位置 if [ -f "$OFFSET_FILE" ]; then OFFSET=$(cat $OFFSET_FILE) else OFFSET=$(wc -c < $ACCESS_LOG) fi # 读取新增日志 NEW_SIZE=$(wc -c < $ACCESS_LOG) if [ $NEW_SIZE -le $OFFSET ]; then exit 0 # 没有新日志 fi tail -c +$((OFFSET+1)) $ACCESS_LOG > /tmp/nginx_new.log echo $NEW_SIZE > $OFFSET_FILE # 统计 TOTAL=$(wc -l < /tmp/nginx_new.log) ERR_5XX=$(awk '$9 ~ /^5[0-9]{2}$/' /tmp/nginx_new.log | wc -l) if [ $TOTAL -gt 0 ]; then ERR_RATE=$(awk "BEGIN {printf \"%.2f\", ($ERR_5XX/$TOTAL)*100}") else ERR_RATE=0 fi # 超过阈值发送告警 if [ $(echo "$ERR_RATE > $THRESHOLD" | bc) -eq 1 ]; then # 告警收敛:15 分钟内不重复 LOCK_FILE="/tmp/nginx_5xx_last_alert" if [ -f $LOCK_FILE ] && [ $(($(date +%s) - $(cat $LOCK_FILE))) -lt 900 ]; then exit 0 fi date +%s > $LOCK_FILE curl -s $DINGTALK_WEBHOOK -H "Content-Type: application/json" -d "{ \"msgtype\": \"markdown\", \"markdown\": { \"title\": \"Nginx 5xx 告警\", \"text\": \"## Nginx 5xx 告警\n> 错误率: **${ERR_RATE}%**\n> 错误数: ${ERR_5XX}/${TOTAL}\n> 时间: $(date '+%Y-%m-%d %H:%M:%S')\" } }" fi