{T}

高可用架构 学习笔记(第 3 部分)

2.2 业务逻辑保护

2.2.1 故障类型

人为失误 + 软件错误

code
业务逻辑保护故障类型:

人为失误
├── 误删除数据
├── 错误配置
├── 发布错误应用
└── 操作失误

软件错误
├── 操作系统 bug
├── 数据库 bug
├── 应用 bug
└── 第三方库 bug

安全事件
├── 数据泄露
├── 恶意攻击
└── 商户跑路(数据丢失)

2.2.2 故障特点

特点说明解决方案
需要数据恢复数据误删、篡改快照、备份
需要决策干预人为判断处理监控告警、人工介入
需要问题追溯查找原因审计日志、追踪系统

2.2.3 典型技术方案

1. 数据快照

javascript
// 数据快照实现
class DataSnapshot {
  constructor() {
    this.snapshots = new Map()
  }
  
  // 创建快照
  createSnapshot(database, snapshotName) {
    const timestamp = Date.now()
    const snapshot = {
      name: snapshotName,
      timestamp,
      data: this.cloneData(database),
      size: this.calculateSize(database)
    }
    
    this.snapshots.set(snapshotName, snapshot)
    
    console.log(`快照 ${snapshotName} 创建成功`)
    console.log(`时间: ${new Date(timestamp).toLocaleString()}`)
    console.log(`大小: ${snapshot.size} MB`)
    
    return snapshot
  }
  
  // 恢复快照
  restoreSnapshot(snapshotName, database) {
    const snapshot = this.snapshots.get(snapshotName)
    
    if (!snapshot) {
      throw new Error(`快照 ${snapshotName} 不存在`)
    }
    
    // 恢复数据
    Object.assign(database, snapshot.data)
    
    console.log(`快照 ${snapshotName} 恢复成功`)
    console.log(`快照时间: ${new Date(snapshot.timestamp).toLocaleString()}`)
    
    return database
  }
  
  // 列出所有快照
  listSnapshots() {
    const list = []
    this.snapshots.forEach((snapshot, name) => {
      list.push({
        name,
        timestamp: new Date(snapshot.timestamp).toLocaleString(),
        size: snapshot.size
      })
    })
    return list
  }
  
  // 克隆数据
  cloneData(data) {
    return JSON.parse(JSON.stringify(data))
  }
  
  // 计算大小
  calculateSize(data) {
    const json = JSON.stringify(data)
    return (Buffer.byteLength(json, 'utf8') / 1024 / 1024).toFixed(2)
  }
}

// 使用示例
const snapshotManager = new DataSnapshot()
const database = {
  users: [
    { id: 1, name: '张三', balance: 1000 },
    { id: 2, name: '李四', balance: 2000 }
  ]
}

// 创建快照
snapshotManager.createSnapshot(database, 'before_update')

// 模拟数据误操作
database.users[0].balance = 0
console.log('误操作后:', database.users[0])

// 恢复快照
snapshotManager.restoreSnapshot('before_update', database)
console.log('恢复后:', database.users[0])

2. 审计日志

javascript
// 审计日志系统
class AuditLogger {
  constructor() {
    this.logs = []
  }
  
  // 记录操作日志
  log(action, userId, details) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      action,
      userId,
      details,
      ip: this.getClientIP(),
      userAgent: this.getUserAgent()
    }
    
    this.logs.push(logEntry)
    
    // 持久化存储
    this.saveToFile(logEntry)
    
    return logEntry
  }
  
  // 查询日志
  query(filters) {
    return this.logs.filter(log => {
      if (filters.userId && log.userId !== filters.userId) return false
      if (filters.action && log.action !== filters.action) return false
      if (filters.startTime && new Date(log.timestamp) < new Date(filters.startTime)) return false
      if (filters.endTime && new Date(log.timestamp) > new Date(filters.endTime)) return false
      return true
    })
  }
  
  // 保存到文件
  saveToFile(logEntry) {
    const logLine = JSON.stringify(logEntry) + '\n'
    fs.appendFileSync('audit.log', logLine)
  }
  
  // 获取客户端 IP
  getClientIP() {
    return '192.168.1.100'
  }
  
  // 获取 User Agent
  getUserAgent() {
    return 'Mozilla/5.0 ...'
  }
}

// 使用示例
const auditLogger = new AuditLogger()

// 记录用户操作
auditLogger.log('DELETE_USER', 'admin001', {
  deletedUserId: 123,
  reason: '违规操作'
})

auditLogger.log('UPDATE_BALANCE', 'admin002', {
  userId: 456,
  oldBalance: 1000,
  newBalance: 500
})

// 查询日志
const logs = auditLogger.query({
  userId: 'admin001',
  startTime: '2024-01-01'
})

3. 灰度发布