灾难恢复
- RFC PR: databendlabs/databend-docs#1546
- Tracking Issue: datafuselabs/databend#17234
概要
使 Databend 能够从涉及元数据或数据丢失的灾难中恢复。
动机
Databend 被设计为高可用和容错的。它的元数据由 Databend MetaSrv 提供服务,该服务由 OpenRaft 提供支持。数据存储在对象存储系统中,如 S3、GCS 等,这些系统保证 99.99% 的可用性和 99.999999999% 的持久性。
然而,对于需要强大的灾难恢复计划的企业用户来说,这还不够。这些用户要么对跨大陆灾难恢复有重大需求,要么必须遵守严格的监管要求。
例如,健康保险流通与责任法案 (HIPAA) 规定医疗保健组织制定并实施应急计划。这种计划确保在发生自然或人为灾害中断运营时,企业可以继续运作,直到恢复正常服务。
本 RFC 提出了一种解决方案,使 Databend 能够从涉及元数据或数据丢失的灾难中恢复。
指导性解释
本 RFC 介绍了通过提供强大的备份和恢复解决方案,使 Databend 能够从灾难(如元数据或数据丢失)中恢复的第一步。我们提出的产品,暂定名为 bendsave
,将允许用户高效地备份和恢复元数据和数据。
该产品的名称尚未确定,我们暂且称之为 bendsave
1. 备份
使用 bendsave backup
命令创建集群数据和元数据的备份。支持增量备份,确保只保存自上次备份以来的更改。这简化了日常备份。
示例:
bendsave backup --from /path/to/query-node-1.toml --to s3://backup/
要点:
- 元数据和数据存储在备份位置。
- 即使在完全失败的情况下,也能实现完整的集群恢复。
2. 列出备份
要查看存储在指定位置的所有备份,请使用 bendsave list
命令。
示例:
bendsave list s3://backup/
3. 恢复
使用 bendsave restore
命令从备份恢复 Databend 集群。默认情况下,这以 dry-run 模式运行,以防止意外恢复。对于自动恢复,请使用 --confirm
标志。
示例:
# Dry-run 模式 (默认)
bendsave restore --from s3://backup/path/to/backup/manifest --to /path/to/query-node-1.toml
# 立即执行恢复
bendsave restore --from s3://backup/path/to/backup/manifest --to /path/to/query-node-1.toml --confirm
4. 清理
使用 bendsave vacuum
命令管理备份保留。这通过删除旧的或不必要的备份来确保备份符合您的保留策略。
示例:
bendsave vacuum s3://backup \
--retention-days 30 \
--min-retention-days 7 \
--max-backups 5 \
--min-backups 2
bendsave
工具将提供一种简单而强大的方式,通过备份和恢复操作来保护 Databend 集群。凭借增量备份、dry-run 恢复模式和基于 vacuum 的保留管理等功能,它为用户在灾难恢复场景中提供了控制和可靠性。
参考级解释
bendsave
将引入一个 BackupManifest
,其中存储以下内容:
- 给定备份的元数据:如备份时间、备份位置、备份类型(完整或增量)等。
- 元数据备份的位置:指向元数据备份的位置。
- 数据备份的位置:包含所有表数据的位置。
struct BackupManifest {
backup_meta: BackupMeta,
metasrv: BackupFile,
storage: Vec<BackupFile>,
...
}
struct BackupMeta {
backup_time: DateTime<Utc>,
...
}
struct BackupFile {
blocks: Vec<Block>,
etag: String,
}
struct BackupBlock {
block_id: String,
block_size: u64,
...
}
BackupManifest
将由 protobuf 编码并与备份元数据和数据一起存储在备份存储中。
BackupManifest
的 protobuf 定义将被版本化,以确保向后和向前兼容性。这将使 Databend Query 能够恢复使用不同版本的 Databend 创建的备份。
备份存储布局
备份存储布局如下:
s3://backup/bendsave.md
s3://backup/manifests/20250114_201500.manifest
s3://backup/manifests/20250115_201500.manifest
s3://backup/manifests/20250116_201500.manifest
s3://backup/data/<block_id_0>
s3://backup/data/<block_id_1>
s3://backup/data/<block_id_....>
s3://backup/data/<block_id_N>
bendsave.md
作为一个快速参考指南,帮助用户理解备份存储并恢复集群。manifests/
目录中的每个 manifest 都包含恢复集群所需的一切。data/
目录存储所有数据块。Bendsave 将源数据分割成固定大小的块(例如,8 MiB),并使用它们的 SHA-256 校验和作为块 ID。
备份过程
- 导出所有 metasrv 数据并将其保存到备份存储。
- 枚举源后端存储服务以创建
BackupManifest
文件。 - 将所有数据文件复制到备份存储。
对于增量备份,Databend 检查现有的 BackupManifest
文件,并将仅修改的数据文件以及新的 BackupManifest
文件传输到备份存储。
例如:
用户第一次执行备份,如:
bendsave backup --from /path/to/query-node-1.toml --to s3://backup/
他们将看到创建以下文件:
s3://backup/bendsave.md
s3://backup/manifests/20250114_201500.manifest
s3://backup/data/<sha256_of_block_0>
s3://backup/data/<sha256_of_block_1>
s3://backup/data/<sha256_of_block_....>
s3://backup/data/<sha256_of_block_N>
用户第二次执行备份时,bendsave 将生成以下文件并省略现有块:
s3://backup/bendsave.md
s3://backup/manifests/20250114_201500.manifest
s3://backup/manifests/20250115_201500.manifest
s3://backup/data/<sha256_of_block_0>
s3://backup/data/<sha256_of_block_1>
s3://backup/data/<sha256_of_block_....>
s3://backup/data/<sha256_of_block_N>
s3://backup/data/<sha256_of_block_....>
s3://backup/data/<sha256_of_block_M>
块 ID 由块内容的 SHA-256 校验和生成。因此,如果之前已经备份过,我们可以重用同一个块。
恢复过程
- 从备份存储读取
BackupManifest
文件。 - 将所有相关数据文件复制到其原始位置。
- 读取备份的 metasrv 数据并导入到新的 metasrv 集群中。
请注意,恢复过程将覆盖整个 MetaSrv 集群。备份目标 MetaSrv 集群中的所有现有元数据将永久丢失。
用户可以使用以下命令从备份恢复:
bendsave restore --from s3://backup/manifests/20250114_201500.manifest --to /path/to/query-node-1.toml
用户还可以通过指定最新的 manifest 文件来增量恢复:
bendsave restore --from s3://backup/manifests/20250115_201500.manifest --to /path/to/query-node-1.toml
缺点
无。
原理和替代方案
无。
先例
Databricks Clone
Databricks 允许用户执行表的 shadow 和 deep cloning。
例如:
使用 clone 进行数据归档
CREATE OR REPLACE TABLE archive_table CLONE my_prod_table;
或者使用 clone 对生产表进行短期实验
-- 执行 shallow clone
CREATE OR REPLACE TABLE my_test SHALLOW CLONE my_prod_table;
UPDATE my_test WHERE user_id is null SET invalid=true;
-- 运行一堆验证。一旦满意:
-- 这应该利用 clone 中的更新信息来尽可能地修剪到 clone 中仅更改的文件
MERGE INTO my_prod_table
USING my_test
ON my_test.user_id <=> my_prod_table.user_id
WHEN MATCHED AND my_test.user_id is null THEN UPDATE *;
DROP TABLE my_test;
未解决的问题
无。
未来可能性
复制
未来,我们可以扩展备份和恢复功能以支持复制。这将允许用户跨不同的 databend 集群复制数据库或表,以实现灾难恢复或数据分发。
Databend 还可以实现热备,以确保高可用性和容错能力。