描述 CouchDB 的“多主”与“主从”在写路径上的根本差异。
解读
面试官想确认两点:
- 你是否真正理解 CouchDB 默认的 多主(multi-master) 架构,而不是把“主从”概念生搬硬套;
- 你能否用“写路径”这一工程视角,把 数据落盘、冲突检测、一致性保证 三个关键环节讲清楚。
国内大厂在选型时,往往把 CouchDB 的离线同步能力当成卖点,因此回答必须突出“写操作可在任意节点完成”与“主从只能写主节点”的本质区别,并点出 CouchDB 通过 MVCC + 增量复制 解决冲突的代价与收益。
知识点
- 写路径定义:客户端 → HTTP 接口 → BEAM 虚拟机 → 存储引擎 → 本地 B+ 树 → 后续复制。
- 多主核心:
- 每个节点都是对等主节点,写请求可在任意节点本地完成,无需远程锁。
- 文档首次写入即带 rev 树(_rev 字段),冲突被保留为分支,读时由应用或 conflict handler 解决。
- 主从核心:
- 写请求必须路由到 唯一主节点,从节点只接受读或只读 SQL。
- 主节点通过 binlog/raft log 把变更串行化后同步给从节点,从节点无投票权。
- 根本差异:
- 写可用性:多主做到分区容忍+高可用,主从在主宕机时需选主,期间写不可用。
- 一致性模型:多主最终一致,主从可做到线性一致(若用同步复制)。
- 冲突处理时机:多主在 读时或后台合并;主从在 写时拒绝或重试,用户无感知。
- 国内落地注意:
- 金融场景往往强制 外部共识(如 ZooKeeper 选主)把 CouchDB 退化成“逻辑主从”,以满足监管 RPO=0 要求。
- 移动端离线写后回仓,必须评估 rev 树深度 带来的 磁盘放大 与 复制流量放大。
答案
在 CouchDB 的多主架构下,任意节点都能直接接受写请求:
- 请求到达本地 HTTP 接口后,BEAM 进程立即把文档追加到 B+ 树,生成新 rev 值并返回 201,整个写路径无需远程协调。
- 后续异步复制阶段,各节点通过 _changes 增量 feed 交换文档,若检测到同一 docid 出现不同 rev 分支,则保留冲突分支,由应用在读时通过
conflicts=true或 view 合并函数解决。
而在传统主从架构里,写路径必须经过唯一主节点:
- 客户端若路由到从节点,从节点会返回 重定向错误 或直接拒绝;
- 主节点先写本地日志,再同步或半同步复制到从节点,多数派确认后才向客户端返回成功,因此写操作强依赖主节点存活与网络质量。
根本差异可总结为:多主写路径本地完成、冲突延后解决,主从写路径集中串行、冲突提前避免;前者带来分区容忍与离线优先,后者带来线性一致与简单语义。
拓展思考
- 国内物联网项目常把 CouchDB 部署在边缘盒子,盒子断网数周后再回传数据,此时 rev 树可能深达数百层,导致首次同步 HTTP 包膨胀。解决思路是:
- 定期在边缘运行 compact + revs_limit 裁剪;
- 回传前用 _revs_diff 接口只推送缺失版本,减少 70% 流量。
- 如果业务要求单行事务,可把 CouchDB 的多主退化为“单主写入+双活只读”:通过 HAProxy + 健康检查 保证同一时间只有一个节点接受写,宕机时 30 秒内切主,兼顾监管合规与 CouchDB 原生复制,无需引入外部一致性协议。