通过一个故障案例,理解 ClickHouse 分布式机制。

作者:张宇,爱可生DBA,负责数据库运维和故障分析。擅长 ClickHouse、MySQL、Oracle,爱好骑行、AI、动漫和技术分享。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 1500 字,预计阅读需要 5 分钟。

业务场景

在日常运维的某个系统下,有一套 4 分片 3 副本的高可用分布式的 ClickHouse 集群。当前分片的每个节点的数据量为 5.6TB。

故障背景

监控发现其中的一个节点无法使用,后续排查发现 5 块磁盘已经损坏,Raid10 也无法保证数据完整,导致数据目录全部重新换成新的磁盘,而且使用的是传统机械盘,速度慢。现在联系厂商更换磁盘,需要停用此节点,等厂商更换完毕之后,需要配合恢复数据。

恢复思路

ClickHouse 的集群是一个分布式的集群,每个分片的数据不同,所有分片的数据加起来才是一份完整的数据,每个分片副本的数据是相同的,这就是 ClickHouse 数据的高可用。

本次也是非常典型的故障,硬件做了 Raid10,但是 Raid10 磁盘基本上全部坏掉了,导致 Raid10 离线也无法使用,最后更换了所有的磁盘,导致整个数据目录变成了空的。

因为此副本为一个分片中的其中一个副本,还有其他两个副本在线,所以业务使用无影响,而且我们可以通过其他副本里面的数据开始恢复此副本的数据。

恢复的基本原理: 同一个分片里面 Zookeeper 路径相同的表,但是副本名不同。数据是会自动验证同步的,所以我们只需要重建表,并且保证 Zookeeper 地址一致,副本名不一致,就会自动开始同步数据,直到两个副本数据完全一致。

副本之间是如何同步数据的呢?

Zookeeper 里面存放了副本数据文件 parts 的路径。如果当前副本没有这些 parts 就会通过 Zookeeper 得到其他副本的 parts 路径,然后通过 9009 端口进行数据文件的传输,然后恢复数据。

如下是官方的原理图:

查看节点是否存在残留数据

  • clickhouse-1:同一个分片正常副本
  • clickhouse-2:坏掉的副本
shell> clickhouse-client --password
clickhouse-2> show databases;

经过确认无残留数据。

查看当前节点的副本

clickhouse-2>select * from system.clusters;

is_local 为 1 就是当前登录的节点。

恢复数据

因为旧节点磁盘损坏,所以需要在它的其他副本得到这些信息,然后到损坏的节点执行:

shell> clickhouse-client --password --host=xxx.xxx.77.30 --port=9000
clickhouse-1>select database,table,replica_is_active from system.replicas;

第三副本的表全部都无法访问。

导出清理 Zookeeper 元数据的 SQL 语句。

因为只是磁盘坏了,本地数据没有了,但是 Zookeeper 里面的数据还存在,如果不清理,重建表的时候会导致元数据冲突无法创建表。

创建清理 Zookeeper 元数据的 SQL 文件。

shell> vim clear_zk.sql

清理 Zookeeper 的元数据。

shell>  clickhouse-client --password --port 9000 --multiquery < clear_zk.sql 2&>1 clear.log7

导出表结构。

clickhouse-1>select   zookeeper_path ,create_table_query from  system.tables a right join system.replicas b on a.name=b.table where a.database  in ('xxx','xxx','xxx') ;

创建所有数据库。

clickhouse-2>create database xxx;

创建建表的 SQL 文件。

PS:要注意这个标红的一定要和 Zookeeper 元数据的地址一样,就是上面导出来的时候第一列就是 Zookeeper 的元数据的地址,一定要好好验证,有些客户建表是存在uuid的,如果存在uuid一定要比对保证地址一样不然无法恢复数据。

ReplicatedReplacingMergeTree(‘/clickhouse/tables/3/xxxx/xxxxx’, ‘{replica}’, created_time)

shell> vim init_table.sql

重建表并确认表是否同步数据。

shell>clickhouse-client --password --port 9000 --multiquery < init_table.sql

检查表的数据是否正确这里总共 22 张本地表,存于在 3 个库。

经过验证已经全部重建完毕,现在验证数据是否传输。

clickhouse-2>use database
clickhouse-2>select * from xxxx limit 5;

检查磁盘的同步情况。

shell>df -h

数据一直同步每分钟数据量大概 10GB 的速度同步回来。

恢复分布式总表

 shell>clickhouse-client --password --host=xxx.xxx.77.30 --port=9000
 clickhouse-1>select   create_table_query from  system.tables a  where a.database  in ('xxx','xxx','xxx') and engine='Distributed';

创建分布式表的初始化 SQL 文件。

 shell>vim init_d_table.sql

同步。

shell>clickhouse-client --password --port 9000 --multiquery < init_d_table.sql

检查分布式总表是否全部创建总共 22 张。

clickhouse-2>select  count(1) from  system.tables a  where a.database  in ('xxx','xxx','xxx') and engine='Distributed';

查询分布式总表看看是否有数据。

通过其他副本验证同步复制关系是否正常

shell>clickhouse-client --password --host=xxx.xxx.77.30 --port=9000
clickhouse-1>select database,table,replica_is_active from system.replicas;

已经通过验证所有表已经全部恢复同步。

总结与启示

本次 ClickHouse 数据恢复案例展示了以下具体技术关键点:

  1. 数据冗余备份:
    • 确保每个分片有多个副本,防止单点故障导致数据丢失。
  2. 掌握 ClickHouse 和 Zookeeper 同步机制:
    • 了解如何通过 Zookeeper 获取其他副本的 parts 路径,并使用端口 9009 进行数据传输恢复。
  3. 清理 Zookeeper 元数据:
    • 在磁盘损坏后,需清理 Zookeeper 中的元数据,以避免重建表时发生元数据冲突。
  4. 详细的恢复操作步骤:
    1. 导出表结构并创建数据库。
    2. 使用create_table_query重建表并确认数据同步。
    3. 检查磁盘同步情况,确保数据正确恢复。
  5. 持续监控与维护:
    • 定期检查系统状态,及时发现并解决潜在问题,确保系统高可用性。

这些经验和具体操作步骤能有效提高系统的可靠性和运维效率,增强应对突发故障的能力。

分类: 故障分析

张宇

爱可生DBA,负责数据库运维和故障分析。擅长 ClickHouse、MySQL、Oracle,爱好骑行、AI、动漫和技术分享。