用 Active-Standby 为 MongoDB 长时间迁移消除单点故障

2026-10-01 25 预计阅读时间: 1 分钟
来源: percona.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

MongoDB 集群迁移往往不是一次短暂的导入操作:初始全量克隆可能持续很久,随后还要通过 Change Stream 同步数天的增量数据。在这段窗口内,Percona ClusterSync for MongoDB(PCSM)始终位于迁移链路的关键路径上。引入 Active-Standby 故障转移后,运维重点也随之变化——不再只是让同步进程跑起来,而是确保主实例失效时,备用实例能够继续接管,并且不会丢失进度或造成双活冲突。

为什么迁移任务尤其需要高可用

普通批处理失败后通常可以从头重跑,但大型 MongoDB 迁移的重启成本很高。已经执行数小时甚至数天的初始复制,如果因为同步组件所在节点宕机而重新开始,会显著拉长割接窗口。

增量同步阶段同样敏感。Change Stream 消费者需要保存可恢复的同步位置;接管实例必须知道已经处理到哪里,否则可能出现两类问题:

  • 从过早的位置恢复,重复处理已经同步的变更;
  • 从过晚的位置恢复,遗漏尚未写入目标集群的变更。

Active-Standby 模式的核心不是简单地启动两个进程,而是保证任意时刻只有一个实例负责迁移,备用实例持续等待,并在主实例不可用后取得执行权。要让这种模式真正可靠,还需要持久化检查点、角色选举或租约机制,以及避免网络分区导致双主的 fencing 策略。

高可用链路需要同时保护什么

可以把迁移链路拆成四个需要验证的部分:

  1. 进程可用性:Active 实例崩溃后,Standby 能否被提升。
  2. 状态连续性:新 Active 是否从已提交的同步位置继续,而不是重新克隆或跳过事件。
  3. 连接一致性:两个实例是否具有相同的源集群、目标集群、TLS 证书和认证配置。
  4. 单写约束:发生网络抖动或节点隔离时,旧 Active 是否会失去执行资格。

因此,“两个副本都在 Running”并不等于迁移链路已经高可用。真正有意义的验收指标包括故障检测时间、接管时间、恢复后的复制延迟,以及目标端是否出现遗漏或异常重复写入。

部署时还要避免把两个实例放在同一故障域。例如,两者运行在同一 Kubernetes 节点上,就无法抵御节点级故障;共享同一块仅能单节点挂载的临时存储,也可能让接管过程卡在卷挂载阶段。

可以这样做一次 Kubernetes 故障演练

下面的命令不假设 PCSM 的具体状态接口,适合作为可改造的演练骨架。运行前需要把命名空间、标签选择器和 Active Pod 名称替换成实际值,并使用 PCSM 官方提供的状态、日志或指标确认角色。

#!/usr/bin/env bash
set -euo pipefail

NAMESPACE="pcsm"
SELECTOR="app.kubernetes.io/name=pcsm"

printf 'Current PCSM pods:\n'
kubectl -n "$NAMESPACE" get pods -l "$SELECTOR" -o wide

printf '\nCheck recent logs and identify the Active instance:\n'
kubectl -n "$NAMESPACE" logs -l "$SELECTOR" --tail=50 --prefix

read -r -p 'Active pod name to terminate: ' ACTIVE_POD

printf '\nDeleting Active pod %s to trigger failover...\n' "$ACTIVE_POD"
kubectl -n "$NAMESPACE" delete pod "$ACTIVE_POD" --wait=false

printf '\nWatching pod replacement and role transition:\n'
kubectl -n "$NAMESPACE" get pods -l "$SELECTOR" -w

另开一个终端持续观察日志:

NAMESPACE="pcsm"
SELECTOR="app.kubernetes.io/name=pcsm"

kubectl -n "$NAMESPACE" logs -l "$SELECTOR" \
  --all-containers=true \
  --prefix \
  --follow \
  --max-log-requests=10

演练时应记录四个时间点:旧 Active 最后一次成功提交进度、故障被发现、Standby 被提升、新 Active 恢复复制。这样可以得到实际的恢复时间,而不是只确认 Pod 最终回到了 Running。

如果 PCSM 运行在 Kubernetes 中,还可以增加 PodDisruptionBudget,降低节点维护或滚动操作同时驱逐两个实例的风险。下面只是通用示例,标签必须与实际工作负载一致:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: pcsm
  namespace: pcsm
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: pcsm

应用并检查:

kubectl apply -f pcsm-pdb.yaml
kubectl -n pcsm get poddisruptionbudget pcsm

PDB 只能约束 Kubernetes 的自愿驱逐行为,不能实现角色选举,也无法防止机器宕机。因此它是 Active-Standby 的补充,不是替代品。

上线前别只测试“进程能不能起来”

正式迁移前,建议完成以下检查:

  • Active 与 Standby 分布在不同节点或故障域;
  • 两个实例都能访问源、目标 MongoDB 集群及所需证书和密钥;
  • 同步检查点位于可恢复的位置,并验证备用实例确实能够读取;
  • 强制终止 Active 后,Standby 能在可接受时间内接管;
  • 故障恢复后复制延迟会下降,而不是持续扩大;
  • 网络分区时不会出现两个实例同时执行迁移;
  • 监控能够区分进程存活、角色状态和数据同步状态;
  • 已定义旧 Active 恢复后的行为,避免它直接重新加入并抢占任务。

Active-Standby 降低了长时间迁移因单个同步实例故障而中断的风险,但它并不自动解决所有问题。源或目标 MongoDB 集群故障、错误凭据、容量不足、目标端业务写入冲突,仍然需要单独的保护措施。最稳妥的采用方式,是先在预生产环境完成一次全量克隆和多轮主动故障演练,再把测得的接管时间、数据校验结果和人工回退步骤写入正式割接手册。


相关推荐