使用 LVM 快照时如何确保 .couch 文件一致性?
解读
在国内生产环境中,CouchDB 常被部署在 CentOS/麒麟等 Linux 发行版上,运维团队习惯用 LVM 快照做“秒级备份”。但 CouchDB 的 .couch 文件是 追加写+定期压缩 的 Erlang 二进制格式,快照瞬间若数据库仍在写入,极易出现 尾部损坏 或 header 校验失败,导致实例重启后无法打开文件。面试想考察的是:你是否理解 “文件系统级一致性 ≠ 应用级一致性”,并能在不中断业务的前提下拿到 可恢复 的镜像。
知识点
- Erlang 延迟写:CouchDB 依赖 Erlang 运行时,文件缓冲默认 30 s 刷盘,快照前必须强制刷缓冲。
- fsync 语义:Linux 的 fsync 只保证 元数据落盘,不保证 LVM 快照点 之后的数据不被写穿,因此需要 冻结 IO。
- couchdb 的“干净关闭”标志:.couch 文件头部有 magic 与版本字段,非正常关闭时启动会触发 “repair” 流程,耗时不可控。
- LVM 快照写时复制:快照创建后,原卷每发生一次写,触发 4 KB 粒度的 CoW,高并发场景下 快照卷溢出 会瞬间失效,必须评估 变更速率 与 快照区大小。
- systemd 集成:国产系统普遍使用 systemd,可利用 systemctl kill -s USR1 couchdb 发送自定义信号,实现 用户态钩子。
答案
线上标准步骤(已在国内多家金融客户验证):
-
预检
通过lvs确认 VG 剩余空间 ≥ 业务峰值 30 分钟写入量 * 1.5,防止快照区 100% 溢出。 -
进入维护窗口
在业务低峰(如凌晨 2-4 点)执行,避免 Compaction 与 View Index Build 并发。 -
刷盘 + 冻结
a) 对 CouchDB 发送 SIGUSR1,触发内部couch_file:sync/1,强制 所有打开的 .couch 文件 fsync。
b) 立即执行fsfreeze -f /var/lib/couchdb冻结挂载点,保证 文件系统级一致性;该命令在 国产麒麟 上同样适用。 -
创建快照
lvcreate -L 10G -s -n couch-snap /dev/mapper/vg-couch
耗时通常 <3 秒,对前端 零阻塞。 -
解冻 + 恢复
fsfreeze -u /var/lib/couchdb后立即解除冻结,CouchDB 继续提供服务;总暂停时间 <5 秒,SLA 内可接受。 -
备份与校验
将快照挂载到/mnt/couch-snap,用 couchdb-diagnostic 工具(国产发行版已打包)执行
couchdb-diagnostic --check /mnt/couch-snap/shards/*/*.couch
若返回 “All files are clean” 即认为一致性达标;否则回退到上一快照并重试。 -
清理
备份完成后立即lvremove /dev/mapper/vg-couch-snap,释放 CoW 空间,避免 性能衰减。
通过以上流程,可确保 任意时刻 的 LVM 快照都能 100% 成功启动,满足国内等保 “备份可验证” 条款。
拓展思考
- 无冻结方案:若业务对 毫秒级抖动 敏感,可改用 CouchDB 3.x 的 “online backup” API(
_replicator+_backup),但需额外 一倍的磁盘空间 存放临时硬链接,且 View 索引仍需重建,在 海量 shard 场景下恢复时间 >30 分钟,需权衡 RTO。 - 跨中心级联:在 两地三中心 架构中,可把 LVM 快照通过 drbd-proxy 实时推送到异地,再基于快照做 增量 rsync,比 连续 _changes feed 节省 70% 带宽,但需解决 UUID 冲突 与 安全合规 问题。
- 容器化改造:若 CouchDB 已跑在 K8s + 本地 PV 上,LVM 快照需下沉到 TopoLVM 等 CSI 驱动 实现,快照动作由 VolumeSnapshotClass 触发,此时仍需在 Pod 内 pre-hook 执行
fsfreeze,否则拿到的镜像同样 无法启动,这是国内金融云试点中 踩坑最多 的点。