删除文档为何需要“_deleted:true”标记而非物理擦除?这对同步有何好处?

解读

国内面试官问这一题,核心想验证两点

  1. 你是否真正理解 CouchDB 的“多主复制 + 增量同步”机制;
  2. 能否把“删除也是数据”这一理念,转化为线上可落地的容灾、溯源、合规方案。
    回答时切忌只背概念,要结合国内互联网场景(如移动办公、小程序离线、多活机房)给出“为什么必须保留墓碑”的实战理由。

知识点

  1. MVCC 版本链:每份文档按 sequence 有序追加,物理擦除会打断版本链,导致其他节点的同一文档无法继续追加。
  2. 墓碑(tombstone)机制_deleted:true 本质是一个新版本,携带 _id_rev_deleted 与最小体积,既宣告删除又保留版本号。
  3. 变更源(_changes feed):同步双方按 last_seq 做增量比对;若物理擦除,feed 里将缺失事件,对端无法感知。
  4. 国内合规要求:等保 2.0、个人信息保护法均要求数据操作可审计;墓碑留痕可直接作为“删除日志”供监管抽查。
  5. 冲突解决:多主场景下,若 A 节点删除而 B 节点同时更新,墓碑版本号更高,系统可自动识别“删除优先”或“更新优先”策略,避免静默数据回归
  6. 压缩与回收compaction物理清理墓碑以外的旧版本,但默认保留最新墓碑,兼顾磁盘回收与同步正确性。

答案

CouchDB 采用多主对等复制,所有变更必须通过 _changes 序列化到对端。若直接物理擦除,被删文档将从变更源中消失,对端因缺失事件而持续保留旧版本,造成数据回潮静默不一致
引入 _deleted:true 墓碑后:

  1. 删除动作被当做一个新版本写入本地 MVCC,序列号递增,确保能出现在 _changes
  2. 同步时,对端收到墓碑即可安全丢弃本地相同文档,并更新自己的 last_seq,实现增量对齐
  3. 墓碑体积仅百字节级别,对磁盘与带宽影响极小
  4. 国内监管审计需要“谁何时删了哪条数据”,墓碑天然携带 _id_rev、时间戳,无需额外日志组件即可满足合规;
  5. 在多活机房或移动离线场景,网络分区恢复后,墓碑通过更高版本号自动覆盖冲突更新,保证删除意图最终一致
    因此,_deleted:true 既是 CouchDB 复制协议的正确性基石,也是国内业务可溯源、可容灾、可合规的关键设计。

拓展思考

  1. 墓碑无限增长怎么办?
    可设置 purge 操作永久抹除墓碑,但会重置所有节点的 uuid,相当于重建副本,需选在低峰期全链路停机执行,国内大厂通常一年一次并提前在监管备案。

  2. 如何证明“删除”已同步到所有边缘节点?
    _changes 里过滤 doc._deleted === true 并对比 last_seq,当所有边缘节点的 last_seq ≥ 墓碑所在 seq 且本地读返回 404,即可出具删除闭环报告,满足个人信息保护法第47条确认删除完成”要求。

  3. 与国产数据库混搭时的注意点
    若下游同步到MySQL做报表,需在Kafka 转换层把墓碑转成 DELETE 语句,并保留原 _id 作为业务主键,否则会出现重复插入。国内金融项目常把这一逻辑封装成数据总线中间件,通过等保三级测评时才被认可。