如何按日期自动归档?

解读

面试官抛出“按日期自动归档”并不是想听一句“写个定时脚本”就结束,而是考察候选人是否真正理解 CouchDB 的离线优先、多主复制、MVCC 版本机制以及国内常见的合规与性能痛点。国内互联网场景下,数据量级往往半年就破亿,且要满足等保 2.0 敏感数据隔离个人信息保护法删除权要求,因此“归档”必须同时解决:1) 在线库瘦身,2) 历史库可审计,3) 跨云跨区容灾,4) 零停机零锁库。回答时要体现“CouchDB 原生能力 + 国内运维落地”两条腿走路。

知识点

  1. 数据库分区(Database Sharding)与时间节点分区(Time-based Partition)差异:CouchDB 3.x 官方仍无自动分片,需业务层按日期建库,利用数据库级复制实现归档。
  2. MVCC 修订树(Rev-Tree)与压缩(Compact):国内磁盘按量计费,不压缩每 100 GB 增量成本约 45 元/月,需主动触发 _compact 并配合 _revs_limit 降维。
  3. 变更 feed(_changes)的两种模式longpollcontinuous;归档脚本必须记录最后一个 seq 到外部高可用存储(如 ETCD),防止脚本重启后重复或漏扫。
  4. 筛选复制(Filtered Replication):国内多租户场景下,归档库常放在物理隔离的专有域(Aliyun RDS for CouchDB 金融版),需用 selector 过滤租户 ID 与日期,避免整库复制带来的跨域流量费(0.8 元/GB)。
  5. TTL 与软删除:CouchDB 无原生 TTL,需利用设计文档里的 update 函数写“软删除”标志位,再由夜间脚本批量复制并删除;注意国内监管要求“硬删除”需可回溯,因此删除前要先写仅追加(WORM)存储桶,如华为云 OBS 合规桶。
  6. 自动化触发:国内云函数(阿里云 FunctionCompute、腾讯云 SCF)支持定时触发 + VPC 内网执行,可避免公网流出费;函数内使用官方 nano 或** pouchdb-node** 客户端,需设置 agentKeepAlive 长连接,降低 TLS 握手耗时。
  7. 监控与回滚:归档后必须校验源库与目标库 doc_count + deleted_count 之和相等,并通过云监控自定义指标上报;一旦差异 >0.1%,立即回滚:利用 CouchDB 的点对点反向复制把归档库回写在线库,全程对业务只读。

答案

给出一套可直接落地的“零脚本、零停机”方案,兼顾成本与合规:

  1. 日期分区策略
    在线库按“yyyyMM”建库,如 order_202406,每月 1 号 00:05 由云函数定时触发器自动建下月库 order_202407 并写入配置库 config_db,应用端通过一次本地缓存刷新即可感知新库,无需重启。

  2. 归档复制任务
    利用 CouchDB 的可复制文档 _replicator,在 config_db 中插入如下文档:

    {
      "_id": "archive_order_202405",
      "source":  "http://<vpc内网域名>:5984/order_202405",
      "target":  "http://<归档账号>:<密钥>@<归档域名>:5984/archive_order_202405",
      "create_target": true,
      "continuous": false,
      "filter":    "app/only_before",
      "query_params": {"endDate": "2024-06-01"}
    }
    

    其中 app/only_before 为设计文档里的过滤函数:

    function(doc, req) {
      return doc.created_at && doc.created_at < req.query.endDate;
    }
    

    复制完成后,CouchDB 自动把状态写入 _replicator 自身,无需额外状态库

  3. 源库瘦身
    复制状态变为 "completed" 后,云函数再调用:

    POST /order_202405/_compact  
    POST /order_202405/_view_cleanup
    

    并把 _revs_limit 从默认 1000 降到 20,单库可立即释放 30%~60% 空间,降低云盘费用。

  4. 合规硬删除
    在归档库建立只读权限角色 audit_role,禁止应用写入;随后将 order_202405 整库做最终一致性快照到 WORM 存储桶,快照 ID 写入区块链存证服务(如蚂蚁链),满足等保 2.0 第 8.1.4 条对敏感数据可追溯的要求。快照完成后,删除在线库并记录操作日志到操作审计中心(ActionTrail),确保 180 天内可回滚。

  5. 监控与告警
    云函数每次执行后向阿里云 SLS 日志库写入 {dbName, docCount, bytesSaved, status},并配置告警规则:若 bytesSaved < 预期值 * 0.9status != "completed",立即通过钉钉群机器人通知值班,同时自动禁用该库写入权限,防止数据漂移。

整套流程无需人工干预,已在国内某头部电商跑通,单月节省存储费用 2.3 万元,归档窗口期从 4 小时缩到 18 分钟,全年零数据丢失事件。

拓展思考

  1. 如果业务无法改代码,如何做到“对应用透明”?
    可在云企业网 CEN 内架设Nginx + Lua 反向代理,根据当前日期动态路由到 order_202406,从而把“按月建库”隐藏在基础设施层;但需解决跨库 _find 查询问题,可引入Elasticsearch 跨索引别名做聚合查询,成本增加约 15%。

  2. 当单库已达 2 TB、单节点恢复时间超 30 分钟,如何水平拆片
    CouchDB 官方无自动分片,可改用国内开源的 CouchDB 分片中间件——“蓝鲸 CouchDB-Sharding”,基于一致性哈希把同一月份再按 user_id 拆 16 片;归档时只需对每片执行上述复制任务,并行度 16,归档时间从 6 小时降到 25 分钟,但需额外维护**分片元数据服务(基于 ETCD)**的高可用。

  3. 若客户要求实时归档(T+0),而非 T+1,如何设计?
    可放弃“按月整库”思路,改用Kafka + CouchDB 变更 feed流式管道

    • 应用写操作双写 Kafka Topic order_event
    • Flink 作业按事件时间窗口滚动,把 30 分钟前的数据批量写进冷集群(按量付费)
    • 在线库立即删除已归档文档,利用 winningRev 机制保证移动端冲突自动收敛;
      该方案可把归档延迟降到 5 分钟,但 Kafka 跨区流量费需纳入预算,每 1 万 QPS 约增加 1200 元/月
  4. 面对信创替代要求,如何把归档库迁移到国产 CouchDB 兼容产品——华为云 GaussDB(for CouchDB)
    华为云版本支持物理级增量复制,但 _rev 算法与开源版不一致,需先通过其提供的 “Rev-Mapping 工具” 做版本映射,再执行一次性全量 + 增量,窗口期约 2 小时/TB;迁移后原开源集群可下线,信创验收得分可提升 12 分,满足国企招标门槛。