设计北京—上海双活架构,如何确保 RPO < 30 s?
解读
面试官真正想验证的是:
- 你是否理解 CouchDB 的多主复制机制在跨城双活中的极限与陷阱;
- 能否用国内网络质量、合规要求、运营商抖动这些真实变量,把“30 秒”翻译成可落地的技术参数;
- 能否在不丢数据的前提下,把复制延迟压到 30 s 以内,同时给出可观测、可灰度、可回滚的完整方案。
一句话:不是让你背手册,而是让你把 CouchDB 的“最终一致性”变成“30 秒内可验证的强一致”。
知识点
- CouchDB 复制模型:_rev 树、checkpoints、batch=10000、filter=selector、since=now 的语义。
- 国内公网质量:北京—上海单向 RTT 25~35 ms,晚高峰丢包 0.5 %~1 %,跨境绕行 60 ms+;必须走BGP 多线+内网专线才能稳控抖动。
- RPO 30 s 的数学意义:复制延迟 ≤ 30 s ⇒ 写入端积压窗口 < 30 s 的数据量;以 10 k doc/s、单 doc 2 kB 为例,积压上限 600 MB。
- CouchDB 4.x 的“可写副本”:节点角色 = voter|replica|shard-holder,双活需voter=odd 且跨城 shard 副本数 ≤ 50 %,避免脑裂。
- 国内合规:日志、个人信息需境内落地,双活不能通过海外中转;因此复制通道必须两端 IP 均在工信部备案。
- 可观测三板斧:Prometheus exporter 暴露 couchdb_replication_changes_pending、couchdb_httpd_requests_bulk_docs、couchdb_db_update_seq,配合 Grafana 告警模板。
答案
一、总体拓扑
- 北京、上海各建 3 节点 CouchDB 集群,同城三副本,跨城再各留 1 副本,共 8 节点;
- 双城之间拉二层专线+BGP 多线冗余,逻辑上视为同一局域网,RTT < 35 ms,抖动 < 5 ms;
- 应用层通过本城读写策略,默认写本地 quorum=2,读本地 quorum=2,跨城副本只用于容灾,不承接日常读负载,避免放大延迟。
二、复制链路设计
- 采用 continuous + selector 过滤 复制,过滤掉本地临时日志、测试库,减少 30 % 流量;
- batch 大小动态调节:白天 5 000、夜间 10 000;心跳间隔 5 s,超时 10 s 即重连,防止 TCP 长连接被运营商 RST;
- 每 10 s 做一次显式 checkpoint,把 since 序列号刷到本地 _local 文档,故障重启后从 10 s 内断点续传;
- 启用 compression=snappy,把 2 kB 文档压缩到 0.6 kB,跨城带宽从 160 Mbps 降到 48 Mbps,晚高峰仍可预留 50 % 余量。
三、延迟预算与容量
- 目标:RPO < 30 s ⇒ 复制延迟 ≤ 30 s;
- 峰值写 10 k doc/s,单 doc 2 kB,30 s 窗口最多 600 MB;
- 专线带宽 200 Mbps,理论 24 s 可清空 600 MB,留 20 % 突发余量,满足要求;
- 每节点 SSD 写缓存 2 GB,即使专线闪断 40 s,也可先写本地 WAL,恢复后按 seq 顺序追赶,不丢数据。
四、脑裂与仲裁
- 采用 CouchDB 4.x 的集群仲裁:总 voter=5(北京 3、上海 2),任意城市掉电仍剩 3 voter,保证选主;
- 跨城复制不依赖自动 failover,由外部哨兵(基于 Consul+Raft)在丢包 > 1 % 或 RTT > 100 ms 持续 20 s 时触发流量调度,把写切到单城,RPO 仍 < 30 s;
- 回切时做 seq 对齐校验:北京 max_seq=123456,上海 max_seq=123450,差值 6 k 条,追赶 8 s < 30 s,满足回切条件。
五、可观测与告警
- Prometheus 每 5 s 采集 couchdb_replication_changes_pending,若 > 15 k 条(对应 15 s 积压)立即告警;
- 同时采集 couchdb_replication_last_update,若超过 25 s 无更新,则短信+电话升级到值班;
- 每周做一次断网演练:用 tc 命令注入 200 ms 延迟、1 % 丢包,验证 30 s 内能否自动追赶并清零 pending。
六、落地步骤
- 先在同城双 AZ 完成 5 节点集群压测,QPS 2 万、延迟 p99 50 ms;
- 再上专线,灰度 5 % 流量跑双活,观察 7 天,确认复制延迟均值 8 s、峰值 22 s;
- 全量切流后,每月做一次真实断电演练,把北京机房整柜拉闸,上海在 28 s 内完成全量追赶,RPO 实测 28 s,符合 < 30 s 要求。
拓展思考
- 如果业务要求 RPO < 5 s,CouchDB 的连续复制模型已逼近极限,需引入 Kafka 顺序队列做双写,或者改用 CouchDB 3.x + pouchdb-server 的“local-first+change-stream”模式,把冲突消解前移到边缘节点。
- 当文档带大附件(> 5 MB)时,attachment 走二进制流,会瞬间打满专线,可考虑把附件拆到阿里云 OSS 双城冗余桶,CouchDB 只存元数据与 etag,复制流量降两个数量级。
- 国内等保 3 级要求审计日志保存 6 个月,双活场景下建议把 _log 库单独建只读副本,通过 logstash->Elasticsearch 集中存储,避免复制风暴影响业务库延迟。