在本地存储或 NAS 上进行 ClickHouse 备份和恢复

概述

本文档介绍如何使用本地存储或已挂载的 NAS 目录对 observability 数据库中的 ClickHouse 表进行备份和恢复。此操作流程适用于使用 ReplicatedMergeTree 表引擎的集群。

对于 ClickHouse,NAS 挂载会被视为本地文件系统路径。因此,本地存储和 NAS 可以使用相同的备份与恢复方法。

本文档提供以下指导:

  • 创建全量备份。
  • 基于全量备份创建增量备份。
  • 将备份数据存储在本地目录或 NAS 挂载路径中。
  • 从本地或 NAS 备份中恢复数据。
  • 验证备份和恢复结果。

本文档以 observability.audit 表为示例。你可以将同样的流程应用于其他表。

常见示例如下:

  • audit:存储审计数据。
  • event:存储事件数据。
  • log_kubernetes:存储 Kubernetes 日志。
  • log_platform:存储平台服务日志。
  • log_system:存储节点级系统日志。
  • log_workload:存储应用和工作负载日志。

存储类型的差异如下:

  • LocalVolume:ClickHouse 数据存储在节点本地目录中,例如 /cpaas/data/clickhouse/。BACKUP ... TO File(...) 会将备份文件写入该本地数据目录下的 ClickHouse 备份目录,例如 /cpaas/data/clickhouse/backups。
  • StorageClass,例如 TopoLVM、NFS 或 Ceph:ClickHouse 数据存储在对应的 StorageClass 卷上。BACKUP ... TO File(...) 会将备份文件写入该卷上的 ClickHouse 备份目录。
  • NAS 归档路径:可以将备份文件从 ClickHouse 备份目录复制到已挂载的 NAS 路径或其他自定义备份目录,以便长期保留。

对于 LocalVolume 和 StorageClass 部署,在归档备份文件时使用实际的 ClickHouse 备份目录作为源路径,在恢复时将备份文件复制回该目录作为目标路径。

前提条件

开始之前,请确保满足以下条件。

环境要求

项目要求
ClickHouse25.3 或更高版本
表引擎ReplicatedMergeTree
备份目标挂载到主机的本地目录或 NAS 目录

访问要求

本文档中的所有 SQL 语句都使用 ClickHouse 内置管理员账户 default。

你可以在任意健康的 ClickHouse 实例上运行这些 SQL 语句。为保持一致性,本文档以单个 ClickHouse Pod 为例。

在运行 SQL 语句之前,先连接到目标 Pod:

kubectl exec -ti -n cpaas-system chi-cpaas-clickhouse-replicated-0-0-0 -- bash

然后连接容器中的 ClickHouse:

clickhouse-client

default 用户已经具备此操作所需的权限,包括 BACKUP、RESTORE、SELECT 和 ALTER。

目录要求

请确保满足以下条件:

  • ClickHouse 进程对目标目录具有读写权限。
  • 目标目录具有足够的可用容量。
  • 如果使用 NAS,在 Pod 或主机重启后挂载点能够自动恢复。
  • 在 Kubernetes 中,该目录通过 PVC、hostPath 或 CSI 挂载。

备份策略

建议使用以下备份策略:

  • 仅在任意健康副本上执行一次备份操作。
  • 使用 BACKUP TABLE 在不中断服务的情况下创建一致性快照。
  • 在增量备份中使用 base_backup 进行文件级去重。
  • 恢复增量备份时,保留可访问的基础全量备份。
  • 每周保留一个全量备份、每天保留一个增量备份,以平衡恢复复杂度和存储成本。

操作步骤

以下示例使用初始全量备份和每日增量备份。

创建全量备份

全量备份会为后续增量备份创建基线。

在任意健康的 ClickHouse 实例上运行以下命令:

BACKUP TABLE observability.audit
TO File('audit_full_20260423')
SETTINGS compression_method = 'zstd';

说明:

  • File(...) 会将备份写入 ClickHouse 数据卷上的 ClickHouse 备份目录。
  • 对于 LocalVolume 部署,备份目录通常位于主机节点上的 /cpaas/data/clickhouse/backups。
  • 对于 TopoLVM、NFS 或 Ceph 等 StorageClass 部署,备份目录位于对应 StorageClass 卷上。
  • compression_method = 'zstd' 会使用 zstd 压缩备份内容,以减少存储占用。
  • 如果需要将备份归档到 NAS 或其他自定义备份目录,请在备份任务完成后复制备份。

验证备份成功

备份完成后,验证结果。

检查备份任务状态

在执行备份命令的 ClickHouse 实例上运行以下查询:

SELECT
    id,
    name,
    status,
    error,
    start_time,
    end_time,
    num_files,
    total_size
FROM system.backups
ORDER BY start_time DESC
LIMIT 10
FORMAT Vertical;

预期结果:

通过 name 字段找到 observability.audit 的备份记录。如果满足以下条件,则表示备份成功:

  • status = 'BACKUP_CREATED'
  • error 为空
  • end_time 有值
  • num_files > 0
  • total_size > 0

检查备份目录

在 ClickHouse 备份目录可用的节点或容器中运行以下命令。

对于 LocalVolume 部署,备份目录通常为 /cpaas/data/clickhouse/backups:

ls -lah /cpaas/data/clickhouse/backups

对于 StorageClass 部署,请检查对应 StorageClass 卷上的备份目录。

预期结果:

  • 备份目录存在。
  • 目录包含本次备份生成的文件或文件夹。
  • 文件数量和总大小均大于 0。

创建增量备份

增量备份使用 base_backup,仅写入新增或变更的数据文件。

在任意健康的 ClickHouse 实例上运行以下命令:

BACKUP TABLE observability.audit
TO File('audit_incr_20260424')
SETTINGS
  base_backup = File('audit_full_20260423'),
  compression_method = 'zstd';

说明:

  • 增量备份依赖 base_backup 指定的备份。
  • 本文档建议每个每日增量备份都使用最新的全量备份作为 base_backup,而不是使用上一个增量备份作为基础。这样可以简化恢复依赖:恢复每日增量备份时,只需要该增量备份及其对应的全量备份。
  • 在恢复增量备份时,请保留其依赖的全量备份。
  • 定期创建新的全量备份,以避免长期依赖同一个基线。

归档备份文件

BACKUP ... TO File(...) 会将备份文件写入执行备份命令的 ClickHouse 数据卷上的 ClickHouse 备份目录。

备份目录取决于存储类型:

  • 对于 LocalVolume 部署,ClickHouse 数据目录位于主机节点上,通常是 /cpaas/data/clickhouse/,备份文件会生成在 /cpaas/data/clickhouse/backups 下。
  • 对于 TopoLVM、NFS 或 Ceph 等 StorageClass 部署,ClickHouse 数据目录位于对应 StorageClass 卷上,备份文件会生成在该卷上的 ClickHouse 备份目录中。

备份成功后,将备份文件从实际的 ClickHouse 备份目录复制到自定义备份目录或 NAS 挂载路径进行保留。

对于 LocalVolume 部署,源路径通常为 /cpaas/data/clickhouse/backups:

cp -r /cpaas/data/clickhouse/backups/audit_full_20260423 /my_dir/audit_full_20260423
cp -r /cpaas/data/clickhouse/backups/audit_incr_20260424 /my_dir/audit_incr_20260424

对于 StorageClass 部署,请将 /cpaas/data/clickhouse/backups 替换为 StorageClass 卷上实际的 ClickHouse 备份目录。

说明:

  • /my_dir 可以是指定的本地归档目录,也可以是 NAS 挂载路径。
  • 归档路径应位于 ClickHouse 数据目录之外。否则,在灾难恢复期间清理 ClickHouse 数据目录时,备份文件可能会被删除。
  • 每次全量或增量备份后,都应将对应的备份目录复制到归档位置。
  • 增量备份复制成功后,如果本地备份不再需要,可以删除 ClickHouse 备份目录下的本地增量备份。
  • 只有在下一次全量备份成功且保留策略允许清理时,才删除 ClickHouse 备份目录下的本地全量备份。
  • 如果后续使用 RESTORE ... ON CLUSTER ... FROM File(...) 进行恢复,请确保在运行恢复命令之前,所需的全量和增量备份目录已复制回每个 ClickHouse 主机节点上的 ClickHouse 备份目录。

恢复

当表数据损坏、数据目录被删除或表状态异常时,使用此流程。

恢复前提

开始恢复流程之前,请确保满足以下条件:

  • 你有有效的全量备份或增量备份。
  • 如果从增量备份恢复,对应的全量备份在恢复路径中可用。
  • 你知道存储最新增量备份及其对应全量备份的归档目录。
  • 你可以访问 Kubernetes 集群以及 ClickHouse 实例所在的主机节点。

恢复操作步骤

该流程按表逐一恢复 ClickHouse 数据。根据故障范围选择相应的准备步骤,然后对每个需要恢复的表执行相同的恢复流程。

停止写入

先停止 razor,以防在恢复期间写入新数据。

登录到集群主节点并创建一个 ResourcePatch 来停止 razor:

cat <<EOF > /tmp/rp-stop-razor.yaml
apiVersion: operator.alauda.io/v1alpha1
kind: ResourcePatch
metadata:
  generateName: rp-
  name: rp-stop-razor
spec:
  jsonPatch:
  - op: replace
    path: /spec/replicas
    value: 0
  release: cpaas-system/logclickhouse
  target:
    apiVersion: apps/v1
    kind: StatefulSet
    name: razor
    namespace: cpaas-system
EOF

kubectl apply -f /tmp/rp-stop-razor.yaml

根据故障范围准备 ClickHouse

根据故障范围选择以下一种准备路径。准备完成后,继续执行相同的逐表恢复流程。

场景 A:表数据损坏,但数据目录正常

当一个或多个表损坏、被误删或数据异常,而 ClickHouse 数据目录和 Keeper 状态仍然正常时,使用此场景。

在此情况下,不要停止 ClickHouse,也不要清理 ClickHouse 数据目录。直接继续执行逐表恢复流程。

场景 B:数据目录或 Keeper 元数据损坏

仅当 ClickHouse 数据目录损坏、节点已重建或 Keeper 元数据不可用时,使用此场景。

在此部署中,ClickHouse Keeper 与 ClickHouse 集成,其数据也存储在 ClickHouse 数据目录下。因此,清理 ClickHouse 数据目录也会删除本地 ClickHouse Keeper 数据。

警告: 清理数据目录会删除目标节点上的本地 ClickHouse 数据。继续之前,请确认备份可用。

请根据存储类型清理每个 ClickHouse 实例实际使用的 ClickHouse 数据目录。对于 LocalVolume 部署,目录通常是主机节点上的 /cpaas/data/clickhouse/。对于 StorageClass 部署,请清理对应 StorageClass 卷或 PV 上的 ClickHouse 数据目录。除非已确认 /cpaas/data/clickhouse/ 就是实际挂载的数据路径,否则不要在 StorageClass 部署中使用该路径。

登录到集群主节点并创建一个 ResourcePatch 来停止 ClickHouse:

cat <<EOF > /tmp/rp-stop-ck.yaml
apiVersion: operator.alauda.io/v1alpha1
kind: ResourcePatch
metadata:
  generateName: rp-
  name: rp-stop-ck
spec:
  jsonPatch:
  - op: add
    path: /spec/stop
    value: "true"
  release: cpaas-system/logclickhouse
  target:
    apiVersion: clickhouse.altinity.com/v1
    kind: ClickHouseInstallation
    name: cpaas-clickhouse
    namespace: cpaas-system
EOF

kubectl apply -f /tmp/rp-stop-ck.yaml

确认所有 ClickHouse Pod 都已停止:

kubectl get pod -n cpaas-system | grep -i "chi-cpaas-clickhouse-replicated"

根据存储类型清理每个 ClickHouse 实例的 ClickHouse 数据目录。

对于 LocalVolume 部署,在部署了 ClickHouse 实例的每个主机节点上运行以下命令:

rm -rf /cpaas/data/clickhouse/*

对于 StorageClass 部署,请清理对应 StorageClass 卷或 PV 上的 ClickHouse 数据目录。具体路径取决于 StorageClass 和 CSI 实现。请使用实际挂载的 ClickHouse 数据路径,而不是 LocalVolume 的示例路径。

通过删除 ClickHouse ResourcePatch 仅启动 ClickHouse 组件。此时不要启动 razor。

kubectl delete -f /tmp/rp-stop-ck.yaml

确认所有 ClickHouse Pod 都在运行:

kubectl get pod -n cpaas-system | grep -i "chi-cpaas-clickhouse-replicated"

在每个 ClickHouse 节点上准备备份文件

确保备份文件在每个 ClickHouse 主机节点上的 ClickHouse 备份目录中可用。

如果备份文件已归档到自定义备份目录或 NAS 挂载路径,并且 ClickHouse 备份目录下的本地文件已被删除,那么在恢复表之前,请先将最新的增量备份及其对应的全量备份复制回每个 ClickHouse 主机节点上的 ClickHouse 备份目录。

对于 LocalVolume 部署,目标路径通常为 /cpaas/data/clickhouse/backups:

mkdir -p /cpaas/data/clickhouse/backups
cp -r /my_dir/audit_full_20260423 /cpaas/data/clickhouse/backups/audit_full_20260423
cp -r /my_dir/audit_incr_20260424 /cpaas/data/clickhouse/backups/audit_incr_20260424

对于 StorageClass 部署,请将备份文件复制回 StorageClass 卷上实际的 ClickHouse 备份目录。

说明:

  • 如果从增量备份恢复,请同时准备其依赖的全量备份。
  • 备份文件必须放在每个 ClickHouse 主机节点上的 ClickHouse 备份目录下,以便 RESTORE ... ON CLUSTER ... FROM File(...) 可以在每个 ClickHouse 实例上访问这些文件。
  • 请将 /my_dir、/cpaas/data/clickhouse/backups、audit_full_20260423 和 audit_incr_20260424 替换为实际的归档路径、ClickHouse 备份目录和备份目录名称。

检查集群就绪状态

在运行恢复命令之前,请确保 ClickHouse 集群配置和宏可用。

检查 replicated 集群配置:

SELECT *
FROM system.clusters
WHERE cluster = 'replicated';

检查本地 ClickHouse 宏:

SELECT *
FROM system.macros;

确保集群包含预期的 ClickHouse 副本,并且 shard 和 replica 等宏可用。

逐个恢复表

对每个需要恢复的表执行以下恢复流程。

在 ClickHouse 集群上删除目标表:

DROP TABLE observability.audit ON CLUSTER 'replicated' SYNC;

从本地或 NAS 备份中恢复表:

RESTORE TABLE observability.audit
ON CLUSTER 'replicated'
FROM File('audit_incr_20260424');

说明:

  • 对于该 3 副本部署中的 ReplicatedMergeTree 表,请使用 ON CLUSTER 'replicated',以便将恢复操作分发到集群中的所有 ClickHouse 副本。
  • 如果从增量备份恢复,ClickHouse 会自动读取其依赖的基础备份。
  • 在恢复期间,请保持对应的全量备份目录可访问。
  • 请将 observability.audit 和备份目录名称替换为实际要恢复的表和备份。
  • 对于每个需要恢复的表,重复相同的流程。表列表由客户决定。

检查恢复任务状态

执行每个恢复命令后,在启动任何相关组件之前检查恢复任务状态:

SELECT
    id,
    name,
    status,
    error,
    start_time,
    end_time,
    num_files,
    total_size
FROM system.backups
ORDER BY start_time DESC
LIMIT 10
FORMAT Vertical;

预期结果:

如果满足以下条件,则表示恢复成功:

  • status 表示恢复操作已成功完成。
  • error 为空。
  • end_time 有值。

验证恢复成功

恢复完成后,从数据、分区和副本三个维度验证结果。

验证总行数

在每个 ClickHouse 实例上运行以下查询:

SELECT count(*) AS total_rows
FROM observability.audit;

预期结果:

所有 ClickHouse 实例上的 total_rows 值完全一致。

验证分区级数据

在每个 ClickHouse 实例上运行以下查询:

SELECT
    partition,
    sum(rows) AS rows,
    count() AS active_parts
FROM system.parts
WHERE active
  AND database = 'observability'
  AND table = 'audit'
GROUP BY partition
ORDER BY partition;

预期结果:

  • 所有 ClickHouse 实例上的 partition 列表完全一致。
  • 所有 ClickHouse 实例上每个分区的 rows 值完全一致。

active_parts 仅用于观察物理分片布局。不同的分片数量并不一定表示恢复失败。

验证副本状态

在任意 ClickHouse 实例上运行以下查询:

SELECT
    database,
    table,
    total_replicas,
    active_replicas,
    queue_size,
    absolute_delay
FROM system.replicas
WHERE database = 'observability'
  AND table = 'audit';

预期结果:

对于 3 副本集群,如果满足以下条件,则表示恢复成功:

  • total_replicas = 3
  • active_replicas = 3
  • queue_size = 0
  • absolute_delay 接近 0

启动相关组件

在恢复成功验证完成后,通过删除 ResourcePatch 重新启动 razor:

kubectl delete -f /tmp/rp-stop-razor.yaml

建议

在生产环境中建议采用以下做法:

  • 保持备份链:每周一个全量备份、每天一个增量备份。
  • 使用统一的备份目录命名规范,例如 full_YYYYMMDD 和 incr_YYYYMMDD。
  • 定期在测试环境中执行恢复演练。
  • 为过期的增量备份和历史全量备份制定保留策略。