一、引言:为什么 ClickHouse 备份如此重要
ClickHouse 作为一款面向在线分析处理场景的列式数据库,以其极高的查询性能、优异的压缩率和灵活的分布式架构,被广泛应用于实时数仓、用户行为分析、广告投放统计、日志分析和时序数据仓库等领域。随着业务规模的扩大,ClickHouse 集群中存储的数据量动辄达到数十 TB 甚至 PB 级,数据已经成为企业最核心的资产之一。然而,很多团队在使用 ClickHouse 的初期阶段,把主要精力都放在建表优化、查询调优和集群扩容上,却容易忽视一个至关重要的问题——数据备份与恢复。
数据丢失的场景远比想象中常见:磁盘损坏、误执行 DELETE 或 DROP 语句、升级失败导致元数据损坏、机房断电、人为操作失误、勒索病毒攻击,甚至云厂商的底层故障,都可能导致数据不可恢复。对于分析型数据库来说,虽然部分数据可以从上游业务系统重新回灌,但回灌成本往往极高,而且对于已经做过聚合、去重、物化视图计算的结果数据,往往根本无法通过重放日志恢复。因此,建立一套可靠的备份与恢复体系,是 ClickHouse 生产环境落地的基本要求。
本文将从 ClickHouse 的存储架构讲起,深入介绍冷备份、FREEZE 命令、文件系统快照、clickhouse-backup 工具、原生 BACKUP/RESTORE 语句等多种备份方案,并结合实战脚本和场景演练,帮助读者建立一套完整的备份恢复能力。无论你是刚开始接触 ClickHouse 的初学者,还是需要为现有集群补齐容灾体系的老手,都能从本文中找到可以直接落地的操作方案。
二、ClickHouse 存储架构基础
要理解备份与恢复,必须先弄清楚 ClickHouse 的数据到底存在哪里、以什么形式存储、修改数据时会发生什么。ClickHouse 的数据存储与传统的行式数据库有很大的不同,其底层基于 MergeTree 表引擎家族,采用 LSM 风格的分区、分片与后台合并机制。只有理解了这些机制,才能知道在备份时应该关注哪些文件、如何保证数据一致性、以及为什么某些场景下简单复制文件会带来风险。
2.1 数据目录结构
ClickHouse 默认的数据目录位于/var/lib/clickhouse/,可以通过配置文件config.xml中的path参数修改。一个典型的数据目录结构如下:
/var/lib/clickhouse/ ├── metadata/ # 元数据目录 │ ├── default/ # 数据库目录 │ │ └── events.sql # 表定义文件 │ ├── default.sql # 数据库定义文件 │ └── system/ # 系统库元数据 ├── data/ # 数据文件目录 │ ├── default/ # 数据库目录 │ │ └── events/ # 表数据目录 │ │ ├── 202501_1_1_0/ # 分区目录 │ │ ├── detached/ # 分离的分区 │ │ └── format_version.txt │ └── system/ # 系统库数据 ├── store/ # 磁盘存储映射 ├── shadow/ # FREEZE 命令生成的影子副本 ├── tmp/ # 临时文件 ├── flags/ # 标志文件 ├── format_schemas/ # 格式 Schema ├── access/ # 用户和权限相关文件 └── user_files/ # 用户文件其中metadata目录保存了所有数据库和表的 DDL 定义,每个库对应一个目录,每个表对应一个.sql文件。例如default/events.sql的内容通常是一行完整的ATTACH TABLE或CREATE TABLE语句,包含表引擎、字段定义、排序键、分区键等完整信息。如果这个文件丢失或损坏,即使数据文件还在,ClickHouse 也无法识别这张表。
data目录保存的是各表真正的列数据文件,按数据库和表名组织。对于 MergeTree 表,表数据目录下会按分区键的取值生成分区目录,例如202501_1_1_0表示 2025 年 1 月分区、最小块编号 1、最大块编号 1、层级 0。每个分区目录内部存放.bin数据文件、.mrk标记文件和count.txt行数信息等。
2.2 MergeTree 存储机制
MergeTree 表引擎是 ClickHouse 最核心的存储引擎,绝大多数业务表都基于它或其变体(ReplicatedMergeTree、AggregatingMergeTree、ReplacingMergeTree 等)。它的写入机制是:数据先以 Part(数据片)的形式写入磁盘,后台会周期性地将多个小 Part 合并成大 Part。这种机制带来的一个直接后果是:数据目录中的文件会不断变化,Part 会被创建、合并和删除。
具体来说,每次 INSERT 操作都会生成一个新的 Part 目录,命名格式为分区_最小块号_最大块号_层级。当后台合并线程将多个 Part 合并后,会生成一个新 Part,并把旧 Part 标记为过期,稍后物理删除。这意味着如果我们直接复制数据目录,必须保证在复制过程中没有正在进行的写入和合并操作,否则复制出来的文件集合可能处于不一致状态,恢复后会出现数据缺失或重复的情况。
2.3 ZooKeeper 元数据
对于使用 ReplicatedMergeTree 表引擎的复制表,ClickHouse 依赖 ZooKeeper 来协调多个副本之间的数据同步。ZooKeeper 中保存了每个复制表的副本列表、Part 清单、队列信息、块编号分配等元数据。备份复制表时,仅仅备份 ClickHouse 数据目录是不够的,还需要考虑 ZooKeeper 元数据的备份,否则恢复后副本之间的状态可能不一致,导致无法正常同步。
一般来说,ReplicatedMergeTree 表的数据文件备份后恢复时,可以先恢复到某一个副本节点,然后让该节点作为数据源,通过 ZooKeeper 向其他副本同步。但如果 ZooKeeper 中该表的元数据也发生了损坏或丢失,那么只备份数据文件就无法直接恢复复制关系。因此完整的企业级备份方案必须同时兼顾 ClickHouse 数据文件和 ZooKeeper 元数据。
三、备份的核心概念与选型依据
在动手写备份脚本之前,我们需要先明确几个关键概念和选型依据。备份不是简单的「把文件复制一份」,而是一个涉及一致性、恢复时间目标、恢复点目标、存储成本和运维复杂度的系统工程。不同的业务场景对备份的要求差异很大,盲目追求最复杂的方案反而会带来不必要的成本。
3.1 冷备份与热备份
冷备份是指在数据库停止服务或表处于冻结状态时进行的备份。由于此时不会有新的写入和合并操作,直接复制数据文件即可获得一致的数据快照。冷备份的优点是实现简单、成本低、一致性有保证;缺点是停机或冻结期间无法提供服务,对于 7x24 小时运行的业务来说不可接受。
热备份是指数据库在正常运行状态下进行的备份。热备份需要借助文件系统快照、FREEZE 命令或专门的备份工具来保证一致性。热备份的优点是业务不中断,缺点是实现相对复杂,需要处理并发写入带来的文件变化问题。
3.2 RPO 与 RTO
RPO(Recovery Point Objective,恢复点目标)是指灾难发生后,能够容忍丢失多少时间的数据。例如 RPO 为 1 小时,意味着最多允许丢失最近 1 小时的数据。RPO 决定了备份的频率:全量备份加增量备份的时间间隔越短,RPO 越小,但备份开销越大。
RTO(Recovery Time Objective,恢复时间目标)是指灾难发生后,从开始恢复到业务可用的目标时间。例如 RTO 为 2 小时,意味着需要在 2 小时内完成数据恢复。RTO 决定了备份方案和恢复流程的复杂度:使用裸文件复制恢复比使用压缩备份包恢复更快,本地备份比远程备份恢复更快。
在设计备份方案时,需要与业务方明确 RPO 和 RTO 指标,然后据此选择备份频率、备份介质和恢复流程。例如对于核心交易分析数据,可能需要 RPO 接近 0、RTO 在小时级;而对于可以重新计算的历史日志数据,RPO 可以放宽到天级。
3.3 备份粒度
ClickHouse 备份的粒度可以分为四种:
- 整库备份:备份所有数据库、所有表及元数据,恢复时整体还原。适合一次性搭建完整容灾环境。
- 数据库级备份:备份某个数据库的全部表,恢复时还原整个库。
- 表级备份:只备份指定的表,适合数据量巨大但只有部分核心表需要高频备份的场景。
- 分区级备份:备份表的某个分区的数据,适合按月分区、历史分区不再变化的场景,可以只对新分区做增量动作。
不同粒度的备份成本差异很大。在实践中,通常采用「全量备份 + 增量备份」的组合策略:定期做全量备份,期间对变化的分区做增量备份,以平衡备份时间和恢复时间。
四、冷备份实战:停止服务复制数据目录
冷备份是所有备份方案中最基础、最直观的一种,也是理解 ClickHouse 备份原理的起点。虽然它在生产环境的适用场景有限,但对于测试环境、开发环境,以及在窗口期允许短暂停机的业务,它仍然是一个简单有效的方案。
4.1 完整冷备份流程
完整冷备份的基本思路是:先停止 ClickHouse 服务,保证数据目录处于静止状态,然后将数据目录和配置目录整体打包复制到备份位置,最后重新启动服务。具体步骤如下:
# 1. 停止 ClickHouse 服务 sudo systemctl stop clickhouse-server 2. 确认服务已停止,没有残留进程 ps -ef | grep clickhouse | grep -v grep 3. 创建备份目录 BACKUP_DIR=/data/backup/clickhouse_full_$(date +%Y%m%d_%H%M%S) mkdir -p "$BACKUP_DIR" 4. 复制数据目录和配置目录 cp -a /var/lib/clickhouse "$BACKUP_DIR/data" cp -a /etc/clickhouse-server "$BACKUP_DIR/config" 5. 重新启动 ClickHouse 服务 sudo systemctl start clickhouse-server 6. 验证备份完整性 ls -lh "$BACKUP_DIR/data" du -sh "$BACKUP_DIR/data"在上面的脚本中,cp -a参数表示归档方式复制,会保留文件的权限、所有者和时间戳等信息,这对于 ClickHouse 的数据文件非常重要,因为某些文件的所有权和权限在恢复后必须与原来一致,否则服务可能无法正常读取。
4.2 使用 tar 打包压缩
如果数据量较大,直接cp会占用大量磁盘空间。更推荐的做法是边压缩边打包,使用tar命令:
sudo systemctl stop clickhouse-server BACKUP_FILE=/data/backup/clickhouse_full_$(date +%Y%m%d_%H%M%S).tar.gz sudo tar -czf "$BACKUP_FILE" -C /var/lib clickhouse -C /etc clickhouse-server sudo systemctl start clickhouse-server需要注意的是,ClickHouse 的数据压缩率通常很高(列式存储本身已经做了压缩),所以再经过gzip压缩后体积并不会显著减小,但tar打包可以避免大量小文件传输时的开销。如果备份介质是对象存储,打包成单个文件也更便于上传和管理。对于压缩比敏感的场景,可以尝试使用zstd或lz4压缩,兼顾速度和体积。
4.3 冷备份的恢复
冷备份的恢复同样简单直接:停止服务,清空或移动当前数据目录,将备份文件还原到原位置,然后启动服务。需要注意的是,恢复前要备份当前可能还存在的新数据,避免覆盖后无法回退。
# 假设备份文件为 /data/backup/clickhouse_full_20250120_030000.tar.gz 1. 停止服务 sudo systemctl stop clickhouse-server 2. 将当前数据目录移走,便于回退 sudo mv /var/lib/clickhouse /var/lib/clickhouse_bak_$(date +%Y%m%d_%H%M%S) 3. 解压备份文件 sudo mkdir -p /var/lib/clickhouse sudo tar -xzf /data/backup/clickhouse_full_20250120_030000.tar.gz -C /var/lib 4. 检查文件所有者 sudo chown -R clickhouse:clickhouse /var/lib/clickhouse 5. 启动服务 sudo systemctl start clickhouse-server 6. 验证数据 clickhouse-client --query "SELECT count() FROM default.events"冷备份的优点是操作简单、可靠性高,但由于需要停机,在大多数在线业务中无法直接使用。不过它的思路——「保证数据目录在备份时刻处于一致静止状态」——是所有其他备份方案的基础。理解了这一点,就理解了为什么 FREEZE 命令和 clickhouse-backup 工具要设计特定的机制来处理并发写入。
五、FREEZE 命令与影子副本备份
如果业务不能接受长时间停机,但又不想引入额外工具,那么 ClickHouse 提供的FREEZE命令是一个很好的折中方案。它可以在不停止服务的情况下,创建一个数据目录的一致性快照,然后我们就可以从容地复制这个快照,而不用担心并发写入导致的文件不一致。
5.1 FREEZE 命令的工作原理
FREEZE命令的核心机制是「硬链接影子副本」。当对表执行FREEZE后,ClickHouse 会在数据目录下的shadow/N/目录中创建该表所有现有数据文件的硬链接。硬链接的特点是:多个文件名指向同一个 inode,不额外占用实际磁盘空间,但修改原始文件不会影响硬链接指向的文件内容。由于 MergeTree 的合并操作总是生成新的 Part 文件后再删除旧文件,而不是原地修改,所以通过硬链接建立的影子副本始终能保持稳定不变,即使 FREEZE 之后表继续写入新数据、合并旧 Part,影子副本中的内容也不会被破坏。
这个机制的巧妙之处在于:它利用 Linux 文件系统的硬链接特性,以几乎零成本的方式获得了一个一致的数据快照,从而避免了热备份中的数据不一致问题。FREEZE 就是通过这种方式实现了「先冻结、后复制」的热备份能力。
5.2 FREEZE 命令的使用
FREEZE 命令支持库级、表级和分区级三种粒度。使用方法如下:
-- 冻结整个数据库的所有表 ALTER DATABASE default FREEZE; -- 冻结单张表 ALTER TABLE default.events FREEZE; -- 冻结表的指定分区 ALTER TABLE default.events FREEZE PARTITION '202501'; -- 为同一张表多次冻结,使用 WITH NAME 指定快照名称 ALTER TABLE default.events FREEZE WITH NAME 'backup_20250120';执行 FREEZE 后,可以在文件系统中看到影子副本目录:
ls -l /var/lib/clickhouse/shadow/ # 输出类似: # drwxr-x--- 2 clickhouse clickhouse 4096 Jan 20 03:00 1/ # drwxr-x--- 2 clickhouse clickhouse 4096 Jan 20 03:00 backup_20250120/影子目录中的文件结构与原表数据目录一致,但都是硬链接。backup_20250120这个目录下会包含data/default/events/这样的路径,其中是当时冻结的所有 Part 的硬链接。
5.3 基于 FREEZE 的完整备份流程
基于 FREEZE 的备份思路是:先执行 FREEZE 生成一致性快照,然后复制 shadow 目录中的内容到备份介质(本地目录、NFS 或对象存储)。由于影子副本是静态的,复制过程可以慢慢进行,不会影响数据库的持续写入。
#!/bin/bash # clickhouse_freeze_backup.sh # 基于 FREEZE 命令的 ClickHouse 热备份脚本 BACKUP_BASE=/data/backup/clickhouse STAMP=$(date +%Y%m%d_%H%M%S) SNAPSHOT_NAME="backup_$STAMP" CH_HOST="127.0.0.1" CH_PORT="9000" 1. 对需要备份的表执行 FREEZE clickhouse-client --host "$CH_HOST" --port "$CH_PORT" --query "ALTER TABLE default.events FREEZE WITH NAME '$SNAPSHOT_NAME'" clickhouse-client --host "$CH_HOST" --port "$CH_PORT" --query "ALTER TABLE default.orders FREEZE WITH NAME '$SNAPSHOT_NAME'" 2. 复制影子副本到备份目录 SHADOW_DIR="/var/lib/clickhouse/shadow/$SNAPSHOT_NAME" if [ -d "$SHADOW_DIR" ]; then mkdir -p "$BACKUP_BASE/freeze" cp -a "$SHADOW_DIR" "$BACKUP_BASE/freeze/$STAMP" echo "备份完成: $BACKUP_BASE/freeze/$STAMP" else echo "错误:未找到影子副本目录 $SHADOW_DIR" exit 1 fi 3. 准备元数据备份 clickhouse-client --host "$CH_HOST" --port "$CH_PORT" --query "SHOW CREATE TABLE default.events" > "$BACKUP_BASE/freeze/$STAMP/events_ddl.sql" 4. 清理旧的影子副本(FREEZE 本身需要在后续手动清理) rm -rf "$SHADOW_DIR" echo "FREEZE 备份流程执行完毕"备份完成后,$BACKUP_BASE/freeze/$STAMP目录中就包含了一致性的表数据硬链接副本。这些文件可以在任何时间恢复,即使原始数据已经被修改或删除。
5.4 清理 shadow 目录
FREEZE 命令会持续消耗磁盘空间吗?答案是不会因为硬链接本身而消耗,但随着表继续合并和写入,被冻结的旧 Part 在被删除时,由于影子目录中还持有硬链接,这些文件的实际磁盘空间不会被释放。因此,如果长时间不清理 shadow 目录,磁盘使用量会持续增长。最佳实践是:备份完成后立即删除对应的 shadow 目录,或者使用SYSTEM UNFREEZE命令清理。
-- 清理指定名称的快照 SYSTEM UNFREEZE WITH NAME 'backup_20250120';# 直接删除文件系统中的影子副本 rm -rf /var/lib/clickhouse/shadow/backup_20250120值得注意的是,在较新版本的 ClickHouse 中,FREEZE 的 shadow 目录管理得到了一定优化,但手动清理仍然是一个好习惯。建议在备份脚本的末尾加上清理逻辑,避免磁盘被无形的硬链接占满。
六、文件系统快照备份
文件系统快照是另一种常见的热备份手段,它在文件系统或存储层面对整个数据卷做瞬时快照,从而实现一致性备份。与 FREEZE 命令相比,文件系统快照的粒度更粗(通常是整个卷),但实现更底层,可以覆盖所有数据库和表,也不需要为每张表单独执行命令。对于运行在云环境或使用 LVM/ZFS 这类支持快照的文件系统的场景,这是一种非常实用的方案。
6.1 LVM 快照备份
LVM(Logical Volume Manager,逻辑卷管理器)是 Linux 下常用的磁盘管理工具,支持对逻辑卷创建快照。LVM 快照使用写时复制(COW)机制,创建瞬间即可完成,随后原始卷的写入会触发数据块的保留。借助 LVM 快照,可以在不停止 ClickHouse 的情况下获得整个数据卷的一致性视图。
但需要注意的是,LVM 快照本身捕获的是文件系统层面的块状态。如果 ClickHouse 在快照时刻正在进行写入,那么快照中可能包含部分写入的文件。为了保证一致性,建议在创建快照前先执行SYSTEM FLUSH LOGS或短暂冻结写入,或者与 FREEZE 结合使用。对于大多数单节点 ClickHouse 场景,直接在低峰期做 LVM 快照通常也能满足需求。
# 1. 创建 LVM 快照(假设卷组为 vg0,逻辑卷为 lv_clickhouse) sudo lvcreate -L 50G -s -n clickhouse_snap_20250120 /dev/vg0/lv_clickhouse 2. 挂载快照卷 sudo mkdir -p /mnt/clickhouse_snap sudo mount -o ro /dev/vg0/clickhouse_snap_20250120 /mnt/clickhouse_snap 3. 从挂载的快照中复制数据(可以边压缩边复制) sudo tar -czf /data/backup/clickhouse_snap_20250120.tar.gz -C /mnt/clickhouse_snap . 4. 卸载并删除快照卷,释放写时复制的空间 sudo umount /mnt/clickhouse_snap sudo lvremove -f /dev/vg0/clickhouse_snap_20250120LVM 快照的优势是速度快、对整个卷生效;劣势是快照本身有容量限制(创建时指定的 50G),如果备份时间过长、期间写入量很大,快照空间可能被耗尽导致快照失效。因此创建快照后应尽快完成备份并及时删除快照。
6.2 云盘快照备份
如果 ClickHouse 运行在云服务器上,可以直接使用云厂商提供的云盘快照功能。例如阿里云 ESSD 云盘快照、腾讯云 CBS 快照、AWS EBS 快照等。云盘快照在存储层面对整个数据盘做备份,不占用服务器本身的 I/O 资源,而且通常由云厂商保证底层一致性。
使用云盘快照备份 ClickHouse 的基本流程是:在低峰期创建数据盘快照,快照完成后即可继续服务。恢复时基于快照创建新的云盘,挂载到新的服务器或替换旧盘。这种方案的最大优点是运维简单、可靠性高,甚至可以配置自动快照策略(例如每天凌晨自动快照、保留 7 天)。缺点是快照粒度是整个云盘,无法满足表级粒度恢复的要求,而且跨云厂商的兼容性有限。
以下是一个使用阿里云 CLI 创建云盘快照的示例:
# 获取数据盘 ID(假设 ClickHouse 数据单独挂载在 /dev/vdb) DISK_ID=$(lsblk -o NAME,SERIAL -n | grep vdb | awk '{print $2}') 创建快照 aliyun ecs CreateSnapshot --DiskId "$DISK_ID" --SnapshotName "clickhouse_backup_$(date +%Y%m%d)" 查看快照状态 aliyun ecs DescribeSnapshots --DiskId "$DISK_ID" --SnapshotName "clickhouse_backup_*"在实际生产环境中,云盘快照常常作为兜底方案,与其他更精细的备份工具配合使用。例如每天用 clickhouse-backup 做逻辑全量+增量备份上传到对象存储,同时每周做一次云盘快照,这样既能满足快速恢复,又能覆盖底层故障。
6.3 ZFS 与 Btrfs 快照
如果底层文件系统使用了 ZFS 或 Btrfs,它们天生支持高效的快照。ZFS 快照同样基于写时复制,创建和删除都很快。以下是一个 ZFS 快照备份 ClickHouse 的示例:
# 假设 ClickHouse 数据位于 zpool/clickhouse 数据集 zfs snapshot zpool/clickhouse@backup_20250120 查看快照 zfs list -t snapshot 基于快照导出备份(可以发送到远程) zfs send zpool/clickhouse@backup_20250120 | gzip > /data/backup/clickhouse_zfs_20250120.zfs.gz 删除快照 zfs destroy zpool/clickhouse@backup_20250120ZFS 快照方案在自建机房和 NAS 环境中非常流行,它的发送/接收机制还天然支持增量备份和远程复制,适合构建高可用和异地容灾体系。
七、clickhouse-backup 工具详解
clickhouse-backup是 Altinity 公司开源的 ClickHouse 备份恢复工具,也是目前社区中使用最广泛的第三方备份方案。它支持全量备份、增量备份、备份压缩、上传到 S3/GCS/Azure 等对象存储、表级备份和恢复,并且可以集成到 Kubernetes 和多种自动化运维平台中。相比原生 FREEZE 命令,它封装了一套完整的工作流,大大降低了备份运维的复杂度。
7.1 工作原理
clickhouse-backup 的核心思路与 FREEZE 类似,但做了更完整的封装。备份时,它首先对目标表执行ALTER TABLE ... FREEZE命令,在 shadow 目录中建立一致性的硬链接快照;然后将 shadow 目录中的数据文件和元数据打包成归档文件,存储到配置的本地目录或远程对象存储中;最后清理 shadow 目录。由于 FREEZE 保证了数据一致性,整个备份过程可以在数据库持续写入的情况下安全进行。
对于增量备份,clickhouse-backup 会记录上次备份的表分区状态,只备份新增或有变化的分区数据,从而大幅减少备份体积和时间。恢复时则可以直接从远程存储拉取备份包并解压还原。
7.2 安装
clickhouse-backup 提供了预编译的二进制文件,支持 Linux 和 macOS。安装步骤如下:
# 下载最新版本(以 v2.5.x 为例,请根据实际需要选择版本) VERSION=2.5.4 wget "https://github.com/Altinity/clickhouse-backup/releases/download/v${VERSION}/clickhouse-backup-linux-amd64.tar.gz" 解压 tar -xzf clickhouse-backup-linux-amd64.tar.gz 安装到系统 PATH sudo mv clickhouse-backup /usr/local/bin/ 验证版本 clickhouse-backup version也可以使用 Docker 方式运行,便于在 Kubernetes 环境中使用:
docker run --rm -it --network host \ -v /var/lib/clickhouse:/var/lib/clickhouse \ -v /etc/clickhouse-server:/etc/clickhouse-server \ -v /data/backup:/backup \ altinity/clickhouse-backup:2.5.4 --config=/etc/clickhouse-backup/config.yml \ create backup_name7.3 配置文件
clickhouse-backup 的默认配置文件位于/etc/clickhouse-backup/config.yml,也可以在运行时通过--config参数指定。一个完整的配置示例:
general: remote_storage: s3 # 远程存储类型:none、s3、gcs、ftp、sftp、azblob 等 max_file_size: 1073741824 # 单个备份文件的最大大小(1GB) disable_progress_bar: false backups_to_keep_local: 7 # 本地保留的备份数量 backups_to_keep_remote: 30 # 远程保留的备份数量 log_level: info allow_empty_backups: false clickhouse: username: default # ClickHouse 用户 password: "" # 密码 host: 127.0.0.1 # ClickHouse 地址 port: 9000 # 原生协议端口 data_path: "/var/lib/clickhouse" # ClickHouse 数据目录 skip_tables: # 跳过系统表 - system.* - INFORMATION_SCHEMA.* timeout: 5m s3: access_key: "your_access_key" secret_key: "your_secret_key" bucket: "clickhouse-backups" endpoint: "" # 自定义 S3 端点(如 MinIO) region: "us-east-1" path: "clickhouse/prod" # 存储路径前缀 compression_level: 1 # 压缩级别 force_path_style: false storage_class: STANDARD如果使用本地磁盘作为备份存储(remote_storage: none),备份文件会保存在/var/lib/clickhouse-backup/目录下。对于生产环境,强烈建议配置对象存储作为远程备份位置,实现异地容灾。
7.4 全量备份
配置完成后,执行全量备份只需要一条命令:
# 创建本地全量备份 clickhouse-backup create my_first_backup 创建备份并立即上传到远程存储 clickhouse-backup create_remote my_backup_name 查看所有备份 clickhouse-backup list 输出示例: Name Created Size Status my_first_backup 2025-01-20 03:00:00 12.5GB local my_backup_name 2025-01-20 04:00:00 12.5GB remote备份完成后,可以使用clickhouse-backup list local和clickhouse-backup list remote分别查看本地和远程备份。
7.5 增量备份
增量备份是 clickhouse-backup 的重要特性。它通过比较分区状态,只备份自上次备份以来新增或变化的分区。由于 ClickHouse 常用按时间分区的设计,历史分区不会再变化,因此增量备份通常只需要备份最新的一两个分区,体积和时间都会大幅下降。
# 先创建全量备份(自动成为增量基准) clickhouse-backup create_remote full_20250120 之后创建增量备份 clickhouse-backup create_remote inc_20250121 使用 --diff-from-remote 指定远程基准备份 clickhouse-backup create_remote inc_20250122 --diff-from-remote full_20250120增量备份的恢复通常需要先恢复基准全量备份,再恢复后续的增量备份。clickhouse-backup 在处理时能够识别备份之间的依赖关系。
7.6 表级备份与恢复
clickhouse-backup 还支持只备份指定的表,这在大表场景下非常有用:
# 备份指定表 clickhouse-backup create backup_events_only --tables "default.events" 备份多个表 clickhouse-backup create backup_two_tables --tables "default.events,default.orders" 排除某些表 clickhouse-backup create backup_except_some --exclude-tables "system.*"恢复时可以只恢复指定表:
# 从备份中只恢复 default.events 表 clickhouse-backup restore backup_name --tables "default.events"7.7 恢复操作
恢复备份的基本命令如下:
# 从本地备份恢复 clickhouse-backup restore backup_name 从远程备份恢复(自动下载) clickhouse-backup restore_remote backup_name 只下载远程备份到本地,不恢复 clickhouse-backup download backup_name 恢复时指定 schema 变更 clickhouse-backup restore backup_name --tables "default.events" --schema恢复操作的执行时间取决于备份的体积和存储介质。恢复完成后,建议执行查询验证数据完整性:
clickhouse-client --query "SELECT count(), max(event_date) FROM default.events" clickhouse-client --query "SELECT * FROM system.backups" # 查看备份相关系统表7.8 clickhouse-backup 的优缺点
优点主要体现在以下几个方面:
- 功能完整:原生支持全量备份、增量备份、表级备份与恢复,并且能够自动管理备份之间的依赖关系。
- 远程存储集成好:可以直接上传到 S3、GCS、Azure Blob、FTP/SFTP 等对象存储,适合异地容灾。
- 自动化程度高:提供 Docker 镜像和 Kubernetes 支持,可以接入 CronJob、Airflow 等调度平台。
- 运维成本低:相比手工 FREEZE 加 tar,命令更简洁,备份元数据统一管理,便于清单查询和按需恢复。
缺点也需要客观认识:
- 仍是逻辑备份:底层依赖 FREEZE 和 shadow 目录,超大集群首次全量备份耗时仍然较长。
- 版本兼容要求:工具版本需要与 ClickHouse 版本保持兼容,升级 ClickHouse 后应及时升级 clickhouse-backup。
- 权限与配置要求:需要能够访问 ClickHouse 数据目录、配置文件和 ZooKeeper,并对备份账号有一定权限要求。
- 大规模表多时管理复杂:虽然支持批量操作,但表数量极多、备份策略差异大时,仍需借助脚本或配置管理。
八、原生 BACKUP/RESTORE 语句
从 ClickHouse 22.x 版本开始,社区推出了原生BACKUP和RESTORE语句,并在后续版本中不断完善。原生备份支持把数据库或表备份到本地磁盘、S3 对象存储等位置,恢复时也能按库、按表粒度还原。相比第三方工具,原生 BACKUP 更贴近内核,能够直接复用 ClickHouse 自身的 Part 管理和元数据能力。
8.1 BACKUP 语句的基本用法
原生 BACKUP 支持库级、表级和分区级备份,语法整体比较统一。最基础的库级备份示例:
-- 备份整个 default 数据库到磁盘 BACKUP DATABASE default TO Disk('backups', 'default_20250120.zip');其中Disk('backups', 'path')表示使用 ClickHouse 配置中名为backups的磁盘,备份文件保存为对应路径。表级备份可以写成:
-- 备份单张表 BACKUP TABLE default.events TO Disk('backups', 'events_20250120.zip'); -- 备份指定分区 BACKUP TABLE default.events PARTITION '202501' TO Disk('backups', 'events_202501.zip');8.2 备份到 S3 对象存储
原生 BACKUP 也支持 S3 兼容对象存储,需要先在配置中声明 S3 磁盘或直接使用S3函数。示例:
BACKUP DATABASE default TO S3('https://oss.example.com/backups/default_20250120.zip', 'access_key', 'secret_key');使用 S3 备份时,ClickHouse 会把备份写入对象存储,适合异地容灾。实际使用中建议把访问密钥放入config.xml或密钥管理工具中,避免直接在 SQL 中暴露。
8.3 RESTORE 恢复操作
恢复时使用RESTORE语句。需要注意的是,恢复目标表默认不能已经存在同名对象,否则会报错,除非使用REPLACE参数覆盖:
-- 恢复 default 数据库 RESTORE DATABASE default FROM Disk('backups', 'default_20250120.zip'); -- 恢复单张表并覆盖现有表 RESTORE TABLE default.events FROM Disk('backups', 'events_20250120.zip') REPLACE;从 S3 恢复时把目标改为对应的 S3 位置即可。恢复完成后建议立即校验行数和分区范围,确认数据符合预期。
8.4 原生 BACKUP/RESTORE 的适用场景
原生 BACKUP/RESTORE 的优势是与内核版本同步演进,无需额外安装工具,而且支持对象存储和压缩,适合对备份链路要求简单、希望减少第三方依赖的团队。但它目前在大规模集群、跨版本恢复、增量备份和细粒度审计方面的能力相比 clickhouse-backup 仍有一定差距。因此,生产环境仍建议结合实际场景,在原生 BACKUP 与 clickhouse-backup、文件系统快照之间组合选择。
九、备份验证与恢复演练
备份任务只能算完成了一半,真正的容灾能力必须通过「可恢复」来证明。实际生产环境中,很多团队做了长期备份,却从未验证过备份是否真的可以还原。等到灾难发生时才发现备份文件损坏、元数据缺失或权限错误,后果非常严重。因此,必须把恢复演练纳入运维规范。
9.1 备份清单与元数据检查
每一次备份完成后,都应记录并检查以下信息:备份名称、备份时间、备份范围、备份体积、备份位置、是否包含 DDL 和 ZooKeeper 元数据、校验和等。对于 clickhouse-backup,可以通过list命令查看清单;对于手工备份,可以在备份目录中生成backup_manifest.txt,内容包括:
backup_name=clickhouse_full_20250120 created_at=2025-01-20 03:00:00 scope=all_databases size=12582912000 ddl=included zookeeper=not_applicable checksum_algorithm=sha2569.2 周期性恢复演练
建议按周或月为单位,在独立的演练环境执行一次完整恢复。演练环境最好与生产使用相同版本的 ClickHouse 和相同的操作系统、文件权限配置。演练流程如下:
- 创建一台干净的 ClickHouse 节点,版本与生产一致。
- 从备份介质拉取最近一次全量备份以及后续增量备份。
- 按先全量、后增量的顺序执行恢复。
- 启动服务,执行
SELECT count()、分区分布、抽样查询校验。 - 记录演练耗时,作为 RTO 的实测依据。
如果恢复脚本或文档在演练中发现不适用,应及时修正。演练本身不应影响生产备份任务。
9.3 数据一致性校验
恢复后不能只看行数是否一致,还要检查分区、排序键、数据分布和关键指标。常用校验 SQL:
-- 对比总行数 SELECT count() FROM default.events; -- 按分区查看数据量 SELECT partition, count() FROM system.parts WHERE database = 'default' AND table = 'events' AND active GROUP BY partition ORDER BY partition; -- 抽样校验明细 SELECT * FROM default.events ORDER BY event_time DESC LIMIT 100;如果生产环境可以接受只读验证,还可以将恢复后的表临时挂载为只读表,抽样对比业务指标,进一步确认数据正确性。
十、备份监控与告警
备份任务如果不能被有效监控,就可能在无人察觉的情况下长期失败。调度脚本、clickhouse-backup、云平台快照都应有对应的监控与告警。
10.1 关键监控指标
- 备份成功率:每次备份任务是否返回成功状态。
- 备份耗时:防止备份时间过长,影响下一个备份窗口。
- 备份体积:快速发现数据异常激增或遗漏。
- 备份留存数量:检查本地和远程保留的策略是否满足要求。
- 磁盘剩余空间:防止 shadow 目录、本地备份和临时文件占满磁盘。
10.2 使用 system 表观察备份状态
对于原生 BACKUP/RESTORE,ClickHouse 提供system.backups和system.backup_log表,可以查看备份记录:
SELECT * FROM system.backups ORDER BY start_time DESC LIMIT 10; SELECT * FROM system.backup_log ORDER BY start_time DESC LIMIT 10;对于 clickhouse-backup,可以在 CronJob 或调度脚本中捕获退出码、输出日志,并把这些结果写入监控系统。
10.3 告警示例
以 shell 脚本为例,当备份失败或超过预期时间时,可以调用 Webhook 通知:
#!/bin/bash set -e START=$(date +%s) clickhouse-backup create_remote "full_$(date +%Y%m%d_%H%M%S)" END=$(date +%s) DURATION=$((END - START)) if [ "$DURATION" -gt 7200 ]; then curl -X POST "$ALERT_WEBHOOK" -H 'Content-Type: application/json' -d "{"text": "ClickHouse 备份耗时异常:${DURATION} 秒"}" fi生产环境建议把备份结果接入 Prometheus、Zabbix、Alertmanager 或企业微信、钉钉、飞书等通知渠道,做到失败即告警。
十一、总结与最佳实践
ClickHouse 备份没有银弹,不同方案在一致性、停机影响、恢复粒度、自动化程度和运维成本上各有取舍。下表对本文介绍的方案做了横向对比:
| 备份方案 | 是否停机 | 粒度 | 实现复杂度 | 适用场景 |
|---|---|---|---|---|
| 冷备份 | 是 | 整库 | 低 | 测试、开发、可接受停机的环境 |
| FREEZE 加影子副本 | 否 | 库/表/分区 | 中 | 单表或少量核心表热备份 |
| 文件系统/LVM/ZFS 快照 | 否 | 整卷 | 中 | 底层快速恢复、兜底备份 |
| 云盘快照 | 否 | 整盘 | 低 | 云上容灾兜底 |
| clickhouse-backup | 否 | 库/表/分区 | 中 | 日常全量与增量备份、对象存储上传 |
| 原生 BACKUP/RESTORE | 否 | 库/表/分区 | 中 | 希望减少第三方依赖、使用内核能力 |
最后给出几条可以直接落地的实践建议:
- 先定目标:和业务方明确 RPO、RTO,再选择备份组合,避免过度设计。
- 全量加增量:按时间分区时优先使用周全量、天增量策略,控制备份体积和时间。
- 元数据不遗漏:同时备份 DDL、用户权限、ZooKeeper 元数据和配置文件。
- 备份要传得出去:生产备份至少保留一份在异地或对象存储中,防止同机房故障。
- 演练才算数:定期恢复演练,实测 RTO,验证备份可用性和恢复文档。
- 全程可观测:对备份状态、耗时、体积和磁盘空间做监控告警。
只要把备份、校验、恢复、演练、监控五个环节串成闭环,ClickHouse 的备份体系就能从看起来有备份升级为真正可恢复,为业务数据提供可靠保障。