bulletproof-react灾备方案:多活架构与数据备份
引言:为什么React应用需要灾备方案?
在现代Web应用开发中,React已经成为构建用户界面的首选框架。然而,随着业务规模的扩大和用户量的增长,单点故障的风险也随之增加。一个生产就绪的React应用不仅需要优秀的代码架构,更需要完善的灾备(Disaster Recovery)方案来确保业务连续性。
本文将基于bulletproof-react项目架构,深入探讨React应用的多活架构设计和数据备份策略,帮助您构建真正"高可用"的React应用。
多活架构设计原则
架构设计目标
1. 地域多活部署
基于bulletproof-react的多地域部署方案:
// config/env.ts - 多环境配置
export const ENV_CONFIG = {
production: {
apiBaseUrl: process.env.API_BASE_URL || 'https://api.example.com',
cdnBaseUrl: process.env.CDN_BASE_URL || 'https://cdn.example.com',
regions: ['us-east-1', 'eu-west-1', 'ap-northeast-1'],
activeRegion: process.env.ACTIVE_REGION || 'us-east-1'
},
development: {
apiBaseUrl: 'http://localhost:3001',
cdnBaseUrl: 'http://localhost:3000',
regions: ['local'],
activeRegion: 'local'
}
};
// 区域健康检查
export const regionHealthCheck = async (region: string): Promise<boolean> => {
try {
const response = await fetch(`https://health.${region}.example.com/status`, {
timeout: 5000
});
return response.status === 200;
} catch (error) {
console.warn(`Region ${region} health check failed:`, error);
return false;
}
};
2. 智能路由与故障转移
// lib/api-client.ts - 增强的API客户端
class ResilientApiClient {
private regions: string[];
private currentRegion: string;
private fallbackRegions: string[];
constructor() {
this.regions = ENV_CONFIG.production.regions;
this.currentRegion = ENV_CONFIG.production.activeRegion;
this.fallbackRegions = this.regions.filter(r => r !== this.currentRegion);
}
async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
let lastError: Error | null = null;
// 优先使用当前区域
try {
return await this.makeRequest(this.currentRegion, endpoint, options);
} catch (error) {
lastError = error as Error;
console.warn(`Request to ${this.currentRegion} failed, trying fallback regions`);
}
// 尝试备用区域
for (const region of this.fallbackRegions) {
try {
const result = await this.makeRequest(region, endpoint, options);
// 成功时切换到该区域
this.currentRegion = region;
return result;
} catch (error) {
lastError = error as Error;
}
}
throw new Error(`All regions failed: ${lastError?.message}`);
}
private async makeRequest<T>(region: string, endpoint: string, options: RequestInit): Promise<T> {
const url = `https://api.${region}.example.com${endpoint}`;
const response = await fetch(url, {
...options,
headers: {
'Content-Type': 'application/json',
'X-Region': region,
...options.headers
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
}
}
数据备份与恢复策略
1. 客户端数据持久化方案
// utils/persistence.ts - 多级存储策略
export class DisasterRecoveryStorage {
private static instance: DisasterRecoveryStorage;
private primaryStorage: Storage;
private secondaryStorage: Storage;
private remoteBackupEnabled: boolean;
private constructor() {
this.primaryStorage = window.localStorage;
this.secondaryStorage = window.sessionStorage;
this.remoteBackupEnabled = navigator.onLine;
}
static getInstance(): DisasterRecoveryStorage {
if (!DisasterRecoveryStorage.instance) {
DisasterRecoveryStorage.instance = new DisasterRecoveryStorage();
}
return DisasterRecoveryStorage.instance;
}
async setItem(key: string, value: any): Promise<void> {
const serializedValue = JSON.stringify({
value,
timestamp: Date.now(),
version: '1.0'
});
// 主存储
try {
this.primaryStorage.setItem(key, serializedValue);
} catch (error) {
console.warn('Primary storage failed, using secondary:', error);
this.secondaryStorage.setItem(key, serializedValue);
}
// 远程备份
if (this.remoteBackupEnabled) {
await this.backupToRemote(key, value);
}
}
async getItem<T>(key: string): Promise<T | null> {
// 尝试从主存储读取
let storedValue = this.primaryStorage.getItem(key);
// 主存储失败时尝试备用存储
if (!storedValue) {
storedValue = this.secondaryStorage.getItem(key);
}
if (!storedValue) {
// 尝试从远程恢复
return await this.restoreFromRemote<T>(key);
}
try {
const parsed = JSON.parse(storedValue);
return parsed.value;
} catch (error) {
console.error('Failed to parse stored value:', error);
return null;
}
}
private async backupToRemote(key: string, value: any): Promise<void> {
try {
await fetch('/api/backup/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key, value, timestamp: Date.now() })
});
} catch (error) {
console.warn('Remote backup failed:', error);
}
}
private async restoreFromRemote<T>(key: string): Promise<T | null> {
try {
const response = await fetch(`/api/backup/data?key=${encodeURIComponent(key)}`);
if (response.ok) {
const data = await response.json();
// 恢复后保存到本地
await this.setItem(key, data.value);
return data.value;
}
} catch (error) {
console.warn('Remote restore failed:', error);
}
return null;
}
}
2. 用户会话灾难恢复
// lib/auth.tsx - 增强的认证管理
export const useAuth = () => {
const queryClient = useQueryClient();
const storage = DisasterRecoveryStorage.getInstance();
const login = async (credentials: LoginCredentials) => {
try {
const user = await apiClient.post<User>('/auth/login', credentials);
// 多级存储用户信息
await storage.setItem('currentUser', user);
await storage.setItem('authToken', user.token);
// 更新React Query缓存
queryClient.setQueryData(['user'], user);
return user;
} catch (error) {
// 尝试从备份恢复会话
const backupUser = await storage.getItem<User>('currentUser');
if (backupUser?.token) {
queryClient.setQueryData(['user'], backupUser);
return backupUser;
}
throw error;
}
};
const logout = async () => {
// 清理所有存储级别的数据
await Promise.all([
storage.setItem('currentUser', null),
storage.setItem('authToken', null),
apiClient.post('/auth/logout')
]);
queryClient.setQueryData(['user'], null);
};
return { login, logout };
};
监控与告警体系
1. 应用健康监控
// utils/monitoring.ts - 综合监控系统
export class ApplicationMonitor {
private static metrics: Map<string, number> = new Map();
private static errors: Error[] = [];
private static readonly MAX_ERRORS = 100;
static trackMetric(name: string, value: number): void {
this.metrics.set(name, value);
// 异常值告警
if (name === 'api_response_time' && value > 5000) {
this.triggerAlert('HIGH_API_RESPONSE_TIME', { value });
}
}
static trackError(error: Error, context?: any): void {
this.errors.push(error);
if (this.errors.length > this.MAX_ERRORS) {
this.errors.shift();
}
// 错误率监控
const errorRate = this.errors.length / 100;
if (errorRate > 0.1) {
this.triggerAlert('HIGH_ERROR_RATE', { errorRate });
}
// 上报到监控系统
this.reportToMonitoringService(error, context);
}
static getHealthStatus(): ApplicationHealth {
const now = Date.now();
return {
timestamp: now,
metrics: Object.fromEntries(this.metrics),
errorCount: this.errors.length,
lastError: this.errors[this.errors.length - 1] || null,
region: ENV_CONFIG.production.activeRegion,
isHealthy: this.errors.length < 10
};
}
private static async triggerAlert(type: string, data: any): Promise<void> {
// 发送告警到多个渠道
await Promise.allSettled([
this.sendToSlack(type, data),
this.sendToEmail(type, data),
this.sendToSMS(type, data)
]);
}
private static async reportToMonitoringService(error: Error, context: any): Promise<void> {
try {
await fetch('/api/monitoring/errors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
error: error.message,
stack: error.stack,
context,
timestamp: Date.now(),
userAgent: navigator.userAgent
})
});
} catch (reportError) {
console.warn('Failed to report error to monitoring service:', reportError);
}
}
}
2. 性能指标监控
// hooks/usePerformanceMonitor.ts - React性能监控Hook
export const usePerformanceMonitor = (componentName: string) => {
const mountTime = useRef(Date.now());
const renderCount = useRef(0);
useEffect(() => {
const mountDuration = Date.now() - mountTime.current;
ApplicationMonitor.trackMetric(`${componentName}_mount_time`, mountDuration);
return () => {
const lifetime = Date.now() - mountTime.current;
ApplicationMonitor.trackMetric(`${componentName}_lifetime`, lifetime);
};
}, [componentName]);
useLayoutEffect(() => {
renderCount.current += 1;
ApplicationMonitor.trackMetric(`${componentName}_render_count`, renderCount.current);
});
};
灾备演练与恢复流程
1. 自动化灾备演练
// utils/disaster-recovery-drill.ts - 灾备演练系统
export class DisasterRecoveryDrill {
private static readonly DRILL_TYPES = {
NETWORK_FAILURE: 'network_failure',
DATABASE_FAILURE: 'database_failure',
REGION_FAILURE: 'region_failure',
STORAGE_FAILURE: 'storage_failure'
} as const;
static async runDrill(type: keyof typeof this.DRILL_TYPES): Promise<DrillResult> {
const startTime = Date.now();
let success = false;
let error: Error | null = null;
try {
switch (type) {
case 'NETWORK_FAILURE':
success = await this.simulateNetworkFailure();
break;
case 'DATABASE_FAILURE':
success = await this.simulateDatabaseFailure();
break;
case 'REGION_FAILURE':
success = await this.simulateRegionFailure();
break;
case 'STORAGE_FAILURE':
success = await this.simulateStorageFailure();
break;
}
} catch (e) {
error = e as Error;
success = false;
}
const duration = Date.now() - startTime;
// 记录演练结果
await this.recordDrillResult({
type,
success,
duration,
error: error?.message,
timestamp: new Date().toISOString()
});
return { success, duration, error };
}
private static async simulateNetworkFailure(): Promise<boolean> {
// 模拟网络中断并测试恢复能力
const originalFetch = window.fetch;
// 注入网络错误
window.fetch = async (...args) => {
if (Math.random() < 0.7) {
throw new Error('Simulated network failure');
}
return originalFetch.apply(window, args);
};
try {
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



