继续针对我们在CK上遇到的问题,展开来学习和复盘。
问题背景
我们在生产上有一个基于ReplicatedMergeTree引擎的无用的业务表,在一个CK节点上执行了truncate xx 的操作后,因为其他原因重启集群的所有节点,发现所有的节点都无法正常启动,关键报错信息如下:
The local set of parts of table xxx doesn’t look like the set of parts in ZooKeeper
复制
从报错信息来看是本地的数据和zookeeper上的数据对不上了。
解决方案
在网上搜了一下,比较靠谱的解决方案来自华为云上的一篇文章,虽然说事故原因并不完全相同,但解决方案仍然可以参考
https://support.huaweicloud.com/trouble-mrs/mrs_03_0281.html
备份移走问题节点的表数据到其他目录:这里既要备份移走表的数据和表结构的metadata,下面是备份default数据库下的表test数据到/home/backup目录下:
# 备份表的数据
mv data/clickhouse/data/default/test home/backup/
# 备份表结构metadata
mv /data/clickhouse/metadata/default/test.sql /home/backup
复制
2. 启动Clickhouse,然后获取当前表所在的ZooKeeper路径zookeeper_path和对应节点所在的副本编号replica_num:
# 获取表的zk path
select zookeeper_path from system.replicas where database='default' and table='test';
#获取对应节点的replica_num , 这个其实也可以直接从ck的配置文件中查到
SELECT replica_num,host_name FROM system.clusters;
复制
3. 在zookeeper找到对应节点的表的副本数据并删除:
# 定位表的副本数据 ls <zookeeper_path>/replicas/<replica_num>
ls /clickhouse/tables/default/01/test/replicas/46161.ck.navrmo.ml
[columns, flags, host, is_active, is_lost, log_pointer, max_processed_insert_time, metadata, metadata_version, min_unprocessed_insert_time, mutation_pointer, parts, queue]
# 删除表的副本数据
deleteall <zookeeper_path>/replicas/<replica_num>
复制
4. 重新在问题节点上建表, 其他副本节点有如下提示表已经存在的报错信息,属于正常现象,可以忽略。建表成功后问题节点上表数据会自动进行同步,数据恢复完成。
CREATE TABLE <db_name>.<tb_name> ON CLUSTER <cluster_name>
...
ENGINE = ReplicatedMergeTree
复制
梳理下其实华为的方案主要就是三步:
在CK问题节点清理掉表数据和表结构
在zookeeper找到对应节点的表的副本数据并删除
在CK问题节点重新建ReplicatedMergeTree表,然后等待CK自动同步数据。
这个方案的原理就是基于CK的副本表的基本原理,将问题表干掉后重建,让CK自己去恢复数据。CK的副本表相关知识可以参考ClickHouse从单节点升级为副本集群
启动失败的原因和官方解决方案
官方文档对启动失败的原因也给出了解释:
https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication/
当服务器启动(或与 ZooKeeper 建立新会话)时,系统会检查本地文件系统中的数据集是否与预期的数据集( ZooKeeper 存储此信息)是否一致。如果存在轻微的不一致,系统会通过与副本同步数据来解决。如果本地数据集与预期数据的差异太大,则会触发安全机制。服务器在日志中记录此内容并拒绝启动。这就是我们这次报错所遇到的情况,然而,此机制的阈值设置得相当低,在正常故障恢复期间可能会出现这种情况。在这种情况下,数据恢复则是半自动模式,通过用户主动操作触发:
要触发启动恢复,可在 ZooKeeper 中创建节点 /path_to_table/replica_name/flags/force_restore_data,节点值可以是任何内容。
或者通过在服务器上创建一个文件来恢复所有的可复制表:
sudou clickhouse touch /var/lib/clickhouse/flags/force_restore_dat
a
复制
然后重启服务器。启动时,服务器会删除这些标志并开始恢复。
官方文档还给出了在节点完全丢失所有数据和元数据时候的恢复办法,其中一个就是:从 ZooKeeper(/path_to_table/replica_name)中删除有数据丢失的副本的所有元信息,再在故障服务器重新创建副本表, 重启服务器,等待CK的副本同步机制自动恢复数据。
仔细在回顾下上文华为给出的解决方案就是人为的通过删除所有数据和元数据,然后采取官方给出的在节点完全丢失所有数据和元数据时候的恢复办法。
小结
我最终还是没有找到为什么truncate副本表的操作会导致这个问题的根本原因,只是在网上看到说 "这是由于truncate、alter等ddl语句用了on cluster,偶尔导致zookeeper同步异常" 。但通过官方文档还是了解了为什么CK会启动失败,以及在CK数据异常时如何恢复, 其核心原理还是CK的副本表的自动同步机制,理解了这个原理,其实很多数据不一致的问题,都可以通过干掉副本数据和元数据, 然后让CK自己再重新自动同步的方法来解决。