容灾模式分类:
按地理位置分类
├── 同城双活(同一城市不同数据中心)
├── 异地双活(不同城市之间)
└── 异地多活(多地同时服务)
按技术实现分类
├── 网络多活(不同运营商之间)
├── 存储多活(逻辑层面对用户透明)
├── 数据库双活(数据库层面冗余)
└── 应用双活(应用层面冗余)定义:同一城市内不同数据中心之间的双活架构
同城双活架构示例:
上海地区:
┌──────────────┐ ┌──────────────┐
│ 浦东数据中心 │ ←──→ │ 浦西数据中心 │
│ (Active) │ │ (Active) │
├──────────────┤ ├──────────────┤
│ 应用集群 │ │ 应用集群 │
│ 数据库主 │ │ 数据库主 │
│ 存储阵列 │ │ 存储阵列 │
└──────────────┘ └──────────────┘
↑ ↑
└─────────┬───────────┘
│
低延迟专线连接
(< 5ms)
特点:
- 地理距离近(通常 < 50km)
- 网络延迟低(< 5ms)
- 数据同步快
- 成本相对较低优势与挑战:
| 优势 | 挑战 |
|---|---|
| 网络延迟低 | 仍可能受城市级灾害影响 |
| 数据同步快 | 建设成本较高 |
| 运维相对简单 | 需要专线连接 |
| 切换速度快 | - |
适用场景:
const 同城双活Scenarios = {
// 场景1: 金融核心系统
finance: {
requirement: 'RTO < 5分钟, RPO < 1分钟',
implementation: '两地三中心(同城双活 + 异地灾备)'
},
// 场景2: 电商交易系统
ecommerce: {
requirement: '高可用、低延迟',
implementation: '同城双活 + 异地冷备'
},
// 场景3: 政务系统
government: {
requirement: '数据安全、业务连续',
implementation: '同城双活 + 异地灾备'
}
}定义:不同城市之间的双活架构,通常距离不超过 100 公里
异地双活架构示例:
北京数据中心 天津数据中心
┌──────────────┐ ┌──────────────┐
│ 北京中心 │ ←───────→ │ 天津中心 │
│ (Active) │ │ (Active) │
├──────────────┤ ├──────────────┤
│ 应用集群 │ │ 应用集群 │
│ 数据库主 │ │ 数据库主 │
│ 存储阵列 │ │ 存储阵列 │
└──────────────┘ └──────────────┘
↑ ↑
└──────────┬───────────────┘
│
专线连接
(距离 < 100km)
(延迟 < 10ms)
限制因素:
- 地理距离:不超过 100km
- 网络延迟:数据库同步延迟 < 10ms
- 专线成本:距离越远成本越高距离限制原因:
// 异地双活距离限制分析
const distanceLimitation = {
// 1. 网络延迟
networkLatency: {
formula: '延迟 = 距离 / 光速 × 2(往返)',
example: {
distance: 100, // km
speed: 200000, // km/s(光在光纤中的速度)
latency: (100 / 200000) * 2 * 1000, // ms
result: '0.5ms 单程, 1ms 往返'
},
problem: '数据库同步需要多次往返通信,累积延迟影响性能'
},
// 2. 数据一致性
dataConsistency: {
challenge: '距离越远,同步延迟越大',
impact: [
'主从延迟增加',
'数据冲突概率提高',
'事务响应时间变长'
]
},
// 3. 成本因素
cost: {
items: [
'专线租赁费用(按距离收费)',
'网络设备成本',
'运维人力成本'
],
example: '100km 专线成本可能是 10km 的 5-10 倍'
}
}典型城市组合:
中国典型异地双活城市组合:
京津冀地区
├── 北京 - 天津(约 120km)
├── 北京 - 石家庄(约 280km)
└── 北京 - 廊坊(约 60km)
长三角地区
├── 上海 - 杭州(约 180km)
├── 上海 - 苏州(约 80km)
└── 上海 - 无锡(约 130km)
珠三角地区
├── 广州 - 深圳(约 140km)
├── 广州 - 佛山(约 30km)
└── 深圳 - 东莞(约 60km)
注: 距离较近(≤ 100km)的组合适合异地双活
距离较远的组合需要评估延迟与成本影响定义:不同运营商之间的多活架构
网络多活架构:
用户请求
↓
┌─────────────────┐
│ 智能 DNS 解析 │
└────────┬────────┘
│
┌────┼────┬────────┐
│ │ │ │
↓ ↓ ↓ ↓
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│电信 │ │联通 │ │移动 │ │BGP │
│机房 │ │机房 │ │机房 │ │机房 │
└──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘
│ │ │ │
└───────┼───────┼───────┘
│ │
统一数据层
(跨运营商同步)
特点:
- 覆盖不同运营商用户
- 提升访问速度
- 降低跨网延迟
- 提高可用性实现示例:
// 基于 BGP 的网络多活
class NetworkMultiActive {
constructor() {
this.datacenters = {
telecom: {
name: '电信机房',
ip: '202.96.128.1',
carrier: 'telecom',
region: 'cn-north'
},
unicom: {
name: '联通机房',
ip: '210.22.128.1',
carrier: 'unicom',
region: 'cn-north'
},
mobile: {
name: '移动机房',
ip: '120.204.128.1',
carrier: 'mobile',
region: 'cn-north'
}
}
}
// 根据用户运营商选择机房
routeByCarrier(userCarrier) {
const dc = this.datacenters[userCarrier]
if (dc && this.isHealthy(dc)) {
return dc
}
// 回退到其他机房
return this.fallback(userCarrier)
}
// 检查机房健康状态
isHealthy(dc) {
// 实际实现:心跳检测、HTTP 探测等
return true
}
// 回退策略
fallback(carrier) {
const carriers = Object.keys(this.datacenters)
const otherCarriers = carriers.filter(c => c !== carrier)
for (const c of otherCarriers) {
if (this.isHealthy(this.datacenters[c])) {
return this.datacenters[c]
}
}
return null
}
}
// DNS 配置示例
const dnsConfig = {
domain: 'api.example.com',
records: [
{ type: 'A', carrier: 'telecom', ip: '202.96.128.1', ttl: 60 },
{ type: 'A', carrier: 'unicom', ip: '210.22.128.1', ttl: 60 },
{ type: 'A', carrier: 'mobile', ip: '120.204.128.1', ttl: 60 },
{ type: 'A', carrier: 'default', ip: '1.2.3.4', ttl: 300 } // BGP IP
]
}定义:逻辑层面的多活,用户无需关心数据实际存储位置
存储多活架构:
┌─────────────────────────────────┐
│ 应用层 │
│ (无需关心数据存储位置) │
└─────────────┬───────────────────┘
↓
┌─────────────────────────────────┐
│ 存储虚拟化层 │
│ (统一存储接口) │
└─────────────┬───────────────────┘
↓
┌─────────┼─────────┐
│ │ │
┌───┴───┐ ┌──┴────┐ ┌──┴────┐
│存储A │ │存储B │ │存储C │
│(北京) │ │(上海) │ │(广州) │
└───────┘ └───────┘ └───────┘
特点:
- 对用户透明
- 自动数据同步
- 统一管理界面
- 异构存储支持存储虚拟化实现:
// 存储虚拟化管理器
class StorageVirtualization {
constructor() {
this.storageNodes = {
beijing: {
endpoint: 'storage-bj.example.com',
capacity: 1000, // TB
used: 300,
latency: 5 // ms
},
shanghai: {
endpoint: 'storage-sh.example.com',
capacity: 1000,
used: 350,
latency: 8
},
guangzhou: {
endpoint: 'storage-gz.example.com',
capacity: 800,
used: 200,
latency: 12
}
}
}
// 统一写入接口
async write(key, data) {
// 1. 选择最优存储节点
const node = this.selectOptimalNode()
// 2. 写入数据
await this.writeToNode(node, key, data)
// 3. 异步同步到其他节点
this.syncToOtherNodes(node, key, data)
return { success: true, location: node }
}
// 统一读取接口
async read(key) {
// 从最近的节点读取
const node = this.selectNearestNode()
try {
const data = await this.readFromNode(node, key)
return data
} catch (error) {
// 失败时从其他节点读取
return this.readFromOtherNodes(key)
}
}
// 选择最优节点
selectOptimalNode() {
const nodes = Object.keys(this.storageNodes)
// 根据负载和延迟选择
const sorted = nodes.sort((a, b) => {
const nodeA = this.storageNodes[a]
const nodeB = this.storageNodes[b]
const scoreA = this.calculateScore(nodeA)
const scoreB = this.calculateScore(nodeB)
return scoreB - scoreA
})
return sorted[0]
}
// 计算节点得分
calculateScore(node) {
const availableSpace = node.capacity - node.used
const latencyScore = 100 - node.latency
return availableSpace * 0.6 + latencyScore * 0.4
}
// 选择最近节点
selectNearestNode() {
const nodes = Object.keys(this.storageNodes)
const sorted = nodes.sort((a, b) => {
return this.storageNodes[a].latency - this.storageNodes[b].latency
})
return sorted[0]
}
// 写入到指定节点
async writeToNode(nodeName, key, data) {
// 实际实现:调用存储节点的 API
console.log(`写入数据到 ${nodeName}: ${key}`)
}
// 从指定节点读取
async readFromNode(nodeName, key) {
console.log(`从 ${nodeName} 读取数据: ${key}`)
return { data: 'example' }
}
// 同步到其他节点
async syncToOtherNodes(sourceNode, key, data) {
const otherNodes = Object.keys(this.storageNodes)
.filter(n => n !== sourceNode)
// 异步同步
Promise.all(otherNodes.map(node =>
this.writeToNode(node, key, data)
))
}
// 从其他节点读取
async readFromOtherNodes(key) {
const nodes = Object.keys(this.storageNodes)
for (const node of nodes) {
try {
return await this.readFromNode(node, key)
} catch (error) {
continue
}
}
throw new Error('数据读取失败')
}
}定义:两个数据库系统在相隔较远的情况下同时运行,支持相同的应用负载
数据库双活架构:
北京数据库 上海数据库
┌──────────┐ ┌──────────┐
│ MySQL 主 │ ←─────────→ │ MySQL 主 │
└────┬─────┘ 双向同步 └────┬─────┘
│ │
┌────┴─────┐ ┌────┴─────┐
│ 应用集群 │ │ 应用集群 │
│ (北京) │ │ (上海) │
└──────────┘ └──────────┘
↑ ↑
└─────────┬───────────────┘
│
负载均衡
│
↓
用户请求
特点:
- 双主架构
- 双向数据同步
- 故障自动切换
- 支持跨地域部署MySQL 双主复制配置:
-- 北京数据库配置 (my.cnf)
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog-format = ROW
auto-increment-increment = 2
auto-increment-offset = 1
-- 上海数据库配置 (my.cnf)
[mysqld]
server-id = 2
log-bin = mysql-bin
binlog-format = ROW
auto-increment-increment = 2
auto-increment-offset = 2
-- 北京数据库:配置上海为主(MySQL 8.0.22+ 语法;CHANGE MASTER TO 已在 8.4 移除)
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='shanghai-db-ip',
SOURCE_USER='repl',
SOURCE_PASSWORD='password',
SOURCE_LOG_FILE='mysql-bin.000001',
SOURCE_LOG_POS=0;
-- 上海数据库:配置北京为主
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='beijing-db-ip',
SOURCE_USER='repl',
SOURCE_PASSWORD='password',
SOURCE_LOG_FILE='mysql-bin.000001',
SOURCE_LOG_POS=0;
-- 启动双向复制
START REPLICA;数据冲突处理:
// 数据冲突检测与解决
class ConflictResolver {
constructor() {
this.strategy = 'last-write-wins' // 最后写入胜出
}
// 检测冲突
detectConflict(localData, remoteData) {
if (localData.version === remoteData.version) {
return localData.timestamp !== remoteData.timestamp
}
return false
}
// 解决冲突
resolveConflict(localData, remoteData) {
switch (this.strategy) {
case 'last-write-wins':
// 最后写入胜出
return localData.timestamp > remoteData.timestamp
? localData
: remoteData
case 'first-write-wins':
// 最先写入胜出
return localData.timestamp < remoteData.timestamp
? localData
: remoteData
case 'merge':
// 合并策略
return this.merge(localData, remoteData)
case 'manual':
// 人工介入
return this.requireManualIntervention(localData, remoteData)
default:
throw new Error('未知的冲突解决策略')
}
}
// 合并数据
merge(localData, remoteData) {
return {
...localData,
...remoteData,
merged: true,
mergedAt: Date.now()
}
}
// 需要人工介入
requireManualIntervention(localData, remoteData) {
// 将冲突数据写入待处理队列
this.writeToConflictQueue(localData, remoteData)
// 发送告警
this.sendAlert({
type: 'data_conflict',
localData,
remoteData,
timestamp: Date.now()
})
// 临时使用某个版本
return localData
}
}定义:应用层面的冗余,通过负载均衡自动路由,但数据库可能是共享的
应用双活架构:
用户请求
↓
┌──────────────┐
│ 负载均衡器 │
└──────┬───────┘
│
┌───┴───┐
│ │
↓ ↓
┌─────┐ ┌─────┐
│应用A │ │应用B │
│(北京)│ │(上海)│
└──┬──┘ └──┬──┘
│ │
└───┬───┘
│
↓
┌──────────────┐
│ 共享数据库 │ ← 单点依赖
│ (主从架构) │
└──────────────┘
特点:
- 应用层多活
- 数据库共享(可能成为瓶颈)
- 部署相对简单
- 成本较低应用双活实现:
// 应用双活负载均衡
class ApplicationLoadBalancer {
constructor() {
this.appInstances = {
beijing: {
url: 'http://app-bj.example.com',
status: 'active',
weight: 50,
health: 100
},
shanghai: {
url: 'http://app-sh.example.com',
status: 'active',
weight: 50,
health: 100
}
}
}
// 路由请求
route(userId) {
const activeApps = this.getActiveApps()
if (activeApps.length === 0) {
throw new Error('无可用应用实例')
}
// 根据权重选择
const selected = this.selectByWeight(activeApps, userId)
return this.appInstances[selected]
}
// 获取活跃应用
getActiveApps() {
return Object.keys(this.appInstances).filter(
app => this.appInstances[app].status === 'active' &&
this.appInstances[app].health > 80
)
}
// 按权重选择
selectByWeight(apps, userId) {
// 一致性哈希(同一用户路由到同一应用)
const hash = this.hashUserId(userId)
let totalWeight = 0
const weightRanges = []
apps.forEach(app => {
const start = totalWeight
totalWeight += this.appInstances[app].weight
weightRanges.push({ app, start, end: totalWeight })
})
const target = hash % totalWeight
for (const range of weightRanges) {
if (target >= range.start && target < range.end) {
return range.app
}
}
return apps[0]
}
// 哈希用户 ID
hashUserId(userId) {
let hash = 0
for (let char of String(userId)) {
hash = (hash << 5) - hash + char.charCodeAt(0)
}
return Math.abs(hash)
}
// 健康检查
async healthCheck() {
for (const app of Object.keys(this.appInstances)) {
const isHealthy = await this.checkAppHealth(app)
this.appInstances[app].health = isHealthy ? 100 : 0
if (!isHealthy && this.appInstances[app].status === 'active') {
this.failover(app)
}
}
}
// 检查应用健康
async checkAppHealth(appName) {
const app = this.appInstances[appName]
try {
const response = await fetch(`${app.url}/health`, {
signal: AbortSignal.timeout(3000)
})
return response.ok
} catch (error) {
return false
}
}
// 故障转移
failover(failedApp) {
console.log(`应用 ${failedApp} 故障,开始转移`)
this.appInstances[failedApp].status = 'failed'
this.appInstances[failedApp].weight = 0
// 将权重分配给其他应用
const activeApps = this.getActiveApps()
const weight = 50 / activeApps.length
activeApps.forEach(app => {
this.appInstances[app].weight += weight
})
}
}应用层面四层架构:
┌─────────────────────────────────┐
│ Layer 4: OS 层 │ ← 操作系统层
│ (Windows / Linux / Unix) │
├─────────────────────────────────┤
│ Layer 3: 数据库层 │ ← 数据库层
│ (MySQL / Oracle / MongoDB) │
├─────────────────────────────────┤
│ Layer 2: 应用层 │ ← 业务逻辑层
│ (业务代码 / API / 服务) │
├─────────────────────────────────┤
│ Layer 1: IP 层 │ ← 网络层
│ (IP 地址 / 路由 / DNS) │
└─────────────────────────────────┘各层职责:
| 层次 | 名称 | 职责 | 示例技术 |
|---|---|---|---|
| Layer 1 | IP 层 | 网络通信、路由 | DNS、BGP、VIP |
| Layer 2 | 应用层 | 业务逻辑处理 | Nginx、Tomcat、Node.js |
| Layer 3 | 数据库层 | 数据存储与查询 | MySQL、Redis、MongoDB |
| Layer 4 | OS 层 | 系统资源管理 | Linux、Windows Server |
数据层面三层架构:
┌─────────────────────────────────┐
│ Layer 3: 存储层 │ ← 磁盘存储
│ (磁盘阵列 / SAN / NAS) │
├─────────────────────────────────┤
│ Layer 2: 存储区域网络层 │ ← 数据传输网络
│ (光纤通道 / iSCSI / FCoE) │
├─────────────────────────────────┤
│ Layer 1: 存储虚拟化层 │ ← 存储池化管理
│ (存储虚拟化 / SDS) │
└─────────────────────────────────┘各层职责:
| 层次 | 名称 | 职责 | 示例技术 |
|---|---|---|---|
| Layer 1 | 存储虚拟化层 | 存储资源池化 | VMware vSAN、Ceph、GlusterFS |
| Layer 2 | 存储区域网络层 | 数据传输网络 | FC、iSCSI、Fibre Channel |
| Layer 3 | 存储层 | 物理存储介质 | RAID、SSD、HDD |
// 容灾层次理解示例
// 场景:用户查询订单信息
const userQueryScenario = {
// Layer 1: IP 层(网络通信)
ipLayer: {
description: '用户请求通过网络到达服务器',
technologies: ['DNS 解析', '路由转发', 'TCP/IP 通信'],
example: `
用户 → DNS 查询 → CDN 节点 → 负载均衡 → 应用服务器
`
},
// Layer 2: 应用层(业务逻辑)
applicationLayer: {
description: '应用服务器处理业务请求',
technologies: ['API 网关', '业务逻辑', '数据聚合'],
example: `
应用服务器接收请求 → 验证权限 → 调用数据库 → 返回结果
`
},
// Layer 3: 数据库层(数据存储)
databaseLayer: {
description: '数据库执行查询操作',
technologies: ['SQL 查询', '索引优化', '缓存'],
example: `
SELECT * FROM orders WHERE user_id = ?
`
},
// Layer 4: OS 层(系统资源)
osLayer: {
description: '操作系统提供资源支持',
technologies: ['内存管理', '文件系统', '进程调度'],
example: `
Linux 内核 → 分配内存 → 读取磁盘 → 返回数据
`
}
}技术方案:磁盘阵列 RAID、存储厂商方案
存储层容灾架构:
主数据中心 备数据中心
┌──────────────┐ ┌──────────────┐
│ 存储阵列 A │ ←───────→ │ 存储阵列 B │
│ (EMC/NetApp) │ 同步 │ (EMC/NetApp) │
└──────────────┘ └──────────────┘
↑ ↑
│ │
应用服务器 应用服务器
特点:
- 数据强一致性
- 对应用透明
- 性能影响小
- 成本极高优势与劣势:
| 优势 | 劣势 |
|---|---|
| 数据一致性保证 | 限制存储厂商(必须同厂商) |
| 对应用透明 | 成本极高 |
| 性能影响小 | 灵活性差 |
| 可靠性高 | 扩展困难 |
适用场景:
存储层容灾适用场景:
金融核心系统
- 银行核心交易系统
- 证券交易系统
- 清算结算系统
大型企业关键业务
- ERP 系统
- CRM 系统
- 核心生产系统
中小型企业
- 成本过高
- 技术复杂厂商方案示例:
// EMC SRDF (Symmetrix Remote Data Facility)
const emcSRDF = {
name: 'EMC SRDF',
type: '存储层复制',
features: {
synchronous: {
name: '同步模式',
description: '数据实时同步,RPO=0',
distance: '< 100km',
useCase: '关键业务系统'
},
asynchronous: {
name: '异步模式',
description: '数据异步同步,RPO>0',
distance: '> 100km',
useCase: '一般业务系统'
},
consistency: {
name: '一致性保证',
description: '保证数据一致性',
mechanism: '一致性组技术'
}
},
requirements: {
storage: '必须是 EMC 存储阵列',
network: '光纤通道或 IP 网络',
software: 'SRDF 管理软件'
},
cost: {
hardware: '数百万人民币',
software: '数十万人民币',
maintenance: '年维护费约硬件成本的 15%'
}
}技术方案:数据库复制技术
数据库层容灾架构:
主数据中心 备数据中心
┌──────────────┐ ┌──────────────┐
│ 应用服务器 │ │ 应用服务器 │
└──────┬───────┘ └──────┬───────┘
│ │
↓ ↓
┌──────────────┐ ┌──────────────┐
│ MySQL 主库 │ ────────→ │ MySQL 从库 │
│ (A厂存储) │ Binlog │ (B厂存储) │
└──────────────┘ 同步 └──────────────┘
特点:
- 存储异构支持
- 占用网络带宽
- 占用应用资源
- 配置灵活优势与劣势:
| 优势 | 劣势 |
|---|---|
| 支持异构存储 | 占用网络带宽 |
| 配置灵活 | 占用应用资源 |
| 成本相对较低 | 复制延迟问题 |
| 技术成熟 | 可能影响性能 |
主流数据库容灾技术:
// 数据库容灾技术对比
const databaseDR = {
// MySQL
mysql: {
replication: {
async: '异步复制',
semiSync: '半同步复制',
group: '组复制(MGR)'
},
tools: ['MySQL Replication', 'MySQL Router', 'MHA', 'Orchestrator'],
features: [
'开源免费',
'配置简单',
'支持异构存储',
'延迟监控方便'
]
},
// Oracle
oracle: {
technologies: {
dataguard: 'Data Guard(物理/逻辑备库)',
rac: 'RAC(集群)',
goldengate: 'Golden Gate(逻辑复制)'
},
features: [
'功能强大',
'企业级支持',
'数据一致性保证',
'成本高昂'
]
},
// PostgreSQL
postgresql: {
replication: {
streaming: '流复制',
logical: '逻辑复制',
cascading: '级联复制'
},
features: [
'开源免费',
'功能丰富',
'性能优秀',
'社区活跃'
]
},
// MongoDB
mongodb: {
replication: {
replicaSet: '副本集',
sharding: '分片集群'
},
features: [
'自动故障转移',
'支持跨机房部署',
'配置简单',
'性能优秀'
]
}
}MySQL 数据库容灾实现:
// MySQL 主从复制管理
class MySQLReplicationManager {
constructor() {
this.master = {
host: 'master.db.example.com',
port: 3306,
status: 'active'
}
this.slaves = [
{ host: 'slave1.db.example.com', port: 3306, status: 'active' },
{ host: 'slave2.db.example.com', port: 3306, status: 'active' }
]
}
// 监控复制状态
async monitorReplication() {
const replicationStatus = []
for (const slave of this.slaves) {
const status = await this.getSlaveStatus(slave)
replicationStatus.push({
slave: slave.host,
ioRunning: status.Slave_IO_Running,
sqlRunning: status.Slave_SQL_Running,
secondsBehindMaster: status.Seconds_Behind_Master,
lastError: status.Last_Error
})
// 检查延迟
if (status.Seconds_Behind_Master > 10) {
this.sendAlert({
type: 'replication_lag',
slave: slave.host,
delay: status.Seconds_Behind_Master
})
}
}
return replicationStatus
}
// 获取从库状态
async getSlaveStatus(slave) {
// 实际实现:执行 SHOW REPLICA STATUS(MySQL 8.0.22 前为 SHOW SLAVE STATUS)
return {
Slave_IO_Running: 'Yes',
Slave_SQL_Running: 'Yes',
Seconds_Behind_Master: 0,
Last_Error: ''
}
}
// 主从切换
async failover(failedMaster) {
console.log('开始主从切换...')
// 1. 选择新的主库
const newMaster = this.selectNewMaster()
// 2. 停止所有从库复制
await this.stopAllSlaves()
// 3. 提升新主库
await this.promoteToMaster(newMaster)
// 4. 重新配置其他从库
await this.reconfigureSlaves(newMaster)
// 5. 更新应用配置
await this.updateApplicationConfig(newMaster)
console.log(`主从切换完成,新主库: ${newMaster.host}`)
}
// 选择新主库
selectNewMaster() {
// 选择延迟最小的从库
const sortedSlaves = this.slaves.sort((a, b) => {
return a.delay - b.delay
})
return sortedSlaves[0]
}
// 停止所有从库复制
async stopAllSlaves() {
for (const slave of this.slaves) {
// 执行 STOP REPLICA
console.log(`停止从库 ${slave.host} 复制`)
}
}
// 提升为主库
async promoteToMaster(slave) {
// 执行 RESET REPLICA ALL
console.log(`提升 ${slave.host} 为主库`)
}
// 重新配置从库
async reconfigureSlaves(newMaster) {
for (const slave of this.slaves) {
if (slave !== newMaster) {
// CHANGE REPLICATION SOURCE TO ...
console.log(`重新配置从库 ${slave.host}`)
}
}
}
// 更新应用配置
async updateApplicationConfig(newMaster) {
// 更新数据库连接配置
console.log('更新应用数据库连接配置')
}
// 发送告警
sendAlert(alert) {
console.log('发送告警:', alert)
}
}技术方案:存储虚拟化技术
存储区域网络层容灾架构:
┌─────────────────────────────────┐
│ 存储虚拟化层 │
│ (容器化技术、资源池) │
└─────────────┬───────────────────┘
│
┌─────────┼─────────┐
│ │ │
┌───┴───┐ ┌──┴────┐ ┌──┴────┐
│存储A │ │存储B │ │存储C │
│(EMC) │ │(NetApp)│ │(华为) │
└───────┘ └───────┘ └───────┘
特点:
- 存储异构支持
- 资源池化管理
- 对应用透明
- 折中方案优势与劣势:
| 优势 | 劣势 |
|---|---|
| 支持异构存储 | 技术复杂度高 |
| 资源池化管理 | 需要额外软件 |
| 灵活性好 | 性能可能有损耗 |
| 可扩展性强 | 运维成本高 |
技术实现示例:
// 存储虚拟化管理
class StorageVirtualizationLayer {
constructor() {
this.storagePool = {
emc: { capacity: 1000, used: 300, type: 'SAN' },
netapp: { capacity: 800, used: 250, type: 'NAS' },
huawei: { capacity: 600, used: 150, type: 'SAN' }
}
this.virtualVolumes = new Map()
}
// 创建虚拟卷
createVirtualVolume(name, size) {
// 选择最优存储
const selectedStorage = this.selectOptimalStorage(size)
// 创建虚拟卷
const volume = {
name,
size,
actualStorage: selectedStorage,
replicas: [],
createdAt: Date.now()
}
// 分配存储空间
this.allocateStorage(selectedStorage, size)
// 创建副本
this.createReplicas(volume)
this.virtualVolumes.set(name, volume)
return volume
}
// 选择最优存储
selectOptimalStorage(requiredSize) {
const storages = Object.keys(this.storagePool)
// 按剩余容量排序
const sorted = storages.sort((a, b) => {
const availableA = this.storagePool[a].capacity - this.storagePool[a].used
const availableB = this.storagePool[b].capacity - this.storagePool[b].used
return availableB - availableA
})
// 选择第一个满足容量要求的存储
for (const storage of sorted) {
const available = this.storagePool[storage].capacity - this.storagePool[storage].used
if (available >= requiredSize) {
return storage
}
}
throw new Error('没有足够的存储空间')
}
// 分配存储空间
allocateStorage(storageName, size) {
this.storagePool[storageName].used += size
}
// 创建副本
async createReplicas(volume) {
// 选择其他存储作为副本
const otherStorages = Object.keys(this.storagePool)
.filter(s => s !== volume.actualStorage)
// 创建副本(简化示例)
for (const storage of otherStorages.slice(0, 1)) {
volume.replicas.push({
storage,
size: volume.size,
status: 'syncing'
})
// 异步同步数据
this.syncReplica(volume, storage)
}
}
// 同步副本
async syncReplica(volume, targetStorage) {
console.log(`同步卷 ${volume.name} 到 ${targetStorage}`)
// 模拟同步过程
setTimeout(() => {
const replica = volume.replicas.find(r => r.storage === targetStorage)
if (replica) {
replica.status = 'synced'
}
console.log(`卷 ${volume.name} 同步完成`)
}, 1000)
}
// 读取数据
async read(volumeName) {
const volume = this.virtualVolumes.get(volumeName)
if (!volume) {
throw new Error(`卷 ${volumeName} 不存在`)
}
// 从主存储读取
return this.readFromStorage(volume.actualStorage, volumeName)
}
// 写入数据
async write(volumeName, data) {
const volume = this.virtualVolumes.get(volumeName)
if (!volume) {
throw new Error(`卷 ${volumeName} 不存在`)
}
// 写入主存储
await this.writeToStorage(volume.actualStorage, volumeName, data)
// 异步同步到副本
for (const replica of volume.replicas) {
this.syncReplica(volume, replica.storage)
}
}
// 从存储读取
async readFromStorage(storageName, volumeName) {
console.log(`从 ${storageName} 读取卷 ${volumeName}`)
return { data: 'example' }
}
// 写入到存储
async writeToStorage(storageName, volumeName, data) {
console.log(`写入 ${storageName} 卷 ${volumeName}`)
}
}| 对比维度 | 存储层容灾 | 数据库层容灾 | 存储区域网络层容灾 |
|---|---|---|---|
| 存储异构 | 必须同厂商 | 支持异构 | 支持异构 |
| 性能影响 | 小 | 占用资源 | 中等 |
| 数据一致性 | 强一致 | 最终一致 | 最终一致 |
| 实现成本 | 极高 | 较低 | 中等 |
| 技术复杂度 | 中等 | 简单 | 复杂 |
| 灵活性 | 差 | 好 | 好 |
| 扩展性 | 困难 | 容易 | 容易 |
选择建议:
const selectionGuide = {
// 场景1: 金融核心系统
finance: {
budget: '充足',
requirement: '数据强一致',
recommendation: '存储层容灾',
reason: '数据一致性要求极高,成本不是主要考虑因素'
},
// 场景2: 互联网应用
internet: {
budget: '有限',
requirement: '高可用、灵活扩展',
recommendation: '数据库层容灾',
reason: '成本可控,技术成熟,扩展性好'
},
// 场景3: 大型企业
enterprise: {
budget: '中等',
requirement: '异构存储支持',
recommendation: '存储区域网络层容灾',
reason: '已有多种存储设备,需要统一管理'
}
}容灾切换流程:
1. 故障检测
├── 监控系统告警
├── 人工确认故障
└── 评估影响范围
2. 决策判断
├── 是否需要切换?
├── 切换到哪个站点?
└── 切换策略(全量/部分)
3. 数据同步检查
├── 检查数据一致性
├── 确认数据完整性
└── 计算数据丢失量
4. 执行切换
├── 停止主站点服务
├── 激活备站点
└── 更新 DNS/路由
5. 验证服务
├── 功能验证
├── 性能测试
└── 监控指标
6. 通知相关方
├── 内部团队
├── 外部用户
└── 合作伙伴// 容灾切换管理器
class DisasterRecoveryManager {
constructor() {
this.sites = {
primary: {
name: '北京主站',
status: 'active',
datacenter: 'beijing',
lastSync: Date.now()
},
secondary: {
name: '上海备站',
status: 'standby',
datacenter: 'shanghai',
lastSync: Date.now() - 5000
}
}
this.switchInProgress = false
}
// 执行容灾切换
async executeFailover(reason) {
if (this.switchInProgress) {
throw new Error('切换正在进行中')
}
this.switchInProgress = true
try {
console.log(`开始容灾切换,原因: ${reason}`)
// 1. 故障检测
const faultInfo = await this.detectFault()
console.log('故障检测结果:', faultInfo)
// 2. 决策判断
const decision = await this.makeDecision(faultInfo)
console.log('切换决策:', decision)
if (!decision.needSwitch) {
console.log('无需切换')
return
}
// 3. 数据同步检查
const syncStatus = await this.checkDataSync()
console.log('数据同步状态:', syncStatus)
// 4. 执行切换
await this.performSwitch(decision.targetSite)
// 5. 验证服务
await this.verifyService()
// 6. 通知相关方
await this.notifyStakeholders(reason)
console.log('容灾切换完成')
} catch (error) {
console.error('容灾切换失败:', error)
// 回滚
await this.rollback()
throw error
} finally {
this.switchInProgress = false
}
}
// 检测故障
async detectFault() {
return {
type: 'network',
severity: 'critical',
affectedServices: ['app', 'database'],
timestamp: Date.now()
}
}
// 决策判断
async makeDecision(faultInfo) {
// 评估故障严重程度
if (faultInfo.severity === 'critical') {
return {
needSwitch: true,
targetSite: 'secondary',
strategy: 'full'
}
}
return {
needSwitch: false
}
}
// 检查数据同步
async checkDataSync() {
const primary = this.sites.primary
const secondary = this.sites.secondary
const timeDiff = primary.lastSync - secondary.lastSync
return {
syncDelay: timeDiff,
dataLoss: timeDiff > 60000, // 超过 1 分钟认为有数据丢失
estimatedDataLoss: timeDiff > 60000 ? `${Math.floor(timeDiff / 1000)}秒` : '无'
}
}
// 执行切换
async performSwitch(targetSite) {
console.log(`切换到 ${targetSite} 站点`)
// 1. 停止主站点
await this.stopSite('primary')
// 2. 激活备站点
await this.activateSite(targetSite)
// 3. 更新 DNS
await this.updateDNS(targetSite)
// 4. 更新路由
await this.updateRouting(targetSite)
}
// 停止站点
async stopSite(siteName) {
const site = this.sites[siteName]
site.status = 'stopped'
console.log(`停止站点 ${site.name}`)
}
// 激活站点
async activateSite(siteName) {
const site = this.sites[siteName]
site.status = 'active'
console.log(`激活站点 ${site.name}`)
}
// 更新 DNS
async updateDNS(targetSite) {
const site = this.sites[targetSite]
console.log(`更新 DNS 指向 ${site.datacenter}`)
}
// 更新路由
async updateRouting(targetSite) {
const site = this.sites[targetSite]
console.log(`更新路由到 ${site.datacenter}`)
}
// 验证服务
async verifyService() {
console.log('验证服务...')
// 1. 检查应用健康
const appHealth = await this.checkAppHealth()
// 2. 检查数据库连接
const dbHealth = await this.checkDatabaseHealth()
// 3. 检查核心功能
const coreFunctions = await this.testCoreFunctions()
if (!appHealth || !dbHealth || !coreFunctions) {
throw new Error('服务验证失败')
}
console.log('服务验证通过')
}
// 检查应用健康
async checkAppHealth() {
// 模拟健康检查
return true
}
// 检查数据库健康
async checkDatabaseHealth() {
// 模拟数据库连接检查
return true
}
// 测试核心功能
async testCoreFunctions() {
// 模拟核心功能测试
return true
}
// 通知相关方
async notifyStakeholders(reason) {
console.log('通知相关方...')
// 1. 通知内部团队
await this.notifyInternalTeam(reason)
// 2. 通知外部用户
await this.notifyExternalUsers(reason)
// 3. 通知合作伙伴
await this.notifyPartners(reason)
}
// 通知内部团队
async notifyInternalTeam(reason) {
console.log('通知内部团队:', reason)
}
// 通知外部用户
async notifyExternalUsers(reason) {
console.log('通知外部用户')
}
// 通知合作伙伴
async notifyPartners(reason) {
console.log('通知合作伙伴')
}
// 回滚
async rollback() {
console.log('开始回滚...')
// 恢复原站点
await this.activateSite('primary')
// 恢复 DNS
await this.updateDNS('primary')
console.log('回滚完成')
}
}
// 使用示例
const drManager = new DisasterRecoveryManager()
// 模拟故障触发切换
drManager.executeFailover('主站网络故障')容灾演练目的:
1. 验证预案有效性
├── 测试切换流程
├── 验证数据完整性
└── 评估恢复时间
2. 发现潜在问题
├── 配置错误
├── 流程缺陷
└── 人员能力不足
3. 提升团队协作
├── 明确职责分工
├── 加强沟通协作
└── 提高应急能力
4. 优化改进
├── 完善预案
├── 优化流程
└── 更新文档// 容灾演练类型
const drillTypes = {
// 桌面演练
desktop: {
description: '通过讨论和模拟方式演练',
frequency: '每季度',
duration: '2-4小时',
participants: '技术团队、运维团队',
cost: '低'
},
// 模拟演练
simulation: {
description: '在测试环境进行实际操作',
frequency: '每半年',
duration: '1天',
participants: '技术团队、运维团队、测试团队',
cost: '中'
},
// 实战演练
actual: {
description: '在生产环境进行真实切换',
frequency: '每年',
duration: '1-2天',
participants: '全体相关人员',
cost: '高',
risk: '有业务影响风险'
}
}容灾演练流程:
准备阶段
├── 制定演练计划
├── 通知相关人员
├── 准备演练环境
└── 备份数据
执行阶段
├── 启动演练
├── 模拟故障
├── 执行切换
└── 验证服务
评估阶段
├── 记录演练过程
├── 评估演练效果
├── 发现问题
└── 提出改进建议
总结阶段
├── 编写演练报告
├── 优化预案
├── 更新文档
└── 组织培训| 问题 | 原因 | 解决方案 |
|---|---|---|
| 数据丢失 | 异步复制延迟 | 半同步复制、多副本 |
| 切换时间长 | 流程不清晰 | 自动化切换工具 |
| 切换失败 | 配置错误 | 定期演练、验证配置 |
| 数据不一致 | 复制冲突 | 冲突检测与解决机制 |
| 成本过高 | 全量容灾 | 分级容灾策略 |
| 网络延迟大 | 距离过远 | 选择合适城市组合 |
容灾模式分类:
异地双活限制:
容灾技术方案对比:
容灾层次架构:
容灾最佳实践:
// 容灾架构设计检查清单
const drChecklist = {
// 规划阶段
planning: [
' 确定容灾目标(RTO/RPO)',
' 选择容灾模式',
' 评估成本预算',
' 选择技术方案'
],
// 实施阶段
implementation: [
' 搭建容灾环境',
' 配置数据同步',
' 实现自动切换',
' 测试验证功能'
],
// 运维阶段
operations: [
' 监控同步状态',
' 定期演练',
' 更新预案文档',
' 培训相关人员'
],
// 关键指标
metrics: {
rto: '恢复时间目标',
rpo: '恢复点目标',
availability: '可用性百分比',
switchTime: '切换时间'
}
}笔记整理完成!
这份笔记详细讲解了异地容灾与多活架构的核心概念、容灾模式分类、技术方案对比、容灾切换流程和演练方法,并结合实际案例和代码示例,帮助理解容灾架构设计的核心思想。建议结合实际项目进行容灾设计和演练。