一、备份恢复概述
数据库备份恢复是保障数据安全的核心措施,能够在数据丢失或损坏时快速恢复数据。在数据密集型应用中,建立完善的备份恢复体系是保障业务连续性的关键。
二、备份类型与策略
2.1 备份类型对比
| 备份类型 | 描述 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 全量备份 | 备份全部数据 | 恢复简单 | 备份时间长、占用空间大 | 定期基础备份 |
| 增量备份 | 备份变化的数据 | 备份速度快、占用空间小 | 恢复复杂 | 日常备份 |
| 差异备份 | 备份上次全量后变化的数据 | 恢复较简单 | 占用空间较大 | 中等频率备份 |
| 事务日志备份 | 备份事务日志 | 支持点恢复 | 依赖全量备份 | 高可用场景 |
2.2 3-2-1备份原则
graph TD
A[3-2-1备份原则] --> B[3份副本]
A --> C[2种介质]
A --> D[1份异地]
B --> B1[原始数据]
B --> B2[本地备份]
B --> B3[异地备份]
C --> C1[磁盘]
C --> C2[磁带/云存储]
D --> D1[异地数据中心]
D --> D2[云端备份]
三、MySQL备份恢复
3.1 MySQL备份策略
public class MySqlBackupService
{
public async Task PerformFullBackupAsync(string backupPath)
{
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var backupFile = Path.Combine(backupPath, $"full_backup_{timestamp}.sql");
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "mysqldump",
Arguments = $"--single-transaction --quick --lock-tables=false -u root -p password database > {backupFile}",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task PerformIncrementalBackupAsync(string backupPath)
{
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var backupFile = Path.Combine(backupPath, $"incremental_backup_{timestamp}.binlog");
await _mysqlClient.ExecuteAsync("FLUSH LOGS");
await _mysqlClient.CopyBinlogToBackup(backupFile);
}
public async Task RestoreFromFullBackupAsync(string backupFile, string databaseName)
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "mysql",
Arguments = $"-u root -p password {databaseName} < {backupFile}",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task RestorePointInTimeAsync(string fullBackupFile, string binlogFile, DateTime pointInTime)
{
await RestoreFromFullBackupAsync(fullBackupFile, "temp_database");
await _mysqlClient.ExecuteAsync($"mysqlbinlog --stop-datetime='{pointInTime:yyyy-MM-dd HH:mm:ss}' {binlogFile} | mysql -u root -p password temp_database");
}
}
3.2 XtraBackup备份
public class XtraBackupService
{
public async Task PerformHotBackupAsync(string backupPath)
{
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var backupDir = Path.Combine(backupPath, $"xtrabackup_{timestamp}");
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "xtrabackup",
Arguments = $"--backup --user=root --password=password --target-dir={backupDir}",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task PrepareBackupAsync(string backupDir)
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "xtrabackup",
Arguments = $"--prepare --target-dir={backupDir}",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task RestoreFromBackupAsync(string backupDir, string dataDir)
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "xtrabackup",
Arguments = $"--copy-back --target-dir={backupDir} --datadir={dataDir}",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
}
四、PostgreSQL备份恢复
4.1 PostgreSQL备份策略
public class PostgreSqlBackupService
{
public async Task PerformFullBackupAsync(string backupPath)
{
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var backupFile = Path.Combine(backupPath, $"pg_dump_{timestamp}.dump");
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "pg_dump",
Arguments = $"-U postgres -F c -b -v -f {backupFile} database",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task PerformBaseBackupAsync(string backupPath)
{
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var backupDir = Path.Combine(backupPath, $"base_backup_{timestamp}");
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "pg_basebackup",
Arguments = $"-U postgres -D {backupDir} -F tar -z -P",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task RestoreFromBackupAsync(string backupFile, string databaseName)
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "pg_restore",
Arguments = $"-U postgres -d {databaseName} -v {backupFile}",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task EnableWalArchivingAsync(string archiveDir)
{
await _postgreSqlClient.ExecuteAsync($"ALTER SYSTEM SET wal_level = 'replica';");
await _postgreSqlClient.ExecuteAsync($"ALTER SYSTEM SET archive_mode = 'on';");
await _postgreSqlClient.ExecuteAsync($"ALTER SYSTEM SET archive_command = 'cp %p {archiveDir}/%f';");
await _postgreSqlClient.RestartAsync();
}
}
五、MongoDB备份恢复
5.1 MongoDB备份策略
public class MongoDbBackupService
{
public async Task PerformFullBackupAsync(string backupPath)
{
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var backupDir = Path.Combine(backupPath, $"mongodump_{timestamp}");
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "mongodump",
Arguments = $"--uri=mongodb://localhost:27017 --out={backupDir}",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task PerformPointInTimeBackupAsync(string backupPath, DateTime pointInTime)
{
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var backupDir = Path.Combine(backupPath, $"pitr_backup_{timestamp}");
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "mongodump",
Arguments = $"--uri=mongodb://localhost:27017 --out={backupDir} --oplog --stopTime={pointInTime:yyyy-MM-ddTHH:mm:ssZ}",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task RestoreFromBackupAsync(string backupDir)
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "mongorestore",
Arguments = $"--uri=mongodb://localhost:27017 {backupDir}",
UseShellExecute = true,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
public async Task EnableOplogAsync()
{
await _mongoClient.GetDatabase("admin").RunCommandAsync(
BsonDocument.Parse("{ replSetInitiate: { _id: 'rs0', members: [ { _id: 0, host: 'localhost:27017' } ] } }"));
}
}
六、灾难恢复方案
6.1 灾难恢复架构
graph TD
A[生产数据中心] --> B[主数据库]
B --> C[从数据库]
B --> D[备份服务器]
A --> E[网络故障]
A --> F[自然灾害]
G[异地灾备中心] --> H[灾备数据库]
H --> I[灾备应用服务器]
B --> J[数据同步]
J --> H
D --> K[备份同步]
K --> G
E --> L[切换到从库]
F --> M[切换到灾备中心]
6.2 RTO与RPO
| 指标 | 定义 | 影响因素 | 优化策略 |
|---|---|---|---|
| RTO | 恢复时间目标 | 恢复流程复杂度 | 自动化恢复 |
| RPO | 恢复点目标 | 备份频率 | 实时同步 |
6.3 灾难恢复流程
public class DisasterRecoveryService
{
public async Task ExecuteDisasterRecoveryAsync(RecoveryPlan plan)
{
await ValidateDisasterAsync();
await SwitchToBackupAsync(plan);
await VerifyRecoveryAsync();
await NotifyStakeholdersAsync();
}
private async Task ValidateDisasterAsync()
{
var healthStatus = await _healthCheckService.CheckAllAsync();
if (!healthStatus.IsHealthy)
{
await _alertService.SendAlert("检测到灾难",
$"健康状态: {healthStatus.Details}");
}
}
private async Task SwitchToBackupAsync(RecoveryPlan plan)
{
await _dnsService.SwitchToBackupDNS();
await _loadBalancerService.SwitchToBackupServers();
await _databaseService.FailoverToBackup();
}
private async Task VerifyRecoveryAsync()
{
var verificationResult = await _verificationService.VerifyAsync();
if (!verificationResult.IsSuccessful)
{
await _alertService.SendAlert("恢复验证失败",
$"失败原因: {verificationResult.FailureReason}");
}
}
private async Task NotifyStakeholdersAsync()
{
await _notificationService.SendNotification("灾难恢复完成",
"系统已切换到备份环境");
}
}
public class RecoveryPlan
{
public string PlanName { get; set; }
public RecoveryType Type { get; set; }
public string TargetEnvironment { get; set; }
public int ExpectedRtoMinutes { get; set; }
}
public enum RecoveryType
{
Failover,
Restore,
Rebuild
}
七、备份监控与验证
7.1 备份监控
public class BackupMonitor
{
public async Task CheckBackupStatusAsync()
{
var lastFullBackup = await _backupRepository.GetLastBackupAsync(BackupType.Full);
var lastIncrementalBackup = await _backupRepository.GetLastBackupAsync(BackupType.Incremental);
var fullBackupAge = DateTime.Now - lastFullBackup.CreatedAt;
var incrementalBackupAge = DateTime.Now - lastIncrementalBackup.CreatedAt;
return new BackupStatus
{
LastFullBackup = lastFullBackup,
LastIncrementalBackup = lastIncrementalBackup,
FullBackupHealthy = fullBackupAge < TimeSpan.FromDays(7),
IncrementalBackupHealthy = incrementalBackupAge < TimeSpan.FromHours(24),
StorageUsage = await _storageService.GetUsageAsync()
};
}
public async Task MonitorAsync()
{
var status = await CheckBackupStatusAsync();
if (!status.FullBackupHealthy)
{
await _alertService.SendAlert("全量备份过期",
$"上次全量备份: {status.LastFullBackup.CreatedAt}");
}
if (!status.IncrementalBackupHealthy)
{
await _alertService.SendAlert("增量备份过期",
$"上次增量备份: {status.LastIncrementalBackup.CreatedAt}");
}
}
}
public class BackupStatus
{
public BackupInfo LastFullBackup { get; set; }
public BackupInfo LastIncrementalBackup { get; set; }
public bool FullBackupHealthy { get; set; }
public bool IncrementalBackupHealthy { get; set; }
public StorageUsage StorageUsage { get; set; }
}
7.2 备份验证
public class BackupValidator
{
public async Task ValidateBackupAsync(string backupFile)
{
var checks = new List>
{
CheckFileExistsAsync(backupFile),
CheckFileIntegrityAsync(backupFile),
CheckFileSizeAsync(backupFile),
CheckRestoreTestAsync(backupFile)
};
var results = await Task.WhenAll(checks);
return new ValidationResult
{
AllPassed = results.All(r => r.Passed),
Checks = results
};
}
private async Task CheckFileExistsAsync(string backupFile)
{
var exists = File.Exists(backupFile);
return new CheckResult { Name = "文件存在", Passed = exists };
}
private async Task CheckFileIntegrityAsync(string backupFile)
{
var hash = await CalculateFileHashAsync(backupFile);
var expectedHash = await GetExpectedHashAsync(backupFile);
return new CheckResult { Name = "文件完整性", Passed = hash == expectedHash };
}
private async Task CheckRestoreTestAsync(string backupFile)
{
var testDatabase = $"test_restore_{Guid.NewGuid():N}";
try
{
await _backupService.RestoreFromBackupAsync(backupFile, testDatabase);
await _databaseService.VerifyDatabaseAsync(testDatabase);
return new CheckResult { Name = "恢复测试", Passed = true };
}
finally
{
await _databaseService.DropDatabaseAsync(testDatabase);
}
}
}
八、备份恢复最佳实践
8.1 制定备份策略
public class BackupPolicy
{
public BackupType Type { get; set; }
public Schedule Schedule { get; set; }
public RetentionPolicy Retention { get; set; }
public EncryptionPolicy Encryption { get; set; }
}
public enum BackupType
{
Full,
Incremental,
Differential,
Log
}
public class Schedule
{
public string CronExpression { get; set; }
public TimeZoneInfo TimeZone { get; set; }
}
public class RetentionPolicy
{
public TimeSpan FullBackupRetention { get; set; }
public TimeSpan IncrementalBackupRetention { get; set; }
}
public class EncryptionPolicy
{
public bool Enabled { get; set; }
public string Algorithm { get; set; }
}
8.2 自动化备份
public class BackupScheduler
{
public void ScheduleBackups(BackupPolicy policy)
{
var scheduler = new HangfireBackgroundJobScheduler();
scheduler.ScheduleRecurringJob(
() => _backupService.PerformFullBackupAsync(policy),
"full_backup",
policy.Schedule.CronExpression);
scheduler.ScheduleRecurringJob(
() => _backupService.PerformIncrementalBackupAsync(policy),
"incremental_backup",
"0 * * * *");
scheduler.ScheduleRecurringJob(
() => _backupValidator.ValidateBackupAsync(),
"validate_backup",
"0 2 * * *");
}
}
8.3 定期演练恢复
定期进行灾难恢复演练,确保备份可用且恢复流程顺畅。
8.4 加密备份数据
public class BackupEncryptionService
{
public async Task EncryptBackupAsync(string backupFile, string encryptionKey)
{
var encryptedFile = $"{backupFile}.encrypted";
using var inputStream = File.OpenRead(backupFile);
using var outputStream = File.Create(encryptedFile);
using var aes = Aes.Create();
aes.Key = Convert.FromBase64String(encryptionKey);
aes.GenerateIV();
outputStream.Write(aes.IV, 0, aes.IV.Length);
using var cryptoStream = new CryptoStream(outputStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
await inputStream.CopyToAsync(cryptoStream);
return encryptedFile;
}
public async Task DecryptBackupAsync(string encryptedFile, string encryptionKey)
{
var decryptedFile = encryptedFile.Replace(".encrypted", "");
using var inputStream = File.OpenRead(encryptedFile);
var iv = new byte[16];
await inputStream.ReadAsync(iv, 0, iv.Length);
using var outputStream = File.Create(decryptedFile);
using var aes = Aes.Create();
aes.Key = Convert.FromBase64String(encryptionKey);
aes.IV = iv;
using var cryptoStream = new CryptoStream(inputStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
await cryptoStream.CopyToAsync(outputStream);
return decryptedFile;
}
}
九、总结
数据库备份恢复是数据密集型应用中保障数据安全的核心措施。遵循3-2-1备份原则,选择合适的备份策略,建立完善的灾难恢复方案,能够在数据丢失或损坏时快速恢复数据。定期监控和验证备份,确保备份可用且恢复流程顺畅。