描述 CouchDB 的“多主”与“主从”在写路径上的根本差异。

解读

面试官想确认两点:

  1. 你是否真正理解 CouchDB 默认的 多主(multi-master) 架构,而不是把“主从”概念生搬硬套;
  2. 你能否用“写路径”这一工程视角,把 数据落盘、冲突检测、一致性保证 三个关键环节讲清楚。
    国内大厂在选型时,往往把 CouchDB 的离线同步能力当成卖点,因此回答必须突出“写操作可在任意节点完成”与“主从只能写主节点”的本质区别,并点出 CouchDB 通过 MVCC + 增量复制 解决冲突的代价与收益。

知识点

  1. 写路径定义:客户端 → HTTP 接口 → BEAM 虚拟机 → 存储引擎 → 本地 B+ 树 → 后续复制。
  2. 多主核心:
    • 每个节点都是对等主节点,写请求可在任意节点本地完成,无需远程锁。
    • 文档首次写入即带 rev 树(_rev 字段),冲突被保留为分支,读时由应用或 conflict handler 解决。
  3. 主从核心:
    • 写请求必须路由到 唯一主节点,从节点只接受读或只读 SQL。
    • 主节点通过 binlog/raft log 把变更串行化后同步给从节点,从节点无投票权。
  4. 根本差异:
    • 写可用性:多主做到分区容忍+高可用,主从在主宕机时需选主,期间写不可用。
    • 一致性模型:多主最终一致,主从可做到线性一致(若用同步复制)。
    • 冲突处理时机:多主在 读时或后台合并;主从在 写时拒绝或重试,用户无感知。
  5. 国内落地注意:
    • 金融场景往往强制 外部共识(如 ZooKeeper 选主)把 CouchDB 退化成“逻辑主从”,以满足监管 RPO=0 要求。
    • 移动端离线写后回仓,必须评估 rev 树深度 带来的 磁盘放大复制流量放大

答案

在 CouchDB 的多主架构下,任意节点都能直接接受写请求:

  1. 请求到达本地 HTTP 接口后,BEAM 进程立即把文档追加到 B+ 树,生成新 rev 值并返回 201,整个写路径无需远程协调
  2. 后续异步复制阶段,各节点通过 _changes 增量 feed 交换文档,若检测到同一 docid 出现不同 rev 分支,则保留冲突分支,由应用在读时通过 conflicts=trueview 合并函数解决。

而在传统主从架构里,写路径必须经过唯一主节点

  1. 客户端若路由到从节点,从节点会返回 重定向错误 或直接拒绝;
  2. 主节点先写本地日志,再同步或半同步复制到从节点,多数派确认后才向客户端返回成功,因此写操作强依赖主节点存活与网络质量。

根本差异可总结为:多主写路径本地完成、冲突延后解决,主从写路径集中串行、冲突提前避免;前者带来分区容忍与离线优先,后者带来线性一致与简单语义

拓展思考

  1. 国内物联网项目常把 CouchDB 部署在边缘盒子,盒子断网数周后再回传数据,此时 rev 树可能深达数百层,导致首次同步 HTTP 包膨胀。解决思路是:
    • 定期在边缘运行 compact + revs_limit 裁剪
    • 回传前用 _revs_diff 接口只推送缺失版本,减少 70% 流量。
  2. 如果业务要求单行事务,可把 CouchDB 的多主退化为“单主写入+双活只读”:通过 HAProxy + 健康检查 保证同一时间只有一个节点接受写,宕机时 30 秒内切主,兼顾监管合规与 CouchDB 原生复制,无需引入外部一致性协议