香港服务器磁盘故障预防与数据恢复:SMART监控 + 备份策略 + 紧急恢复实战

香港服务器磁盘故障预防与数据恢复:SMART监控 + 备份策略 + 紧急恢复实战

磁盘故障不是「会不会发生」的问题,而是「什么时候发生」。SSD 的平均无故障时间(MTTF)通常在 150 万小时以上,但电源异常、固件 Bug、过热都可能导致提前失效。本文建立一套从故障预测到数据恢复的完整防线,让数据丢失的风险降到最低。


一、SMART 监控(预测磁盘故障)

<code"># 安装 smartmontools
apt install -y smartmontools

# 查看磁盘 SMART 概览
smartctl -H /dev/sda        # 整体健康状态
smartctl -a /dev/sda        # 完整 SMART 数据

# 关键 SMART 属性解读
smartctl -A /dev/sda | grep -E "Reallocated|Pending|Uncorrectable|Temperature"

# 重要的 SMART 告警指标:
# Reallocated_Sector_Ct:重新分配扇区数(>0 是坏信号)
# Current_Pending_Sector:等待重新分配的扇区(>0 代表有读取错误)
# Offline_Uncorrectable:无法纠正的离线扇区(>0 非常危险)
# Temperature_Celsius:磁盘温度(SSD 建议 <70°C,HDD <50°C) # Power_On_Hours:通电时间(HDD >30000小时需要关注)
<code"># 配置 SMART 自动监控和告警
# /etc/smartd.conf

# 监控所有磁盘,每天检查,发现问题发邮件
DEVICESCAN -a \
  -o on \           # 开启自动离线测试
  -S on \           # 开启属性保存
  -n standby,q \    # 磁盘待机时不唤醒
  -s (S/../.././02|L/../../6/03) \   # 短测试每天2点,长测试每周六3点
  -W 4,45,55 \      # 温度预警:差值4度/45度/55度时告警
  -m admin@yourdomain.com \          # 告警邮件
  -M exec /usr/local/bin/smartd-alert.sh   # 也可以执行自定义脚本

systemctl enable --now smartd
<code"># /usr/local/bin/smartd-alert.sh(SMART 告警时发飞书通知)
#!/bin/bash
curl -s -X POST "https://open.feishu.cn/open-apis/bot/v2/hook/your_webhook" \
  -H "Content-Type: application/json" \
  -d "{
    \"msg_type\": \"text\",
    \"content\": {
      \"text\": \"🚨 磁盘健康告警\n设备:$SMARTD_DEVICE\n主机:$(hostname)\n消息:$SMARTD_MESSAGE\n时间:$(date)\"
    }
  }"
chmod +x /usr/local/bin/smartd-alert.sh

二、磁盘空间预警监控

<code"># 磁盘使用率监控脚本(每小时检查)
cat > /usr/local/bin/disk-monitor.sh << 'EOF'
#!/bin/bash
THRESHOLD=85   # 超过85%时告警
FEISHU_WEBHOOK="https://open.feishu.cn/open-apis/bot/v2/hook/your_webhook"

while read -r line; do
    use=$(echo "$line" | awk '{print $5}' | tr -d '%')
    mount=$(echo "$line" | awk '{print $6}')

    if [ "$use" -gt "$THRESHOLD" ]; then
        curl -s -X POST "$FEISHU_WEBHOOK" \
          -H "Content-Type: application/json" \
          -d "{\"msg_type\":\"text\",\"content\":{\"text\":\"⚠️ 磁盘空间告警\n服务器:$(hostname)\n挂载点:$mount\n使用率:$use%\n请及时清理!\"}}"
    fi
done < <(df -h | grep -E '^/dev/' | grep -v tmpfs) EOF chmod +x /usr/local/bin/disk-monitor.sh echo "0 * * * * /usr/local/bin/disk-monitor.sh" >> /etc/crontab

三、3-2-1 备份策略实施

<code">
3-2-1 备份黄金法则:
- 3 份数据副本(1份原始 + 2份备份)
- 2 种不同存储介质(服务器磁盘 + 外部存储)
- 1 份异地备份(不同物理位置)

实施方案(香港服务器):
副本1:生产数据库(香港服务器主磁盘)
副本2:本地备份(香港服务器 /backup 目录,每日增量)
副本3:异地备份(Cloudflare R2 或 另一地区服务器,每周全量)
<code"># 完整备份脚本(3-2-1 实施)
cat > /opt/backup/backup-all.sh << 'SCRIPT' #!/bin/bash set -euo pipefail DATE=$(date +%Y%m%d_%H%M) BACKUP_DIR="/backup" LOG="/var/log/backup.log" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; } log "开始备份..." # ── 副本2:本地备份 ── # MySQL 数据库(全量 + 压缩) log "备份 MySQL..." mkdir -p $BACKUP_DIR/mysql mysqldump \ --single-transaction \ --quick \ --all-databases \ -uroot -p"$MYSQL_ROOT_PASSWORD" \ | gzip -9 > $BACKUP_DIR/mysql/all-$DATE.sql.gz
log "MySQL 备份完成:$(du -sh $BACKUP_DIR/mysql/all-$DATE.sql.gz | cut -f1)"

# 应用文件(增量同步)
log "同步应用文件..."
rsync -av --delete \
  /var/www/ \
  $BACKUP_DIR/www/ \
  --exclude=".git" \
  --exclude="node_modules" \
  --exclude="*.log"

# 配置文件
log "备份配置文件..."
tar -czf $BACKUP_DIR/configs/config-$DATE.tar.gz \
  /etc/nginx \
  /etc/supervisor \
  /opt/*/config \
  2>/dev/null || true

# ── 副本3:异地备份(Cloudflare R2)──
# 仅在周日执行全量异地备份
if [ "$(date +%u)" -eq 7 ]; then
    log "执行异地备份到 R2..."
    /usr/local/bin/mc cp \
      $BACKUP_DIR/mysql/all-$DATE.sql.gz \
      r2/myapp-backups/mysql/

    /usr/local/bin/mc mirror \
      $BACKUP_DIR/configs/ \
      r2/myapp-backups/configs/
    log "异地备份完成"
fi

# ── 清理旧备份 ──
# 本地保留14天
find $BACKUP_DIR/mysql -name "*.sql.gz" -mtime +14 -delete
find $BACKUP_DIR/configs -name "*.tar.gz" -mtime +14 -delete

log "所有备份完成 ✓"
SCRIPT
chmod +x /opt/backup/backup-all.sh

# 每天凌晨 3 点执行
echo "0 3 * * * root /opt/backup/backup-all.sh" >> /etc/crontab

四、备份验证(最重要却最容易忽视)

<code"># 未经验证的备份等于没有备份!每周自动恢复验证
cat > /opt/backup/verify-backup.sh << 'EOF' #!/bin/bash LATEST_BACKUP=$(ls -t /backup/mysql/*.sql.gz | head -1) if [ -z "$LATEST_BACKUP" ]; then echo "错误:找不到备份文件!" | mail -s "备份验证失败" admin@yourdomain.com exit 1 fi # 在临时数据库中恢复验证 docker run --rm \ -e MYSQL_ROOT_PASSWORD=test \ -e MYSQL_DATABASE=verify_test \ -v /tmp/verify_mysql:/var/lib/mysql \ mysql:8.0 \ --daemonize --user=mysql sleep 10 zcat "$LATEST_BACKUP" | docker exec -i verify_mysql \ mysql -uroot -ptest verify_test 2>&1

# 检查关键表是否存在
TABLE_COUNT=$(docker exec verify_mysql \
  mysql -uroot -ptest verify_test -e "SHOW TABLES;" 2>/dev/null | wc -l)

if [ "$TABLE_COUNT" -gt 0 ]; then
    echo "✅ 备份验证通过!文件:$LATEST_BACKUP,表数量:$TABLE_COUNT"
else
    echo "❌ 备份验证失败!文件:$LATEST_BACKUP" | mail -s "备份验证失败" admin@yourdomain.com
fi

# 清理临时数据库
docker rm -f verify_mysql 2>/dev/null || true
rm -rf /tmp/verify_mysql
EOF
chmod +x /opt/backup/verify-backup.sh
echo "0 10 * * 0 root /opt/backup/verify-backup.sh" >> /etc/crontab   # 每周日上午10点验证

五、误删文件恢复(EXT4 文件系统)

<code"># 场景:rm -rf 误删了文件,磁盘还没有新数据覆盖

# 立即!停止对该磁盘的所有写入操作(防止覆盖)
# 如果是系统磁盘,考虑立即将服务器关机,使用恢复模式启动

# 方法一:extundelete(针对 EXT4)
apt install -y extundelete

# 先卸载分区(或使用只读方式)
umount /dev/sdb1   # 如果是数据磁盘

# 恢复所有可恢复的文件
extundelete /dev/sdb1 --restore-all

# 恢复特定文件
extundelete /dev/sdb1 --restore-file /var/www/mysite/wp-config.php

# 方法二:testdisk(更强大,也支持恢复分区)
apt install -y testdisk
testdisk /dev/sda   # 交互式界面操作

六、MySQL 误删数据恢复

<code"># 场景:执行了 DELETE FROM orders 没加 WHERE 条件

# ── 方法一:从备份恢复 ──
# 先导出备份中的 orders 表
zcat /backup/mysql/all-latest.sql.gz \
  | sed -n '/-- Table structure for table `orders`/,/-- Table structure/p' \
  > /tmp/orders-restore.sql
mysql -uroot -p mydb < /tmp/orders-restore.sql

# ── 方法二:通过 Binlog 恢复(更精确)──
# 前提:MySQL 已启用 Binlog(log_bin = ON)

# 查看可用的 Binlog 文件
mysqlbinlog --list /var/lib/mysql/mysql-bin.*

# 从特定时间点提取 SQL(删除操作发生时间 = 提取到该时间之前)
mysqlbinlog \
  --start-datetime="2026-07-28 09:00:00" \
  --stop-datetime="2026-07-28 09:30:00" \
  --database=mydb \
  /var/lib/mysql/mysql-bin.000123 \
  | grep -v "DELETE FROM orders" \
  | mysql -uroot -p mydb

# 精确定位:先找到 DELETE 操作的位置
mysqlbinlog /var/lib/mysql/mysql-bin.000123 | grep -n "DELETE FROM \`orders\`"
# 然后使用 --stop-position 参数只恢复到该位置之前

七、磁盘故障时的紧急处置流程

<code">
⚠️ 发现磁盘故障告警 → 立即行动:

T+0:确认故障严重程度
  → smartctl -H /dev/sda 查看 SMART 状态
  → dmesg | tail -50 查看内核错误日志

T+5分钟:评估数据风险
  → df -h 检查磁盘挂载状态
  → 数据库是否可以正常读写?

T+10分钟:保护现有数据
  → 立即执行完整备份(即使磁盘有问题)
  → mysqldump -uroot -p --all-databases > /tmp/emergency-backup.sql
  → rsync -avz /var/www/ root@备用服务器:/emergency-restore/

T+30分钟:评估是否需要迁移
  → 如果是 I/O 错误频繁 → 立即迁移到新服务器
  → 如果是 SMART 预警但仍可读写 → 计划维护窗口更换磁盘

T+1小时:联系 IDC 更换磁盘或申请新服务器
  → 提交工单:说明故障现象 + SMART 数据

迁移到新服务器(参考第五阶段文章13):
  → 数据库恢复 → 文件同步 → DNS 切换

八、总结

磁盘管理的核心原则:预防 → 备份 → 验证 → 恢复演练,四个环节缺一不可。SMART 监控让故障有 3~7 天的预警窗口,3-2-1 备份确保数据有多份冗余,定期验证确保备份真实可用,而恢复演练则保证真正发生故障时团队能快速行动。香港服务器用户应当将备份策略和磁盘监控作为上线第一天就要配置好的基础设施,而不是「出问题后再说」。

Telegram