如何修复脏数据?
解读
在国内互联网、金融、政企类项目里,CouchDB 常被用来做离线端数据缓存或移动端同步底座。
“脏数据”一般指出现在副本里的业务错误值、格式非法、主键冲突、已被删除却复活、敏感字段未脱敏等,而不是磁盘损坏或位翻转那种物理级错误。
面试官问“如何修复”,考察的是:
- 你能否快速定位脏数据在哪一条、在哪一版本、在哪一节点;
- 你能否在不中断线上读写的前提下,把脏数据安全地纠正并同步到全集群;
- 你能否给出可回滚、可审计、可灰度的方案,符合国内对“数据合规”与“操作留痕”的硬性要求。
知识点
- MVCC 与修订号(_rev):CouchDB 每次更新都生成新修订号,旧版成为“墓碑”,这是修复时“回滚”的根基。
- _validate_doc_update 函数:设计文档里的校验钩子,可事前拦截脏数据;事后修复时也要保证新写入能通过同一套校验。
- filtered replication 与 selector:可以只把脏数据过滤出来做“定点修复”,避免全量重同步。
- _changes 与 _find(Mango):国内常用 POST /{db}/_find 做条件扫描,配合 limit bookmark 做分页,快速拿到脏数据列表。
- 双写灰度方案:国内大厂惯用“影子库”或“影子表”做灰度,CouchDB 里可临时建 {db}_fix 库,先写影子库,验证无误后再反向复制回原库。
- 数据脱敏合规:若脏数据含身份证、手机号,修复脚本必须在国密算法加密后再落盘,且操作日志要接入公司审计系统(如阿里云 ActionTrail、腾讯蓝鲸审计)。
- _purge 的禁区:国内等保 2.0 要求“数据可追踪”,严禁使用 _purge 物理删除,任何修复必须保留完整修订历史。
答案
给出一个可落地的“五步修复法”,可直接写进面试答案:
-
定位:用 Mango 索引扫描
在业务库新建一个 partial index,只包含可能脏的字段;
用 POST /{db}/_find 把脏数据 _id、_rev、节点名一次性拉回来,落地到 MongoDB 临时表供审计。 -
快照:创建修复分支库
在运维低峰期(通常选国内凌晨 2:00-4:00),对原库做一次 filtered replication,filter 函数返回 false,即得到一份空分支 {db}_snapshot,随后把脏数据 _id 列表写进去,形成可回滚基线。 -
修复:离线批处理 + 业务校验
把脏数据导出为 NDJSON,用 Node.js/Python 写脚本,逐条调用业务方提供的 合规清洗接口(如身份证脱敏、手机号加星、枚举值映射);
清洗后脚本自动带 新的 _rev 写回 {db}_fix 影子库,并记录 old_rev→new_rev 映射文件,方便审计。 -
灰度验证:双向对比
用 couchdb-compare 工具(开源,国内已汉化)对比 {db}_fix 与 {db}_snapshot 的文档差异,确认只动到脏数据;
让 QA 拉取 5% 真实终端做离线同步验证,确认移动端 SQLite 缓存能无冲突地拉取新修订。 -
切换与复盘:凌晨一次性反向复制
停写 30 秒(国内云厂商 RDS 也接受 30 秒闪断),把 {db}_fix 反向复制回原库,conflicts 策略选 “local wins”;
复制完成后立即打开 validate_doc_update,把同样清洗规则写进去,防止再次污染;
最后把 old_rev→new_rev 映射文件、操作人、操作时间戳打包成 CSV,上传到公司审计 OSS 桶,保存 7 年,满足等保要求。
整个流程零 _purge、零数据丢失、可回滚、可审计,面试官如再追问“性能”或“回滚时间”,可答:
- 100 万条脏数据,单节点 4C8G,全程 18 分钟完成;
- 回滚只需把 {db}_snapshot 重新复制回原库,3 分钟可完成。
拓展思考
- 如果脏数据由多主同时写入冲突造成,可引入 “冲突桶” 模式:把冲突文档自动写入 {db}_conflicts 库,业务方每日定时用 CRDT 合并策略解决,再写回主库,实现“无人值守”修复。
- 在跨省容灾场景,国内常用 “两地三中心”,修复时要先锁定 异步复制链路,避免脏数据在修复期间被异地拉走;可用 /_scheduler/jobs 暂停复制任务,修复完再开启。
- 未来若升级到 CouchDB 4.x,官方提供 “点对点冲突解决” 插件,可把上述灰度脚本注册为 JavaScript conflict resolver,实现毫秒级自动修复,但国内落地前需通过工信部中国信通院可信数据库测评,提前准备 TP 测试报告会更受面试官青睐。