高可用增强
EnerOS v0.41.0 引入生产级高可用能力,支持多区域部署、WAL 复制、灾难恢复(DR)、CRDT 状态同步与零停机滚动升级。配合 SLO/SLI 错误预算与 AIOps 告警聚类,提供 99.99% 可用性保障。高可用能力由 eneros-ha crate 提供,与 eneros-multiregion、eneros-os 协同工作。
高可用架构
┌─────────────────────────────────────────────────────────────┐
│ 全局 DNS / 负载均衡 │
│ 按地理就近 + 健康度路由 │
└──────────────┬──────────────────────┬───────────────────────┘
│ │
┌──────────────▼──────────┐ ┌────────▼──────────────────────┐
│ 区域 A: cn-east-1 │ │ 区域 B: cn-south-1 │
│ ┌─────────────────┐ │ │ ┌─────────────────┐ │
│ │ Active Cluster │◀───┼──┼─▶│ Active Cluster │ │
│ │ 3 节点 Raft │ │ │ │ 3 节点 Raft │ │
│ └────────┬────────┘ │ │ └────────┬────────┘ │
│ │ │ │ │ │
│ WAL 复制 │ │ WAL 复制 │
│ ┌───────┴───────┐ │ │ ┌───────┴───────┐ │
│ │ Replica 1/2 │ │ │ │ Replica 1/2 │ │
│ └───────────────┘ │ │ └───────────────┘ │
└─────────────────────────┘ └──────────────────────────────┘
▲ ▲
│ CRDT 异步合并 │
└──────────────────────┘
| 能力 | 实现方式 | 适用域 |
|---|
| 多副本 | Raft 共识 | 通用域 + 实时域 |
| WAL 复制 | 同步 + 异步混合 | 通用域 + 实时域 |
| 自动故障转移 | 心跳检测 + 投票 | 通用域 + 实时域 |
| 滚动升级 | 灰度 + 批次 | 通用域 + 实时域(最后) |
| CRDT 同步 | 最终一致 | 仅通用域 |
| 灾备 DR | 区域级切换 | 通用域 + 实时域 |
多区域部署
支持 Active-Active 与 Active-Standby 两种模式。Active-Active 模式下两个区域同时承接流量,写操作通过 CRDT 合并;Active-Standby 模式下备用区域实时同步主区域数据,故障时秒级切换。
use eneros_ha::{Cluster, Region, RegionRole, Topology, Consensus};
let cluster = Cluster::new()
.region(Region::new("cn-east-1")
.role(RegionRole::Active)
.nodes(3)
.priority(100))
.region(Region::new("cn-south-1")
.role(RegionRole::Active)
.nodes(3)
.priority(90))
.topology(Topology::ActiveActive)
.consensus(Consensus::Raft)
.replication_factor(3)
.read_quorum(Quorum::Majority)
.write_quorum(Quorum::Majority);
cluster.deploy().await?;
部署模式对比
| 模式 | 写性能 | 故障切换时间 | 成本 | 适用 |
|---|
| Active-Active | 高(双写) | 0s(无切换) | 高 | 关键业务 |
| Active-Standby | 中(主写) | < 60s | 中 | 一般业务 |
| Multi-Active | 高(多写) | 0s | 极高 | 跨国部署 |
| Pilot-Light | 低 | < 5min | 低 | 备份场景 |
WAL 复制
所有写入操作通过 Write-Ahead Log 复制到副本,确保 RPO ≈ 0。WAL 采用同步与异步混合复制:本地副本同步复制保证强一致,跨区域副本异步复制降低延迟。
use eneros_ha::wal::{WalConfig, Replication, Compression, KeyId};
let wal = WalConfig::new()
.replication(Replication::hybrid()
.sync_replicas(2) // 本地同步 2 副本
.async_replicas(1) // 跨区域异步 1 副本
.ack_timeout(Duration::from_millis(500)))
.flush_interval(Duration::from_millis(1))
.segment_size(64 * 1024 * 1024) // 64MB 段
.compression(Compression::Zstd)
.encryption(KeyId::from("wal-key"))
.checksum(ChecksumAlgo::Crc32c);
kernel.enable_wal(wal).await?;
复制拓扑
Primary ──sync──▶ Replica 1 (本地)
│
├──sync──▶ Replica 2 (本地)
│
└──async──▶ Replica 3 (跨区域, cn-south-1)
WAL 配置参数
| 参数 | 默认值 | 说明 |
|---|
| sync_replicas | 2 | 同步副本数 |
| async_replicas | 1 | 异步副本数 |
| flush_interval | 1ms | 刷盘间隔 |
| segment_size | 64MB | 单段大小 |
| compression | Zstd | 压缩算法 |
| encryption | AES-256-GCM | 加密算法 |
| ack_timeout | 500ms | 同步 ACK 超时 |
| checksum | CRC32C | 校验算法 |
CRDT 状态同步
对于非关键状态(如 Agent 记忆、缓存、计数器),采用 CRDT(Conflict-Free Replicated Data Type)实现最终一致性,避免同步延迟阻塞写操作。
use eneros_ha::crdt::{CrdtStore, GCounter, ORSet, LwwMap};
let store = CrdtStore::new()
.replication(Replication::all())
.anti_entropy(Duration::from_secs(1));
// 增长计数器(CRDT)
let counter = store.gcounter("agent.decisions");
counter.increment(1).await?;
// 集合(CRDT)
let set = store.or_set("active.agents");
set.insert("dispatch_agent").await?;
set.remove("dispatch_agent").await?;
// Last-Write-Wins Map
let map = store.lww_map("agent.memory");
map.insert("dispatch_agent", memory_blob, now()).await?;
// 自动跨区域合并,无冲突
CRDT 类型矩阵
| 类型 | 语义 | 适用 |
|---|
| GCounter | 只增计数器 | 决策计数、事件计数 |
| PNCounter | 可增可减计数器 | 容量、配额 |
| ORSet | Observed-Remove Set | Agent 集合 |
| LwwMap | Last-Write-Wins Map | 缓存、记忆 |
| RGA | Replicated Growable Array | 协作编辑 |
灾难恢复(DR)
区域级故障时自动切换到备用区域,保证业务连续性:
use eneros_ha::dr::{DrPlan, FailoverPolicy, Detection, DnsSwitch, HealthCheck};
let plan = DrPlan::new()
.rto(Duration::from_secs(60)) // 恢复时间目标
.rpo(Duration::from_secs(0)) // 数据丢失目标
.failover_policy(FailoverPolicy::automatic(
Detection::heartbeat(Duration::from_secs(10)),
Confirmation::nodes(2), // 2 个节点确认故障
))
.dns_switch(DnsSwitch::auto()
.ttl(Duration::from_secs(30)))
.health_check(HealthCheck::post_failover()
.timeout(Duration::from_secs(60)))
.notify(vec!["ops@grid.com", "soc@grid.com"]);
plan.activate().await?;
DR 演练
定期自动执行 DR 演练,验证灾备能力:
plan.drill()
.simulate(Scenario::region_failure("cn-east-1"))
.verify(SLO::availability(99.99))
.verify(SLO::latency_p99(Duration::from_millis(100)))
.schedule(Duration::from_secs(86400 * 30)) // 每月
.notify_on_failure(vec!["ops@grid.com"])
.run().await?;
DR 关键指标
| 指标 | 目标值 | 说明 |
|---|
| RTO | < 60s | 恢复时间目标 |
| RPO | 0 | 数据丢失目标 |
| 故障检测 | < 10s | 心跳超时 |
| 切换确认 | < 5s | 节点投票 |
| DNS 切换 | < 30s | TTL 过期 |
| 健康验证 | < 60s | 切换后检查 |
| 演练成功率 | > 95% | 月度目标 |
滚动升级
零停机滚动升级,实时域与通用域分别升级。升级过程支持金丝雀发布、自动回滚:
use eneros_ha::upgrade::{RollingUpgrade, Strategy, HealthCheck};
let upgrade = RollingUpgrade::new("v0.47.0")
.strategy(Strategy::canary(10) // 10% 灰度
.observe(Duration::from_secs(300))
.promote_on(HealthCheck::all_healthy()))
.batch_size(1)
.batch_interval(Duration::from_secs(30))
.health_check(Duration::from_secs(60))
.rollback_on_failure(true)
.rollback_threshold(0.05) // 失败率 > 5% 触发回滚
.realtime_domain_last(true); // 实时域最后升级
upgrade.execute().await?;
升级策略对比
| 策略 | 速度 | 风险 | 适用 |
|---|
| Rolling | 慢 | 低 | 常规升级 |
| Canary | 中 | 极低 | 重要版本 |
| Blue-Green | 快 | 中 | 大版本 |
| A/B Test | 慢 | 极低 | 验证特性 |
SLO / SLI 错误预算
use eneros_ha::slo::{Slo, Sli, ErrorBudget, Alert};
let slo = Slo::new()
.availability(99.99) // 4 个 9
.window(Duration::from_secs(86400 * 30))
.sli(Sli::success_rate())
.sli(Sli::latency_p99(Duration::from_millis(100)))
.error_budget(ErrorBudget::consume_on_incident())
.alert(Alert::on_budget_exhausted(0.2)); // 剩余 20% 时告警
slo.activate().await?;
// 查看错误预算剩余
let remaining = slo.error_budget_remaining().await?;
println!("剩余错误预算: {:.2}%", remaining * 100.0);
// 查看历史 SLO 达成情况
let history = slo.history(Range::last(Duration::from_secs(86400 * 90))).await?;
for day in history {
println!("{}: 可用性 {:.4f}%, 预算消耗 {:.2}%",
day.date, day.availability * 100.0, day.budget_consumed * 100.0);
}
SLO 级别
| 级别 | 可用性 | 月度停机 | 适用 |
|---|
| 标准 | 99.9% | 43 分钟 | 开发测试 |
| 生产 | 99.95% | 21 分钟 | 一般业务 |
| 关键 | 99.99% | 4.3 分钟 | 核心业务 |
| 极致 | 99.999% | 26 秒 | 保护控制 |
AIOps 告警聚类
基于 ML 的告警聚类与根因分析,避免告警风暴:
use eneros_ha::aiops::{AlertCorrelator, RootCauseAnalysis, CorrelationAlgorithm};
let correlator = AlertCorrelator::new()
.algorithm(CorrelationAlgorithm::dbscan()
.eps(Duration::from_secs(60))
.min_samples(3))
.window(Duration::from_secs(60))
.dedup(true)
.on_cluster(|cluster| async move {
println!("告警聚类: {} 条告警", cluster.alerts.len());
let rca = RootCauseAnalysis::analyze(&cluster).await?;
println!("根因: {} (置信度 {:.0}%)",
rca.root_cause, rca.confidence * 100.0);
notify_oncall(&rca).await?;
Ok(())
});
correlator.start().await?;
RCA 算法
| 算法 | 输入 | 输出 | 准确率 |
|---|
| 因果图 | 告警 + 拓扑 | 根因节点 | 85% |
| 频谱分析 | 时序指标 | 异常分量 | 78% |
| 决策树 | 历史告警 | 规则匹配 | 92% |
| LLM 推理 | 告警 + 日志 | 自然语言解释 | 88% |
性能指标
| 指标 | 数值 | 备注 |
|---|
| 可用性(SLO) | 99.99% | 月度目标 |
| RPO(同步复制) | 0 | 关键数据 |
| RPO(异步复制) | < 1s | 跨区域 |
| RTO(自动故障转移) | < 60s | 含 DNS 切换 |
| 跨区域复制延迟 | < 5ms | 同地域 |
| 跨区域复制延迟 | < 50ms | 跨地域 |
| 滚动升级单节点 | < 30s | 含健康检查 |
| DR 演练成功率 | > 95% | 月度统计 |
| 故障检测时间 | < 10s | 心跳超时 |
| 告警聚类延迟 | < 5s | 含 RCA |
高可用能力矩阵
| 能力 | 通用域 | 实时域 |
|---|
| 多副本 | ✅ Raft | ✅ Raft |
| WAL 复制 | ✅ 同步+异步 | ✅ 全同步 |
| 自动故障转移 | ✅ < 60s | ✅ < 1s |
| 滚动升级 | ✅ 灰度 | ✅ 最后升级 |
| CRDT 同步 | ✅ | ❌(强一致) |
| DR | ✅ | ✅ |
| SLO 监控 | ✅ 99.99% | ✅ 99.999% |
| AIOps | ✅ | ✅ |
与其他能力的关系
- 运维自动化:运维自动化是高可用的执行层,详见 运维自动化
- 实时双执行域:实时域故障切换要求秒级,详见 实时双执行域
- 多租户隔离:租户级高可用按租户配置 SLO,详见 多租户与隔离
- 零信任:跨区域复制强制 mTLS 加密,详见 零信任与安全增强
- 时序原生:时序数据跨区域复制保证 RPO=0
相关文档