PouchDB 的“rev_tree”与 CouchDB 的“rev”格式有何异同?
解读
在国内一线互联网与金融级离线优先项目中,面试官问“rev_tree vs rev”并不是想听“都是版本号”这种表面答案,而是考察候选人是否真正踩过移动端同步冲突、断网续传、多主写入的坑。CouchDB 的 rev 是“扁平”的获胜版本号,而 PouchDB 的 rev_tree 是“带分支家谱”的完整冲突史;能否讲清两者在存储体积、冲突恢复策略、同步协议上的差异,直接决定你能否拿到 30K+ 的分布式存储岗。
知识点
- CouchDB rev 格式:{number}-{hash},例 3-abc123,仅保留当前获胜分支的最新一代,老版本在磁盘 compaction 后物理删除。
- PouchDB rev_tree 格式:本地 IndexedDB 里以树形 JSON 保存所有分支,节点含 {rev: "3-abc", status: "available|deleted", parent: 1, …},即使 10 次离线冲突也全部保留,用于后续三方合并。
- 协议层差异:CouchDB 在 _revs_diff 阶段只传扁平数组 ["3-abc","2-def"];PouchDB 在 _revs_diff 请求里额外带上branch 长度与祖先提示,减少移动端 30% 流量。
- 冲突表现:CouchDB GET 只返回winning rev,冲突历史需手动 ?conflicts=true;PouchDB 在本地查询时默认把整条 rev_tree 暴露给应用,可直接做三路合并。
- Compaction 策略:CouchDB 的压实会物理删除非 winning 分支;PouchDB 为了离线场景永不自动删分支,除非开发者显式调用 compact() 并传入“删到第几代”参数。
- 国内实战:微信小程序里若直接把 CouchDB rev 当缓存键,会出现用户 A 与 B 看到同一 doc 不同内容的“幽灵数据”;用 rev_tree 可在本地先合并再上报,避免客诉。
答案
相同点:两者都基于MVCC思想,用**{number}-{hash}标识一次文档突变,保证写不阻塞读**;在同步协议里都通过 _revs_diff + _bulk_docs 完成增量复制。
不同点:
① 数据结构——CouchDB 只存单条获胜 rev,而 PouchDB 在本地维护完整 rev_tree,包括所有删除分支;
② 冲突可见性——CouchDB 需显式参数才能拿到冲突列表,PouchDB 本地可直接遍历 rev_tree 拿到全部分支;
③ 存储生命周期——CouchDB compaction 会物理清除非 winning 分支,PouchDB 默认永久保留以便离线回滚;
④ 网络传输——CouchDB 的 _revs_diff 只传扁平数组,PouchDB 会附带分支深度与共同祖先,减少弱网重传;
⑤ 应用场景——CouchDB 侧重服务端高性能与节省磁盘,PouchDB 侧重移动端离线冲突自恢复。
一句话总结:CouchDB 的 rev 是“结果”,PouchDB 的 rev_tree 是“过程”。
拓展思考
如果业务要求“移动端断网 7 天后再同步,且不能丢任何用户编辑记录”,你会如何设计 rev_tree 的裁剪策略?
提示:可结合业务时间戳与分支热度给节点打分,只保留最近 3 天且被查看过的分支,其余在本地压缩成墓碑哈希;同步时再向 CouchDB 发送墓碑摘要,既满足合规审计,又控制本地存储 < 50 MB。