ClickHouse 恢复

本文说明如何使用 clickhouse_ansible 中的恢复 Playbook,将备份批次恢复到目标 ClickHouse 集群。

文中命令默认基于绿色版 Ansible 已执行 setup_portable_ansible.shsource ~/.bashrc,因此直接使用 ansible-playbook

1. 恢复原理概览

恢复流程默认以备份 manifest 为输入,并使用“每分片主副本全量恢复,其他副本结构恢复”的策略:

  1. 每个分片选定一个主副本执行全量恢复。
  2. 其他副本执行 structure_only 恢复,补齐结构与复制元数据。
  3. 随后由 ClickHouse 复制机制完成其余数据追平。

这样可以减少所有副本同时从备份盘做全量导入带来的重复 IO。

2. 前置条件

  1. 已存在可用备份批次和 manifest 文件。
  2. 目标集群已完成 NFS 挂载,并正确配置备份磁盘,例如 backup_nfs
  3. 目标节点均能访问备份挂载目录,例如 /backup
  4. 使用专用恢复 inventory,例如 inventory/hosts.restore.ini
  5. 若目标是原集群灾难恢复,需要先完成停写和对象清理。
  6. 如果是默认演练环境,恢复目标为 192.168.199.141/142/143,备份盘准备使用 inventory/hosts.dr_backup.ini,恢复执行使用 inventory/hosts.restore.ini

3. 恢复 inventory 最小示例

[clickhouse_restore]
ck-141-1 ansible_host=198.51.100.141 shard=1 replica=1 clickhouse_tcp_port=9000
ck-141-2 ansible_host=198.51.100.141 shard=3 replica=2 clickhouse_tcp_port=9001
ck-142-1 ansible_host=198.51.100.142 shard=1 replica=2 clickhouse_tcp_port=9000
ck-142-2 ansible_host=198.51.100.142 shard=2 replica=1 clickhouse_tcp_port=9001
ck-143-1 ansible_host=198.51.100.143 shard=2 replica=2 clickhouse_tcp_port=9000
ck-143-2 ansible_host=198.51.100.143 shard=3 replica=1 clickhouse_tcp_port=9001

[all:vars]
dbbot_inventory_purpose=restore
ansible_python_interpreter=auto_silent
ansible_user=root
ansible_ssh_pass="'<your_ssh_password>'"

4. 关键参数

编辑 playbooks/vars/restore_config.yml,重点确认:

  • restore_batch_id
  • restore_manifest_file
  • restore_to_all_replicas
  • restore_allow_non_empty_tables
  • restore_require_manual_confirm
  • restore_enable_two_phase_mv_compat
  • restore_allow_partial_cluster

补充说明:

  • restore_cluster.yml 也会校验 clickhouse_default_password
  • 如果你仍在用公开默认值 Dbbot_default@8888,默认会被 pre_tasks 拦截;实验环境才建议显式设置 fcs_allow_dbbot_default_passwd: true

5. 恢复前的目标集群准备

cd /usr/local/dbbot/clickhouse_ansible/playbooks
ansible-playbook \
  -i ../inventory/hosts.dr_backup.ini \
  setup_nfs_client_mount_rc_local.yml

ansible-playbook \
  -i ../inventory/hosts.dr_backup.ini \
  prepare_backup_disk.yml \
  -e "backup_storage_disk=backup_nfs backup_mount_dir=/backup"

上面两步必须先在恢复目标集群执行完成,然后再进入正式恢复。

6. 标准恢复命令

cd /usr/local/dbbot/clickhouse_ansible/playbooks
ansible-playbook \
  -i ../inventory/hosts.restore.ini \
  restore_cluster.yml \
  -e "restore_batch_id=20260306T210000_CST_bk001"

默认会提示输入确认短语,例如:RESTORE 20260306T210000_CST_bk001

7. 单副本恢复模式

如果你只希望每个分片恢复一个副本,可临时覆盖:

cd /usr/local/dbbot/clickhouse_ansible/playbooks
ansible-playbook \
  -i ../inventory/hosts.restore.ini \
  restore_cluster.yml \
  -e "restore_batch_id=20260306T210000_CST_bk001 restore_to_all_replicas=false"

该模式更适合演练或特殊场景;在生产使用时,应先确认表结构和复制策略已满足要求。

8. 原集群灾难恢复的推荐顺序

  1. 停止业务写入,冻结变更窗口。
  2. 选定恢复批次,核对 manifest 中的 safe_ts
  3. 使用恢复专用 inventory 指向目标集群。
  4. 人工清理需要恢复的数据库或表。
  5. 执行 restore_cluster.yml
  6. 校验行数、副本状态和复制健康。
  7. safe_ts 为起点执行业务补数或回放。

9. 恢复后验证

8.1 总量核对

SELECT count() FROM <db>.<distributed_table>;

8.2 各副本本地行数

SELECT
  hostName() AS host,
  tcpPort() AS port,
  count() AS rows
FROM clusterAllReplicas('<cluster>', '<db>', '<local_table>')
GROUP BY host, port
ORDER BY host, port;

8.3 复制健康

SELECT table, is_readonly, queue_size, absolute_delay
FROM system.replicas
WHERE database = '<db>'
ORDER BY table;

8.4 TTL 表的验收口径

如果恢复对象带有 TTL ... DELETE,不要直接拿源集群与目标集群的全表 count() 做强一致验收。

原因:

  1. RESTORE 只负责把 part 恢复回来。
  2. TTL DELETE 依赖后台 merge 异步清理,不会在恢复时瞬间全部完成。
  3. 即使手工执行 ALTER TABLE ... MATERIALIZE TTL,源集群和目标集群的执行时刻也可能不同,TTL 边界附近的少量数据仍可能继续漂移。

例如,mysql_slowlog_raw_local 默认是:

  • 造数跨度 60
  • 表 TTL 30 DAY DELETE

这种组合更适合演示 TTL 行为,不适合直接用“全表总数必须完全一样”来做恢复验收。

对 TTL 表,推荐使用以下两种方式之一:

  1. 使用固定时间窗口做对比,源和目标都使用同一个字面 cutoff:
SELECT count()
FROM lab_ck_biz.mysql_slowlog_raw_local
WHERE log_time >= toDateTime('2026-02-07 00:00:00');
  1. 优先选择无 TTL 的业务表做恢复一致性验收。

如果只是想加快 TTL 清理,可在源和目标都执行:

ALTER TABLE lab_ck_biz.mysql_slowlog_raw_local
ON CLUSTER 'example_3shards_2replicas'
MATERIALIZE TTL
SETTINGS mutations_sync = 2;

但要注意:这条命令只能帮助加快 TTL 收敛,仍不建议把 TTL 表的“全表总数完全一致”作为唯一验收标准。

10. 注意事项

  1. 恢复 Playbook 默认要求 inventory 文件名包含 restore 且设置 dbbot_inventory_purpose=restore
  2. Playbook 不会自动执行高风险的 DROP DATABASEDROP TABLE,这些动作需要人工复核后执行。
  3. 对包含物化视图的场景,默认启用两阶段兼容恢复逻辑。
  4. 若备份中包含配置快照,是否回放配置应结合变更窗口和目标环境评估后再决定。
  5. 恢复目标侧的 NFS 挂载和 prepare_backup_disk.yml 不会由 restore_cluster.yml 自动代劳,必须提前准备好。
  6. 如果要做源集群与目标集群的跨集群验收,请使用独立的 ClickHouse 恢复后数据校验 文档与 validate_restore_consistency.yml