# 灾备操作手册 (DR Runbook) > **文档版本**: 1.0 > **最后更新**: 2026-06-17 > **适用场景**: 生产环境故障处理 --- ## 概述 本手册提供常见故障场景的诊断和处理步骤。每个场景包含:症状、诊断、处理步骤、验证方法。 **紧急联系**: 参见 `docs/dr/dr-plan.md` 第 6 节联系人列表 --- ## 场景 1: 数据库故障 ### 1.1 数据库不可达 #### 症状 - 应用报错: `ECONNREFUSED` 或 `Connection refused` - 健康检查 `database` 状态为 `fail` - 用户无法登录、查询数据 #### 诊断 ```bash # 1. 检查数据库连接 mysql -h -P -u -p -e "SELECT 1;" # 2. 检查数据库进程 systemctl status mysql # 或 Docker 环境 docker ps | grep mysql # 3. 检查端口 telnet # 或 nc -zv # 4. 查看数据库日志 tail -100 /var/log/mysql/error.log # 或 Docker docker logs --tail 100 ``` #### 处理步骤 **情况 A: 数据库服务停止** ```bash # 重启数据库服务 sudo systemctl restart mysql # 或 Docker docker restart # 等待启动完成 sleep 10 mysql -h -P -u -p -e "SELECT 1;" ``` **情况 B: 数据库无法启动** ```bash # 1. 检查磁盘空间 df -h # 2. 检查配置文件 mysql --verbose --help | head -20 # 3. 如果磁盘满,清理空间 sudo find /var/log -type f -name "*.log" -mtime +7 -delete # 4. 如果配置错误,恢复备份配置 sudo cp /etc/mysql/my.cnf.bak /etc/mysql/my.cnf sudo systemctl restart mysql ``` **情况 C: 数据库损坏,需要从备份恢复** ```bash # 1. 获取最新备份 LATEST_BACKUP=$(ls -t backups/db_backup_*.sql.gz | head -1) echo "Using backup: $LATEST_BACKUP" # 2. 校验备份 ./scripts/backup-verify.sh "$LATEST_BACKUP" # 3. 恢复数据库 ./scripts/restore-db.sh "$LATEST_BACKUP" # 4. 重启应用 docker restart nextjs-app ``` **情况 D: 主库故障,需要切换到备库** ```bash # 1. 执行故障切换(手动模式) ./scripts/failover.sh # 2. 或半自动模式 ./scripts/failover.sh --auto # 3. 验证切换结果 ./scripts/health-check.sh ``` #### 验证 ```bash # 1. 运行健康检查 ./scripts/health-check.sh # 2. 验证应用功能 curl -f http://localhost:8015 # 3. 验证数据库查询 mysql -h -P -u -p -e "SELECT COUNT(*) FROM users;" # 4. 运行灾备演练验证数据完整性 ./scripts/dr-drill.sh ``` --- ### 1.2 数据库性能问题 #### 症状 - 应用响应缓慢 - 查询超时 - CPU/内存使用率高 #### 诊断 ```bash # 1. 查看当前连接 mysql -e "SHOW PROCESSLIST;" # 2. 查看慢查询 mysql -e "SHOW VARIABLES LIKE 'slow_query%';" tail -100 /var/log/mysql/slow.log # 3. 查看系统资源 top iostat -x 1 ``` #### 处理步骤 ```bash # 1. 终止长时间运行的查询 mysql -e "KILL ;" # 2. 优化表 mysql -e "OPTIMIZE TABLE ;" # 3. 重启数据库(如果必要) sudo systemctl restart mysql ``` #### 验证 ```bash # 监控性能指标 mysql -e "SHOW STATUS LIKE 'Threads%';" mysql -e "SHOW STATUS LIKE 'Slow_queries';" ``` --- ## 场景 2: 应用故障 ### 2.1 应用不可达 #### 症状 - HTTP 502/503 错误 - 页面无法访问 - 健康检查 `app` 状态为 `fail` #### 诊断 ```bash # 1. 检查应用容器 docker ps | grep nextjs-app # 2. 查看应用日志 docker logs nextjs-app --tail 100 # 3. 检查端口 netstat -tlnp | grep 8015 # 4. 检查健康端点 curl -v http://localhost:8015 ``` #### 处理步骤 **情况 A: 容器停止** ```bash # 启动容器 docker start nextjs-app # 等待启动 sleep 10 curl -f http://localhost:8015 ``` **情况 B: 容器崩溃,需要重启** ```bash # 重启容器 docker restart nextjs-app # 如果重启失败,重新部署 docker stop nextjs-app || true docker rm nextjs-app || true # 重新运行部署流程(参见 CI/CD) ``` **情况 C: 应用配置错误** ```bash # 1. 检查环境变量 docker exec nextjs-app env | grep DATABASE_URL # 2. 检查 .env.local cat .env.local # 3. 修正配置后重启 docker restart nextjs-app ``` #### 验证 ```bash # 1. 健康检查 ./scripts/health-check.sh # 2. 功能测试 curl -f http://localhost:8015 curl -f http://localhost:8015/api/auth/providers # 3. 查看日志确认无错误 docker logs nextjs-app --tail 20 ``` --- ### 2.2 应用 OOM(内存不足) #### 症状 - 容器被 OOM Killer 终止 - 日志中出现 `JavaScript heap out of memory` #### 诊断 ```bash # 1. 查看容器状态 docker inspect nextjs-app | grep -A 5 "State" # 2. 查看内存使用 docker stats nextjs-app # 3. 查看系统日志 dmesg | grep -i "oom" ``` #### 处理步骤 ```bash # 1. 增加 Node.js 内存限制 docker stop nextjs-app docker rm nextjs-app docker run -d \ --init \ -p 8015:3000 \ --restart unless-stopped \ --name nextjs-app \ --network 1panel-network \ -e NODE_OPTIONS="--max-old-space-size=2048" \ -e NODE_ENV=production \ -e DATABASE_URL=$DATABASE_URL \ -e NEXTAUTH_SECRET=$NEXTAUTH_SECRET \ -e NEXTAUTH_URL=$NEXTAUTH_URL \ nextjs-app # 2. 或增加容器内存限制 docker run -d --memory=2g ... ``` #### 验证 ```bash # 监控内存使用 docker stats nextjs-app # 确认应用正常 curl -f http://localhost:8015 ``` --- ## 场景 3: 备份失败 ### 3.1 定时备份未执行 #### 症状 - 健康检查 `backup` 状态为 `fail`(备份超过 24 小时) - `./backups/` 目录无新文件 - CI 中 `scheduled-backup` job 失败 #### 诊断 ```bash # 1. 检查最新备份 ls -lt backups/db_backup_*.sql.gz | head -5 # 2. 检查 CI 运行记录 # 访问 Gitea Actions 页面查看 scheduled-backup job # 3. 手动运行备份测试 ./scripts/backup-db.sh # 4. 检查磁盘空间 df -h ``` #### 处理步骤 **情况 A: 磁盘空间不足** ```bash # 1. 清理旧备份 find backups/ -name "db_backup_*.sql.gz" -mtime +30 -delete # 2. 清理其他临时文件 find /tmp -type f -mtime +7 -delete # 3. 重新运行备份 ./scripts/backup-db.sh ``` **情况 B: 数据库连接问题** ```bash # 1. 验证数据库连接 mysql -h -P -u -p -e "SELECT 1;" # 2. 检查 DATABASE_URL 环境变量 echo $DATABASE_URL # 3. 修正配置后重新备份 export DATABASE_URL="mysql://correct_url" ./scripts/backup-db.sh ``` **情况 C: mysqldump 权限问题** ```bash # 1. 检查用户权限 mysql -u -p -e "SHOW GRANTS;" # 2. 授予必要权限 mysql -u root -p -e "GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER ON *.* TO ''@'%';" FLUSH PRIVILEGES; # 3. 重新备份 ./scripts/backup-db.sh ``` #### 验证 ```bash # 1. 确认新备份存在 ls -lt backups/db_backup_*.sql.gz | head -1 # 2. 校验备份完整性 ./scripts/backup-verify.sh # 3. 运行健康检查 ./scripts/health-check.sh ``` --- ### 3.2 备份文件损坏 #### 症状 - `backup-verify.sh` 校验失败 - gzip 解压失败 - SQL 文件内容异常 #### 诊断 ```bash # 1. 运行校验脚本 ./scripts/backup-verify.sh backups/db_backup_YYYYMMDD_HHMMSS.sql.gz # 2. 手动检查 gzip gunzip -t backups/db_backup_YYYYMMDD_HHMMSS.sql.gz # 3. 检查文件大小 ls -lh backups/db_backup_*.sql.gz ``` #### 处理步骤 ```bash # 1. 删除损坏的备份 rm backups/db_backup_YYYYMMDD_HHMMSS.sql.gz # 2. 重新执行备份 ./scripts/backup-db.sh # 3. 校验新备份 ./scripts/backup-verify.sh # 4. 如果新备份也损坏,检查数据库完整性 mysql -e "CHECK TABLE users; CHECK TABLE schools;" ``` #### 验证 ```bash # 1. 校验新备份 ./scripts/backup-verify.sh # 2. 运行灾备演练 ./scripts/dr-drill.sh ``` --- ## 场景 4: 异地同步失败 ### 4.1 S3/OSS 同步失败 #### 症状 - `backup-offsite-sync.sh` 失败 - CI 中 "Sync backup to offsite storage" 步骤失败 - 异地存储缺少最新备份 #### 诊断 ```bash # 1. 检查后端配置 echo $BACKUP_OFFSITE_BACKEND echo $BACKUP_OFFSITE_REMOTE echo $BACKUP_OFFSITE_BUCKET # 2. 检查凭证 echo $BACKUP_OFFSITE_ACCESS_KEY echo $BACKUP_OFFSITE_SECRET_KEY # 3. 测试连接 aws s3 ls s3://$BACKUP_OFFSITE_BUCKET/ # S3 # 或 ossutil ls oss://$BACKUP_OFFSITE_BUCKET/ # OSS # 4. 手动运行同步 ./scripts/backup-offsite-sync.sh ``` #### 处理步骤 **情况 A: 凭证错误** ```bash # 1. 更新凭证 export BACKUP_OFFSITE_ACCESS_KEY="new_access_key" export BACKUP_OFFSITE_SECRET_KEY="new_secret_key" # 2. 更新 Gitea Secrets # 访问仓库 Settings > Secrets 更新对应 secret # 3. 重新同步 ./scripts/backup-offsite-sync.sh ``` **情况 B: 网络问题** ```bash # 1. 测试网络连通性 ping s3.amazonaws.com # S3 ping oss-cn-beijing.aliyuncs.com # OSS # 2. 检查代理设置 echo $http_proxy echo $https_proxy # 3. 配置代理后重试 export http_proxy=http://proxy:port export https_proxy=http://proxy:port ./scripts/backup-offsite-sync.sh ``` **情况 C: 工具未安装** ```bash # 1. 安装 aws-cli pip install awscli # 或 apt-get install -y awscli # 2. 安装 rclone curl https://rclone.org/install.sh | sudo bash # 3. 重新同步 ./scripts/backup-offsite-sync.sh ``` #### 验证 ```bash # 1. 列出远程文件 aws s3 ls s3://$BACKUP_OFFSITE_BUCKET/backups/ # 或 rclone lsf $BACKUP_OFFSITE_REMOTE # 2. 对比本地和远程文件数量 LOCAL_COUNT=$(ls backups/db_backup_*.sql.gz | wc -l) REMOTE_COUNT=$(aws s3 ls s3://$BACKUP_OFFSITE_BUCKET/backups/ | grep -c "db_backup") echo "Local: $LOCAL_COUNT, Remote: $REMOTE_COUNT" ``` --- ### 4.2 NFS 同步失败 #### 症状 - `backup-offsite-sync.sh` NFS 后端失败 - NFS 目录不可写 #### 诊断 ```bash # 1. 检查 NFS 挂载 mount | grep nfs # 2. 检查目录权限 ls -la $BACKUP_OFFSITE_REMOTE # 3. 测试写入 touch $BACKUP_OFFSITE_REMOTE/test && rm $BACKUP_OFFSITE_REMOTE/test ``` #### 处理步骤 ```bash # 1. 重新挂载 NFS sudo umount /mnt/nfs sudo mount -t nfs :/path /mnt/nfs # 2. 检查权限 sudo chown -R $USER:$USER /mnt/nfs/backups # 3. 重新同步 ./scripts/backup-offsite-sync.sh ``` --- ## 场景 5: 灾备演练失败 ### 5.1 演练恢复失败 #### 症状 - `dr-drill.sh` 步骤 3(恢复)失败 - 测试数据库创建成功但恢复失败 #### 诊断 ```bash # 1. 查看演练报告 cat docs/dr/reports/dr_drill_*.md # 2. 手动测试恢复 mysql -h -u -p -e "CREATE DATABASE test_manual;" gunzip -c backups/db_backup_*.sql.gz | mysql -h -u -p test_manual # 3. 检查备份文件 ./scripts/backup-verify.sh ``` #### 处理步骤 ```bash # 1. 清理失败的测试数据库 mysql -h -u -p -e "DROP DATABASE IF EXISTS next_edu_dr_drill;" # 2. 校验备份 ./scripts/backup-verify.sh # 3. 如果备份损坏,重新备份 ./scripts/backup-db.sh # 4. 重新运行演练 ./scripts/dr-drill.sh ``` --- ### 5.2 演练后测试数据库未清理 #### 症状 - `next_edu_dr_drill` 数据库残留 - 磁盘空间异常增长 #### 诊断 ```bash # 1. 检查测试数据库 mysql -e "SHOW DATABASES LIKE 'next_edu_dr_drill';" # 2. 检查数据库大小 mysql -e "SELECT table_schema, SUM(data_length + index_length) / 1024 / 1024 AS size_mb FROM information_schema.tables WHERE table_schema = 'next_edu_dr_drill' GROUP BY table_schema;" ``` #### 处理步骤 ```bash # 1. 手动删除测试数据库 mysql -h -u -p -e "DROP DATABASE IF EXISTS next_edu_dr_drill;" # 2. 验证已删除 mysql -e "SHOW DATABASES LIKE 'next_edu_dr_drill';" ``` --- ## 场景 6: 磁盘空间不足 #### 症状 - 健康检查 `disk` 状态为 `fail` - 应用或数据库写入失败 - 系统响应缓慢 #### 诊断 ```bash # 1. 检查磁盘使用 df -h # 2. 查找大文件 du -sh /* 2>/dev/null | sort -rh | head -10 du -sh /var/* 2>/dev/null | sort -rh | head -10 # 3. 查找大日志文件 find /var/log -type f -size +100M -exec ls -lh {} \; ``` #### 处理步骤 ```bash # 1. 清理旧备份 find backups/ -name "db_backup_*.sql.gz" -mtime +30 -delete # 2. 清理日志 sudo find /var/log -type f -name "*.log" -mtime +7 -delete sudo journalctl --vacuum-time=7d # 3. 清理 Docker 资源 docker system prune -a --volumes # 注意: 这会删除未使用的镜像和卷,谨慎使用 # 4. 清理 npm 缓存 npm cache clean --force # 5. 清理临时文件 find /tmp -type f -mtime +7 -delete ``` #### 验证 ```bash # 1. 检查磁盘空间 df -h # 2. 运行健康检查 ./scripts/health-check.sh ``` --- ## 附录: 快速参考命令 ### 备份相关 ```bash # 执行备份 npm run backup # 校验备份 npm run dr:backup-verify # 异地同步 npm run dr:offsite-sync # 灾备演练 npm run dr:drill # 健康检查 npm run dr:health-check ``` ### 恢复相关 ```bash # 从备份恢复 ./scripts/restore-db.sh backups/db_backup_YYYYMMDD_HHMMSS.sql.gz # 故障切换 ./scripts/failover.sh --auto ``` ### 诊断相关 ```bash # 完整健康检查 ./scripts/health-check.sh # 检查数据库 mysql -h -P -u -p -e "SHOW PROCESSLIST;" # 检查应用日志 docker logs nextjs-app --tail 100 # 检查磁盘空间 df -h ``` --- ## 变更记录 | 日期 | 版本 | 变更内容 | 变更人 | |------|------|---------|--------| | 2026-06-17 | 1.0 | 初始版本 | - |