Hacking Limbo

Reading / Coding / Hacking

GlusterFS 增量备份

GlusterFS 没有提供现成的增量备份方案,但稍微折腾一下还是有希望实现的,用到了一个没有文档说明的特性:changelog. 官方文档完全没有提到怎样使用,所幸在邮件列表里翻到一个回复,提到了 glusterfind 这个工具,大致的用法是:

# 首次运行时创建 session
glusterfind create SESSION_NAME VOLUME_NAME

# 获取完整的文件列表
glusterfind pre --full SESSION_NAME VOLUME_NAME all-files.txt

# 获取增量列表
glusterfind pre SESSION_NAME VOLUME_NAME files.txt
glusterfind post SESSION_NAME VOLUME_NAME

基于 glusterfind 设计出来的增量备份方案就是,用 glusterfind pre 导出 changelog, 排除掉排除不需要的文件后,生成文件列表,扔给 rsync 执行文件增量同步。

比较棘手的部分:区分 NEW, MODIFY, RENAMEDELETE 操作。NEWMODIFY 都好说,直接复制就完事,DELETE 也不难,正常情况下很少删除,可以攒起来隔一段时间集中删除一次(注意:要考虑删除后重新写入原路径的情况),但是 RENAME 就有点麻烦了。

RENAME 涉及到的情况:

  1. 最简单的情况,mv /dir/file1 /dir/file2,按 NEW + DELETE 处理即可。
  2. 难点 1, mv /dir /newdir,把整个新目录重新同步一遍?由于 RENAME 只有一条记录(被更名的那个目录),如果生成文件列表时排除了目录类型的路径,就会漏掉这个更新。
  3. 难点 2, date >> /dir/file3 && mv /dir /newdir,源路径和备份路径不一致,要么追踪目录的 RENAME 事件,从 /newdir 里复制 file3;要么先执行 RENAME,再复制文件。
  4. 难点 3, 跨目录的移动,比如 mv /dir1/subdir /dir2/abc.

如果不考虑 RENAME 事件,整个备份过程大致如下:

  1. 在 GlusterFS 机器上导出 changelogs - 调用 glusterfind pre 输出 changelogs 到按日期划分的目录里,顺便备份 status 文件(记录了前一次增量的时间戳)。

  2. 同步 changelogs 到备份机器。

  3. 解析 changelogs 事件生成文件列表,并记录最后读取的位置。这一步涉及到的逻辑有:

    • 根据最后一次读取的 changelogs 文件位置,按日期向后遍历所有 changelogs.
    • 校验 states.json 记录的 last_log_md5sum
    • 将所有事件加载进内存,按文件顺序(即时间顺序)遍历。
    • 忽略所有目录类型的路径,并跳过符合 exclude patterns 的路径。
    • 保证在各种情况下,程序退出时都记录下最后处理成功的事件。
    • 检查上一次执行的状态,如果上一次执行出错,必须手动跳过出错的事件才能继续执行。
    • 遇到非预期的事件 (RENAME) 时,抛异常终止程序。
  4. 调用 rsync 完成文件同步。用 rsync 是为了简化 file metadata 的备份,除了文件本身的 owner / group / permission 之外,其上层目录的 metadata 也要备份。

如果有的选,还是别用 GlusterFS 比较好。