🎯 学习目标:学会备份与恢复:数据备份、配置迁移、灾难恢复
⏱️ 阅读时间:约 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(0, 10);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: { level: 9 } }); 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 = {// 系统配置system: awaitthis.getSystemConfig(),// 用户配置(脱敏)users: awaitthis.getUserConfigs(),// 技能配置skills: awaitthis.getSkillConfigs(),// 通道配置(密钥除外)channels: awaitthis.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, null, 2); }}🔄 数据恢复
恢复流程
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',timestamp: newDate() }); }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 研习社
夜雨聆风