跳到主要内容

容灾切换流程

Testudo V2 的容灾切换采用 Pilot Light(长明火) 模式。正常保护期间,数据和资源持续同步到备集群;备集群提前保留可切换的资源骨架,但工作负载默认保持 replicas=0,不对外提供业务流量。发生切换时,operator 拉起备集群工作负载,并更新实例的主备角色。

本文说明实例级 Failover 的执行流程。具体控制台操作示例见 执行实例级故障切换 Failover

如果切换步骤失败或超时,operator 会按失败阶段尝试自动补偿。补偿机制见 容灾切换失败自动补偿机制

Pilot Light 长明火切换流程

可编辑图源:pilot-light-failover-workflow.excalidraw

长明火模式

长明火模式下,容灾实例在 Protected 状态时保持以下关系:

对象主集群备集群
业务工作负载正常运行已恢复资源骨架,副本数为 0
数据持续备份持续恢复或准备恢复
Kubernetes 资源原始资源经 ResourceSync 恢复后的 standby 资源
对外流量由外部流量系统指向主集群不承载生产流量

这种模式的目标是降低冷恢复时间。切换时不需要从零创建全部资源,而是基于备集群已有的资源骨架拉起工作负载。

前置状态

执行 Failover 前,实例通常应处于 Protected 状态:

primaryCluster = 当前主集群
secondaryCluster = 当前备集群
fsmState = Protected

同时应确认:

  • DataSync 最近一次同步成功。
  • ResourceSync 最近一次同步成功。
  • 目标集群存在 standby 资源。
  • 目标集群具备业务镜像、Secret、StorageClass、IngressClass、CRD 和网络依赖。
  • 外部 DNS、网关、负载均衡或流量切换方案已准备。

Testudo 负责 Kubernetes 资源和数据同步编排,不直接替代外部全局流量管理。

标准切换步骤

Failover 会创建 operationType=failoverDisasterOperation。当前实现的步骤顺序是:

PreCheck
-> PauseSchedules
-> FinalSync
-> ScaleDownSource
-> ScaleUpTarget
-> CheckReplicas
-> SwitchRoles

1. PreCheck

operator 检查实例、基础配置、集群、存储仓库、ResourceSync/DataSync 状态和资源修改规则。

这一步会尽量在破坏性动作前发现问题。如果预检查失败,操作不会进入源端缩容。

2. PauseSchedules

暂停 DataSync 和 ResourceSync 的周期调度,避免切换过程中又触发新的同步任务。

3. FinalSync

触发最后一次 DataSync 和 ResourceSync,并等待同步完成。

当前实现中,FinalSync 必须在 ScaleDownSource 之前执行。原因是 Velero FSB 依赖仍在运行的 Pod 读取 PVC 数据;如果先把源端 Pod 缩到 0,最后一次数据同步可能无法包含 PVC 数据。

如果用户选择跳过最终同步,operator 会跳过该步骤,使用最近一次成功同步点进行切换。

4. ScaleDownSource

缩容当前主集群中的受保护工作负载,降低双写和脑裂风险。

执行缩容前,operator 会记录工作负载原始副本数,用于后续在目标集群恢复副本数。记录失败不会直接阻断切换,但会产生告警事件。

如果用户选择跳过源端缩容,operator 不会修改源集群工作负载。此时必须依赖外部流量治理或人工手段避免源、目标两端同时写入。

5. ScaleUpTarget

在当前备集群中恢复 Deployment、StatefulSet 等工作负载副本数。

operator 优先读取 ResourceSync 记录的副本数;如果目标集群资源仍是 standby 形态,即 replicas=0,则按记录恢复为原始副本数。

6. CheckReplicas

检查目标集群工作负载副本是否达到期望状态。

如果配置了等待 Pod 就绪,operator 会等待目标侧 Pod Ready 后再继续。若选择跳过容器就绪检查,该步骤只做较轻量的状态确认。

7. SwitchRoles

切换实例角色关系:

切换前:
primaryCluster = A
secondaryCluster = B
fsmState = Protected

切换后:
primaryCluster = B
secondaryCluster = A
fsmState = Active

切换成功后,实例进入 Active。这表示目标集群已经接管业务,但当前实例还没有重新建立反向保护,所以控制台通常展示为未保护或待反向保护状态。

切换参数

常用参数如下:

参数含义典型场景
skipFinalSync跳过最后一次同步源集群不可达,或需要使用最近一次成功同步点快速切换
skipScaleDownSource跳过源端缩容源集群不可达,或由外部系统确保源端不会继续接收写流量
force允许源集群不可达时继续执行灾难场景,源集群 API Server 无法访问
timeoutMinutes操作超时时间大数据量最终同步或大规模工作负载拉起时应适当调大
skipPodReadyCheck跳过 Pod Ready 检查业务健康由外部系统确认,或需要先完成资源层切换

标准生产切换通常不跳过最终同步,也不跳过源端缩容:

{
"operation": "failover",
"config": {
"skipFinalSync": false,
"skipScaleDownSource": false,
"force": false,
"timeoutMinutes": 30,
"skipPodReadyCheck": false
}
}

源集群不可达时,通常使用强制切换参数:

{
"operation": "failover",
"config": {
"force": true,
"skipFinalSync": true,
"skipScaleDownSource": true,
"timeoutMinutes": 30
}
}

强制切换会牺牲最后一次同步点,RPO 取决于最近一次成功同步结果。

API

实例级切换接口:

POST /apis/disasterinstances.testudo.softcdata.com/v1/instances/:name/actions

请求示例:

{
"operation": "failover",
"config": {
"timeoutMinutes": 30,
"skipFinalSync": false,
"skipScaleDownSource": false,
"skipPodReadyCheck": false
}
}

组级切换接口:

POST /apis/disastergroups.testudo.softcdata.com/v1/groups/:name/actions

组级 Failover 会按 DisasterGroup 的 levels 展开实例切换。同一 level 内可以并行执行,下一 level 会等待当前 level 完成。

观察切换进度

查看实例状态:

kubectl -n disaster-system get disasterinstance <instance-name> -o wide
kubectl -n disaster-system get disasterinstance <instance-name> -o yaml

查看操作状态和步骤:

kubectl -n disaster-system get disasteroperation \
-l testudo.softcdata.com/instance=<instance-name>

kubectl -n disaster-system describe disasteroperation <operation-name>

重点关注:

  • status.state
  • status.currentStep
  • status.steps
  • status.reason
  • status.message
  • status.autoCancelTriggered
  • status.autoCancelStatus
  • status.autoCancelMode
  • status.autoCancelSteps
  • status.manualInterventionRequired

切换后处理

Failover 成功后,需要根据业务决策选择后续动作:

操作适用场景结果
反向保护 Reprotect目标集群已接管生产,后续长期以目标集群为主重新建立 B -> A 的保护关系,实例回到 Protected
撤销切换 Undo误切或临时切换后需要回到原主集群缩容当前目标,拉起原主,恢复 A -> B 保护关系
中止 Cancel操作卡住或人工决定停止当前操作停止继续执行,之后必须人工检查资源状态

切换完成后还应执行:

  • 验证目标集群 Pod、Service、PVC 和入口资源。
  • 验证业务读写路径。
  • 切换或确认外部 DNS、网关、负载均衡。
  • 记录 RTO、RPO 和操作结果。
  • 确认是否立即执行 Reprotect。

常见风险

风险说明建议
跳过最终同步导致数据点落后使用最近一次成功同步点切换灾难场景可接受,计划切换不建议跳过
跳过源端缩容导致双写源、目标可能同时运行必须先切断源端入口或由外部流量系统保证单写
目标镜像拉取失败业务镜像、Secret 或 registry 配置缺失切换前在目标集群验证镜像和 imagePullSecret
目标依赖缺失StorageClass、IngressClass、CRD、外部服务未准备在 ResourceSync 阶段提前排查恢复事件
Pod Ready 超时镜像、探针、依赖或容量问题查看目标集群 Pod event 和 DisasterOperation.status.steps

与演练的区别

Failover 会切换主备角色,并可能缩容源端;演练不会交换主备角色,也不应影响生产 standby 资源。演练完成后,实例仍保持原来的保护方向。

因此,生产切换前应先用演练验证恢复策略、资源映射和目标集群依赖,但不能把演练完成等同于已经完成生产 Failover。