feat(P2): 实现质量保障类5项功能(无障碍/视觉回归/通知渠道/漏洞扫描/灾备)
## 新增功能 ### 1. 屏幕阅读器兼容性增强(a11y) - 无障碍工具库:src/shared/lib/a11y.ts - aria-live Hook:src/shared/hooks/use-aria-live.ts - a11y 组件:skip-link/visually-hidden/focus-trap/aria-status - 增强 UI:table.tsx 系统性 ARIA role,dialog.tsx aria-modal - 审计文档:docs/accessibility/a11y-audit.md(WCAG 2.1 AA 清单) ### 2. 视觉回归测试 - 测试套件:tests/visual/(homepage + 3 个 dashboard) - 3 视口(desktop/tablet/mobile)× 2 主题(light/dark) - 动态元素遮罩,避免误报 - playwright.config.ts 新增 visual-chromium 项目 - 文档:docs/testing/visual-regression.md ### 3. 短信/微信推送渠道集成 - 新模块:src/modules/notifications/ - 4 个渠道:SMS(阿里云/腾讯云)、WeChat(公众号)、Email(SMTP)、In-App - 分发器按用户偏好并行多渠道发送 - 外部 SDK 动态 import,Mock 模式开发可用 - 文档:docs/notifications/channels.md ### 4. 漏洞扫描 CI 集成 - CI security-scan job:npm audit + Snyk + Trivy FS + OWASP ZAP - 独立工作流 security.yml:每周一深度扫描 + 容器镜像扫描 - 配置:suppressions.json + .trivyignore - 本地脚本:security-scan.sh/ps1 - 文档:docs/security/scanning.md(SLA 分级) ### 5. 灾备方案 - 脚本:backup-verify/backup-offsite-sync/dr-drill/failover/health-check - CI 增强:备份后校验+异地同步,每周灾备演练 - 独立工作流 dr-drill.yml:每周一凌晨 4 点自动演练 - 文档:docs/dr/dr-plan.md(RTO 4h/RPO 24h)+ dr-runbook.md(6 故障场景) ## 验证 - npx tsc --noEmit:0 错误 - npm run lint:0 错误 0 警告
This commit is contained in:
362
docs/dr/dr-plan.md
Normal file
362
docs/dr/dr-plan.md
Normal file
@@ -0,0 +1,362 @@
|
||||
# 灾备计划 (Disaster Recovery Plan)
|
||||
|
||||
> **文档版本**: 1.0
|
||||
> **最后更新**: 2026-06-17
|
||||
> **审核周期**: 每季度审核一次
|
||||
|
||||
---
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本文档定义了 Next_Edu 系统的灾备策略、恢复目标、备份方案和故障切换流程,确保在发生灾难性故障时能够快速恢复服务并最小化数据丢失。
|
||||
|
||||
### 1.1 适用范围
|
||||
|
||||
- 生产环境数据库(MySQL)
|
||||
- 应用服务(Next.js)
|
||||
- 备份文件(本地 + 异地)
|
||||
- CI/CD 流水线
|
||||
|
||||
### 1.2 关键指标
|
||||
|
||||
| 指标 | 目标 | 说明 |
|
||||
|------|------|------|
|
||||
| **RTO** (Recovery Time Objective) | 4 小时 | 从故障发生到服务恢复的最长时间 |
|
||||
| **RPO** (Recovery Point Objective) | 24 小时 | 最大可接受的数据丢失时间窗口 |
|
||||
|
||||
---
|
||||
|
||||
## 2. RTO/RPO 定义
|
||||
|
||||
### 2.1 RTO(恢复时间目标): 4 小时
|
||||
|
||||
**定义**: 从系统故障发生到服务完全恢复的最长允许时间。
|
||||
|
||||
**分解**:
|
||||
| 阶段 | 预计耗时 | 说明 |
|
||||
|------|---------|------|
|
||||
| 故障检测 | 5 分钟 | 健康检查脚本自动检测 |
|
||||
| 通知与决策 | 15 分钟 | 通知运维团队,决定是否切换 |
|
||||
| 执行恢复 | 60 分钟 | 从备份恢复数据库 |
|
||||
| 应用重启 | 10 分钟 | 重启应用并验证 |
|
||||
| 数据验证 | 30 分钟 | 验证数据完整性 |
|
||||
| 流量恢复 | 10 分钟 | 逐步恢复用户流量 |
|
||||
| 缓冲时间 | 90 分钟 | 应对意外情况 |
|
||||
| **总计** | **≤ 4 小时** | |
|
||||
|
||||
### 2.2 RPO(恢复点目标): 24 小时
|
||||
|
||||
**定义**: 最大可接受的数据丢失时间窗口。
|
||||
|
||||
**保障措施**:
|
||||
- 每日凌晨 2 点全量备份(cron: `0 2 * * *`)
|
||||
- 备份后自动校验完整性
|
||||
- 备份后自动同步到异地存储
|
||||
- 最坏情况下丢失不超过 24 小时数据
|
||||
|
||||
---
|
||||
|
||||
## 3. 备份策略
|
||||
|
||||
### 3.1 备份频率
|
||||
|
||||
| 备份类型 | 频率 | 时间 | 保留期 |
|
||||
|---------|------|------|--------|
|
||||
| 全量备份 | 每日 | 凌晨 2:00 (CST) | 本地 30 天,异地 90 天 |
|
||||
| 异地同步 | 每日(备份后) | 凌晨 2:30 (CST) | 90 天 |
|
||||
|
||||
### 3.2 备份内容
|
||||
|
||||
- **数据库**: 使用 `mysqldump` 导出全部数据库,`gzip` 压缩
|
||||
- **格式**: `db_backup_YYYYMMDD_HHMMSS.sql.gz`
|
||||
- **存储位置**:
|
||||
- 本地: `./backups/`
|
||||
- 异地: S3/OSS/NFS(根据 `BACKUP_OFFSITE_BACKEND` 配置)
|
||||
|
||||
### 3.3 备份验证
|
||||
|
||||
每次备份后自动执行校验:
|
||||
1. 文件存在性检查
|
||||
2. 文件大小检查(最小 1KB)
|
||||
3. gzip 完整性校验(`gunzip -t`)
|
||||
4. SQL 内容结构检查(mysqldump 头部、语句数量)
|
||||
5. SQL 语法校验(可选,需 `DATABASE_URL`)
|
||||
|
||||
### 3.4 备份保留策略
|
||||
|
||||
| 存储位置 | 保留期 | 清理方式 |
|
||||
|---------|--------|---------|
|
||||
| 本地 (`./backups/`) | 30 天 | `find -mtime +30 -delete` |
|
||||
| 异地 (S3/OSS/NFS) | 90 天 | `backup-offsite-sync.sh` 自动清理 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 故障切换流程
|
||||
|
||||
### 4.1 故障检测
|
||||
|
||||
1. **自动检测**: `health-check.sh` 定期运行,检查:
|
||||
- 应用 HTTP 健康端点
|
||||
- 数据库连接
|
||||
- 磁盘空间
|
||||
- 备份新鲜度
|
||||
2. **手动报告**: 用户反馈、监控系统告警
|
||||
|
||||
### 4.2 故障切换步骤
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ 1. 检测故障 │ 健康检查失败 / 用户报告
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ 2. 通知运维 │ 电话/邮件/即时通讯通知运维团队
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ 3. 决策(5分钟) │ 评估故障严重程度,决定是否切换
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌────┴────┐
|
||||
│ │
|
||||
切换 不切换
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────┐ ┌─────────┐
|
||||
│4. 执行 │ │ 修复主库 │
|
||||
│ 切换 │ │ │
|
||||
└────┬────┘ └─────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────┐
|
||||
│5. 验证 │ 健康检查、功能测试
|
||||
│ 恢复 │
|
||||
└────┬────┘
|
||||
│
|
||||
▼
|
||||
┌─────────┐
|
||||
│6. 事后 │ 记录事件、复盘改进
|
||||
│ 复盘 │
|
||||
└─────────┘
|
||||
```
|
||||
|
||||
### 4.3 执行故障切换
|
||||
|
||||
使用 `failover.sh` 脚本:
|
||||
|
||||
```bash
|
||||
# 手动模式(交互式确认)
|
||||
./scripts/failover.sh
|
||||
|
||||
# 半自动模式(检测到故障后自动切换,需确认)
|
||||
./scripts/failover.sh --auto
|
||||
|
||||
# 演练模式(不实际执行)
|
||||
./scripts/failover.sh --dry-run
|
||||
|
||||
# 指定备库
|
||||
./scripts/failover.sh --standby "mysql://user:pass@standby-host:3306/dbname"
|
||||
```
|
||||
|
||||
**前提条件**:
|
||||
- 配置 `DATABASE_URL_STANDBY` 环境变量
|
||||
- 备库已配置主从复制(如果是主从架构)
|
||||
- 应用容器可通过 Docker 重启
|
||||
|
||||
---
|
||||
|
||||
## 5. 灾备演练
|
||||
|
||||
### 5.1 演练频率
|
||||
|
||||
| 演练类型 | 频率 | 触发方式 |
|
||||
|---------|------|---------|
|
||||
| 自动演练 | 每周一次 | CI 定时任务(每周一凌晨 4 点) |
|
||||
| 手动演练 | 每月一次 | 运维人员手动触发 |
|
||||
| 全量演练 | 每季度一次 | 完整故障切换演练 |
|
||||
|
||||
### 5.2 演练内容
|
||||
|
||||
1. **创建测试数据库** (`next_edu_dr_drill`)
|
||||
2. **从最新备份恢复** 到测试数据库
|
||||
3. **数据完整性检查**:
|
||||
- 表数量对比(测试库 vs 源库)
|
||||
- 记录数对比
|
||||
4. **冒烟测试**:
|
||||
- 基础表查询
|
||||
- 关键业务表查询(users, schools)
|
||||
5. **清理测试数据库**
|
||||
6. **生成演练报告**
|
||||
|
||||
### 5.3 演练脚本
|
||||
|
||||
```bash
|
||||
# Bash 版本(Linux/macOS)
|
||||
./scripts/dr-drill.sh
|
||||
|
||||
# PowerShell 版本(Windows)
|
||||
.\scripts\dr-drill.ps1
|
||||
|
||||
# 指定备份文件
|
||||
./scripts/dr-drill.sh --backup backups/db_backup_20260617_020000.sql.gz
|
||||
|
||||
# 保留测试数据库(用于调试)
|
||||
./scripts/dr-drill.sh --no-cleanup
|
||||
```
|
||||
|
||||
### 5.4 演练报告
|
||||
|
||||
- **存储位置**: `docs/dr/reports/`
|
||||
- **格式**: Markdown
|
||||
- **内容**: 演练时间、步骤结果、RTO 评估、数据完整性指标
|
||||
- **保留期**: 90 天(CI artifact)
|
||||
|
||||
---
|
||||
|
||||
## 6. 联系人列表
|
||||
|
||||
> **注意**: 以下为模板,请根据实际人员填写
|
||||
|
||||
### 6.1 主要联系人
|
||||
|
||||
| 角色 | 姓名 | 电话 | 邮箱 | 职责 |
|
||||
|------|------|------|------|------|
|
||||
| 主负责人 | [待填写] | [待填写] | [待填写] | 灾备决策、协调 |
|
||||
| 备份负责人 | [待填写] | [待填写] | [待填写] | 备份执行、监控 |
|
||||
| DBA | [待填写] | [待填写] | [待填写] | 数据库恢复 |
|
||||
| 运维工程师 | [待填写] | [待填写] | [待填写] | 应用部署、网络 |
|
||||
| 开发负责人 | [待填写] | [待填写] | [待填写] | 代码修复、功能验证 |
|
||||
|
||||
### 6.2 升级路径
|
||||
|
||||
1. **L1**: 运维工程师(5 分钟内响应)
|
||||
2. **L2**: 主负责人 + DBA(15 分钟内响应)
|
||||
3. **L3**: 全体联系人(30 分钟内响应)
|
||||
|
||||
---
|
||||
|
||||
## 7. 恢复步骤
|
||||
|
||||
### 7.1 从备份恢复数据库
|
||||
|
||||
```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. 验证恢复结果
|
||||
mysql -u root -p -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='next_edu';"
|
||||
```
|
||||
|
||||
### 7.2 完整恢复流程
|
||||
|
||||
1. **获取最新备份**
|
||||
- 本地: `./backups/`
|
||||
- 异地: 从 S3/OSS/NFS 下载
|
||||
- CI artifact: 从 Gitea Actions 下载
|
||||
|
||||
2. **恢复数据库**
|
||||
```bash
|
||||
./scripts/restore-db.sh backups/db_backup_YYYYMMDD_HHMMSS.sql.gz
|
||||
```
|
||||
|
||||
3. **重启应用**
|
||||
```bash
|
||||
docker restart nextjs-app
|
||||
# 或
|
||||
docker stop nextjs-app && docker rm nextjs-app
|
||||
# 重新部署
|
||||
```
|
||||
|
||||
4. **验证数据完整性**
|
||||
```bash
|
||||
# 运行健康检查
|
||||
./scripts/health-check.sh
|
||||
|
||||
# 运行灾备演练(对比数据)
|
||||
./scripts/dr-drill.sh --no-cleanup
|
||||
```
|
||||
|
||||
5. **恢复流量**
|
||||
- 验证应用功能正常
|
||||
- 逐步恢复用户流量
|
||||
- 监控系统指标
|
||||
|
||||
---
|
||||
|
||||
## 8. 监控与告警
|
||||
|
||||
### 8.1 健康检查
|
||||
|
||||
```bash
|
||||
# 手动运行健康检查
|
||||
./scripts/health-check.sh
|
||||
|
||||
# 输出 JSON 格式报告
|
||||
./scripts/health-check.sh > health-report.json
|
||||
```
|
||||
|
||||
**检查项**:
|
||||
- 应用 HTTP 健康端点
|
||||
- 数据库连接
|
||||
- 磁盘空间(阈值 90%)
|
||||
- 备份新鲜度(24 小时内)
|
||||
|
||||
### 8.2 告警条件
|
||||
|
||||
| 条件 | 严重级别 | 通知方式 |
|
||||
|------|---------|---------|
|
||||
| 应用不可达 | 严重 | 电话 + 邮件 |
|
||||
| 数据库连接失败 | 严重 | 电话 + 邮件 |
|
||||
| 磁盘空间 > 90% | 警告 | 邮件 |
|
||||
| 备份超过 24 小时 | 警告 | 邮件 |
|
||||
| 备份校验失败 | 严重 | 电话 + 邮件 |
|
||||
| 灾备演练失败 | 警告 | 邮件 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 环境变量配置
|
||||
|
||||
```bash
|
||||
# 灾备配置
|
||||
BACKUP_OFFSITE_BACKEND=none # s3|oss|nfs|none
|
||||
BACKUP_OFFSITE_REMOTE= # 远程路径
|
||||
BACKUP_OFFSITE_BUCKET= # 存储桶名
|
||||
BACKUP_OFFSITE_ACCESS_KEY= # 访问密钥
|
||||
BACKUP_OFFSITE_SECRET_KEY= # 秘密密钥
|
||||
BACKUP_OFFSITE_REGION=us-east-1 # 区域
|
||||
DR_DRILL_TEST_DB=next_edu_dr_drill # 演练测试数据库
|
||||
HEALTH_CHECK_URL=http://localhost:8015 # 健康检查 URL
|
||||
|
||||
# 故障切换配置
|
||||
DATABASE_URL_STANDBY= # 备库连接 URL
|
||||
FAILOVER_APP_NAME=nextjs-app # 应用容器名
|
||||
FAILOVER_APP_URL=http://localhost:8015 # 应用 URL
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 文档维护
|
||||
|
||||
- **审核周期**: 每季度审核一次
|
||||
- **更新触发**: 系统架构变更、联系人变更、演练发现问题
|
||||
- **关联文档**:
|
||||
- `docs/dr/dr-runbook.md` - 灾备操作手册
|
||||
- `docs/dr/reports/` - 演练报告存档
|
||||
- `scripts/` - 灾备相关脚本
|
||||
|
||||
---
|
||||
|
||||
## 11. 变更记录
|
||||
|
||||
| 日期 | 版本 | 变更内容 | 变更人 |
|
||||
|------|------|---------|--------|
|
||||
| 2026-06-17 | 1.0 | 初始版本 | - |
|
||||
699
docs/dr/dr-runbook.md
Normal file
699
docs/dr/dr-runbook.md
Normal file
@@ -0,0 +1,699 @@
|
||||
# 灾备操作手册 (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 <DB_HOST> -P <DB_PORT> -u <DB_USER> -p -e "SELECT 1;"
|
||||
|
||||
# 2. 检查数据库进程
|
||||
systemctl status mysql
|
||||
# 或 Docker 环境
|
||||
docker ps | grep mysql
|
||||
|
||||
# 3. 检查端口
|
||||
telnet <DB_HOST> <DB_PORT>
|
||||
# 或
|
||||
nc -zv <DB_HOST> <DB_PORT>
|
||||
|
||||
# 4. 查看数据库日志
|
||||
tail -100 /var/log/mysql/error.log
|
||||
# 或 Docker
|
||||
docker logs <mysql_container> --tail 100
|
||||
```
|
||||
|
||||
#### 处理步骤
|
||||
|
||||
**情况 A: 数据库服务停止**
|
||||
```bash
|
||||
# 重启数据库服务
|
||||
sudo systemctl restart mysql
|
||||
# 或 Docker
|
||||
docker restart <mysql_container>
|
||||
|
||||
# 等待启动完成
|
||||
sleep 10
|
||||
mysql -h <DB_HOST> -P <DB_PORT> -u <DB_USER> -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 <DB_HOST> -P <DB_PORT> -u <DB_USER> -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 <process_id>;"
|
||||
|
||||
# 2. 优化表
|
||||
mysql -e "OPTIMIZE TABLE <table_name>;"
|
||||
|
||||
# 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 <DB_HOST> -P <DB_PORT> -u <DB_USER> -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 <DB_USER> -p -e "SHOW GRANTS;"
|
||||
|
||||
# 2. 授予必要权限
|
||||
mysql -u root -p -e "GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER ON *.* TO '<DB_USER>'@'%';"
|
||||
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 <nfs_server>:/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 <DB_HOST> -u <DB_USER> -p -e "CREATE DATABASE test_manual;"
|
||||
gunzip -c backups/db_backup_*.sql.gz | mysql -h <DB_HOST> -u <DB_USER> -p test_manual
|
||||
|
||||
# 3. 检查备份文件
|
||||
./scripts/backup-verify.sh
|
||||
```
|
||||
|
||||
#### 处理步骤
|
||||
```bash
|
||||
# 1. 清理失败的测试数据库
|
||||
mysql -h <DB_HOST> -u <DB_USER> -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 <DB_HOST> -u <DB_USER> -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 <DB_HOST> -P <DB_PORT> -u <DB_USER> -p -e "SHOW PROCESSLIST;"
|
||||
|
||||
# 检查应用日志
|
||||
docker logs nextjs-app --tail 100
|
||||
|
||||
# 检查磁盘空间
|
||||
df -h
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 变更记录
|
||||
|
||||
| 日期 | 版本 | 变更内容 | 变更人 |
|
||||
|------|------|---------|--------|
|
||||
| 2026-06-17 | 1.0 | 初始版本 | - |
|
||||
Reference in New Issue
Block a user