乐于分享
好东西不私藏

OpenClaw 30 天系列 - Day 27:备份与恢复:数据备份、配置迁移、灾难恢复

OpenClaw 30 天系列 - Day 27:备份与恢复:数据备份、配置迁移、灾难恢复

🎯 学习目标:学会备份与恢复:数据备份、配置迁移、灾难恢复

⏱️ 阅读时间:约 12 分钟 

💡 前置要求:无


💾 数据备份

备份策略

3-2-1 规则

3 份数据副本2 种不同介质1 份异地备份

备份频率

全量备份:频率:每周一次时间:周日凌晨2保留:4增量备份:频率:每天一次时间:凌晨3保留:7实时备份:频率:持续同步延迟:<1分钟

数据库备份

#!/bin/bash# backup-db.shBACKUP_DIR="/backups/database"DATE=$(date +%Y%m%d_%H%M%S)DB_NAME="openclaw"DB_USER="openclaw"# 创建备份目录mkdir -p $BACKUP_DIR# PostgreSQL 备份pg_dump -U $DB_USER$DB_NAME | gzip > ${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz# 保留最近 7 天的备份find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete# 上传到对象存储ossutil cp${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz oss://my-backups/database/echo"数据库备份完成:${DB_NAME}_${DATE}.sql.gz"

文件备份

const fs = require('fs');const archiver = require('archiver');const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');classBackupManager {asyncbackupFiles(sourceDir, backupPath) {const date = newDate().toISOString().slice(010);const backupFile = `${backupPath}/files_${date}.zip`;// 创建压缩包awaitthis.createZip(sourceDir, backupFile);// 上传到云存储awaitthis.uploadToS3(backupFile);// 清理本地备份awaitthis.cleanupOldBackups(backupPath, 7);return backupFile;  }asynccreateZip(sourceDir, outputFile) {returnnewPromise((resolve, reject) => {const output = fs.createWriteStream(outputFile);const archive = archiver('zip', { zlib: { level9 } });      output.on('close', resolve);      archive.on('error', reject);      archive.pipe(output);      archive.directory(sourceDir, false);      archive.finalize();    });  }asyncuploadToS3(file) {const client = newS3Client({});const fileStream = fs.createReadStream(file);await client.send(newPutObjectCommand({Bucket: process.env.S3_BUCKET,Key`backups/files/${file}`,Body: fileStream    }));  }}

配置备份

classConfigBackup {asyncbackup() {const config = {// 系统配置systemawaitthis.getSystemConfig(),// 用户配置(脱敏)usersawaitthis.getUserConfigs(),// 技能配置skillsawaitthis.getSkillConfigs(),// 通道配置(密钥除外)channelsawaitthis.getChannelConfigs()    };// 加密敏感信息const encrypted = awaitthis.encryptSensitive(config);// 保存备份const backupFile = `config_${Date.now()}.json.enc`;await fs.writeFile(backupFile, encrypted);return backupFile;  }asyncencryptSensitive(config) {// 不备份原始密钥const sanitized = JSON.parse(JSON.stringify(config));// 删除敏感字段delete sanitized.channels?.feishu?.appSecret;delete sanitized.channels?.wechat?.token;delete sanitized.model?.apiKey;// 标记需要重新配置    sanitized._requiresReconfiguration = true;returnJSON.stringify(sanitized, null2);  }}

🔄 数据恢复

恢复流程

classRestoreManager {asyncrestore(backupFile, options = {}) {console.log('开始恢复数据...');// 1. 验证备份文件awaitthis.verifyBackup(backupFile);// 2. 停止服务(可选)if (options.stopServices) {awaitthis.stopServices();    }// 3. 备份当前数据awaitthis.backupCurrent();// 4. 恢复数据awaitthis.restoreData(backupFile);// 5. 验证恢复awaitthis.verifyRestore();// 6. 重启服务if (options.stopServices) {awaitthis.startServices();    }console.log('数据恢复完成');  }asyncverifyBackup(backupFile) {// 检查文件存在if (!await fs.exists(backupFile)) {thrownewError('备份文件不存在');    }// 检查文件完整性const checksum = awaitthis.calculateChecksum(backupFile);const expectedChecksum = awaitthis.getStoredChecksum(backupFile);if (checksum !== expectedChecksum) {thrownewError('备份文件损坏');    }  }asyncrestoreData(backupFile) {// 解压备份awaitthis.extractBackup(backupFile);// 恢复数据库awaitthis.restoreDatabase();// 恢复文件awaitthis.restoreFiles();// 恢复配置awaitthis.restoreConfig();  }}

数据库恢复

#!/bin/bash# restore-db.shBACKUP_FILE=$1DB_NAME="openclaw"DB_USER="openclaw"if [ -z "$BACKUP_FILE" ]; thenecho"用法:$0 <备份文件>"exit 1fi# 解压备份gunzip -c $BACKUP_FILE > /tmp/restore.sql# 恢复数据库psql -U $DB_USER$DB_NAME < /tmp/restore.sql# 清理临时文件rm /tmp/restore.sqlecho"数据库恢复完成"

🌍 异地容灾

多区域部署

区域配置:主区域:位置:华东1(杭州)角色:主流量:100%备区域:位置:华北2(北京)角色:热备流量:0%同步:实时灾备区域:位置:华南1(深圳)角色:冷备流量:0%同步:每天

故障切换

classFailoverManager {asynccheckHealth() {const primary = awaitthis.checkRegion('primary');if (!primary.healthy) {awaitthis.triggerFailover();    }  }asynctriggerFailover() {console.log('主区域故障,开始切换...');// 1. 提升备区域为主awaitthis.promoteRegion('secondary');// 2. 更新 DNSawaitthis.updateDNS('secondary');// 3. 通知相关人员awaitthis.notifyTeam('故障切换已完成');// 4. 记录事件awaitthis.logIncident({type'failover',from'primary',to'secondary',timestampnewDate()    });  }asyncfailback() {console.log('主区域恢复,准备回切...');// 1. 同步数据awaitthis.syncData('primary''secondary');// 2. 验证数据一致性awaitthis.verifyConsistency();// 3. 切换流量awaitthis.switchTraffic('primary');// 4. 降级原主区域为备区域awaitthis.demoteRegion('secondary');  }}

📋 灾难恢复计划

恢复时间目标(RTO)

关键系统:RTO:<1小时RPO:<5分钟重要系统:RTO:<4小时RPO:<1小时一般系统:RTO:<24小时RPO:<24小时

恢复流程文档

# 灾难恢复流程## 1. 事件识别- [ ] 确认故障范围- [ ] 评估影响程度- [ ] 通知应急团队## 2. 应急响应- [ ] 启动应急预案- [ ] 切换到备用系统- [ ] 通知用户## 3. 数据恢复- [ ] 从备份恢复数据- [ ] 验证数据完整性- [ ] 恢复服务## 4. 事后总结- [ ] 分析故障原因- [ ] 更新应急预案- [ ] 改进监控系统

✅ 学完这篇你能做什么

学完 Day 27,你将能够:

  • ✅ 配置数据备份
  • ✅ 实施数据恢复
  • ✅ 设计异地容灾方案
  • ✅ 制定灾难恢复计划
  • ✅ 处理备份恢复相关错误

🔜 下篇预告

Day 28:第四周复盘:高级主题总结

  • 📚 第四周内容回顾
  • ❓ 常见问题 Q&A
  • 📊 学习成果自测

💬 互动环节

你的备份策略是什么?有过恢复经历吗?留言分享!


公众号:OpenClaw 研习社

系列:OpenClaw 30 天入门到精通 

作者:OpenClaw 研习社