写点什么

大数据 -141 ClickHouse 副本实战 | ReplicatedMergeTree + ZooKeeper 从 0–1:创建、选举、日志复制、排障

作者:武子康
  • 2025-11-01
    山东
  • 本文字数:3574 字

    阅读完需:约 12 分钟

大数据-141 ClickHouse 副本实战 | ReplicatedMergeTree + ZooKeeper 从 0–1:创建、选举、日志复制、排障

TL;DR

  • 场景:两台以上 ClickHouse 节点做同步副本,要求写入可在任意副本执行且最终一致。

  • 结论:按本文 SOP,你能在 10–15 分钟完成副本创建、日志复制校验与故障回滚。

  • 产出:配置文件、整个过程、ON CLUSTER DDL、排障速查等。



副本介绍

ReplicatedMergeTreeZooKeeper:实现多个实例之间的通信。

副本的特点

作为数据副本的主要载体,ReplicatedMergeTree 在设计上有一些缺点:


  • 依赖 ZooKeeper: 在执行 INSERT 和 ALTER 查询的时候,ReplicatedMergeTree 需要借助 ZooKeeper 的分布式协同功能,以实现多个副本之间的同步。但是在查询副本的时候,并不需要 ZooKeeper。

  • 表级别的副本:副本是在表级别定义的,所以每张表的副本配置都可以按照它的实际需求进行个性化定义,包括副本的数量,以及副本在集群内的分布位置等。

  • 多主架构(Multi Master):可以在任意一个副本上执行 INSERT 和 ALTER 查询,他们效果是相同的,这些操作会借助 ZooKeeper 的协同能力被分发至每个副本以本地的形式执行。

  • Block 数据块,在执行 INSERT 命令写入数据时,会依据 max_block_size 的大小(默认 1048576 行)将数据切分成 若干个 Block 数据块。所以 Block 数据块是数据写入的基本单元,并且具有写入的原子性和唯一性。

  • 原子性:在数据写入时,一个 Block 块内的数据要么全部写入成功,要不全部失败。

  • 唯一性:在写一个 Block 数据块的时候,会按照当前 Block 数据块的数据顺序、数据行和数据大小等指标,计算 Hash 信息摘要并记录在案。在此之后,如果某个待写入的 Block 数据块与先前被写入的 Block 数据块拥有相同的 Hash 摘要(Block 数据块内数据顺序、数据大小和数据行均相同),则该 Block 数据块会被忽略,这项设计可以预防由异常原因引起的 Block 数据块重复写入问题。

ZK 的配置

之前配置之前章节我们已经配置过了 ZK,配置好了集群模式。这里简单提一下,如果你没有做好,你需要回去之前的章节完成。


<yandex>  <zookeeper-servers>    <node index="1">      <host>h121.wzk.icu</host>      <port>2181</port>    </node>    <node index="2">      <host>h122.wzk.icu</host>      <port>2181</port>    </node>    <node index="3">      <host>h123.wzk.icu</host>      <port>2181</port>    </node>  </zookeeper-servers></yandex>
复制代码

开启 ZK

但是我们没有开启 ZK,我们需要在配置文件中开启:


vim /etc/clickhouse-server/config.xml
# 在之前配置的地方,再加入一行<include_from>/etc/clickhouse-server/config.d/metrika.xml</include_from># 之前没有下面的一行<zookeeper incl="zookeeper-servers" optional="true" />
复制代码


配置结果如下图所示:


重启服务

systemctl restart clickhouse-server
复制代码

检验结果

# 连接到ClickHouseclickhouse-client -m --host h121.wzk.icu --port 9001 --user default --password clickhouse@wzk.icu
复制代码


接着执行 SQL 检查是否成功链接到了 ZooKeeper


SELECT * FROM system.zookeeper WHERE path = '/';
复制代码


执行结果如下图,如果你也是这样的没有报错,说明配置 ZooKeeper 服务成功!


集群配置

如果有需要,记得将其他的节点都按照如上配置方式配置完毕。

副本定义形式

创建新表

CREATE TABLE replicated_sales_5(  `id` String,  `price` Float64,  `create_time` DateTime) ENGINE = ReplicatedMergeTree('/clickhouse/tables/01/replicated_sales_5', 'h121.wzk.icu')PARTITION BY toYYYYMM(create_time)ORDER BY id;
复制代码


  • /clickhouse/tables 约定俗成的路径

  • /01/ 分片编号

  • replicated_sales_5 数据表的名字 建议与物理表名字相同

  • h121.wzk.icu 在 ZK 中创建副本的名称,约定俗成是服务器的名称


执行结果如下图所示:


查询结果

可以检查刚才的操作结果:


select * from system.zookeeper where path = '/clickhouse';
复制代码


执行结果内容如下:


查看 ZK

进入到 ZK 中,对数据进行查看:


zkCli.sh
复制代码


执行结果如下图所示:


ReplicatedMergeTree 原理

数据结构

[zk: localhost:2181(CONNECTED) 7] ls /clickhouse/tables/01/replicated_sales_5[alter_partition_version, block_numbers, blocks, columns, leader_election, log, metadata, mutations, nonincrement_block_numbers, part_moves_shard, pinned_part_uuids, quorum, replicas, table_shared_id, temp, zero_copy_hdfs, zero_copy_s3][zk: localhost:2181(CONNECTED) 8] 
复制代码


元数据:


  • metadata:元数信息 主键、采样表达式、分区键

  • columns:列的字段的数据类型、字段名

  • replicats:副本的名称


标志:


  • leader_eletion:主副本的选举路径

  • blocks:hash 值(复制数据重复插入)、partition_id

  • max_insert_block_size: 1048576 行

  • block_numbers:在同一分区下 block 的顺序

  • quorum:副本的数据量


操作类:


  • log:log-000000 常规操作

  • mutations:delete update

创建新表 1

在当前机器上建立新表:


CREATE TABLE a1(  id String,  price Float64,  create_time DateTime) ENGINE = ReplicatedMergeTree('/clickhouse/tables/01/a1', 'h121.wzk.icu')PARTITION BY toYYYYMM(create_time)ORDER BY id;
复制代码


  • 根据 zk_path 初始化所有的 zk 节点

  • 在 replicas 节点下注册自己的副本实例 h121.wzk.icu

  • 启动监听任务 监听 LOG 日志节点

  • 参与副本选举,选出主副本,选举的方式是向 leader_election 插入子节点,第一个插入成功的副本就是主副本


执行结果如下图所示:


创建新表 2

创建第二个副本实例(注意,当前我们需要连接到 h122 节点上):


clickhouse-client -m --host h122.wzk.icu --port 9001 --user default --password clickhouse@wzk.icu
复制代码


执行对应的 SQL:


CREATE TABLE a1(  id String,  price Float64,  create_time DateTime) ENGINE = ReplicatedMergeTree('/clickhouse/tables/01/a1', 'h122.wzk.icu')PARTITION BY toYYYYMM(create_time)ORDER BY id;
复制代码


执行的结果如下图所示:



此时参与副本选举,h121.wzk.icu 副本成为了主副本。

插入数据 1

目前我们在 h121.wzk.icu 插入数据:


insert into table a1 values('A001',100,'2024-08-20 08:00:00');
复制代码


执行上述内容结果为:


查看结果

执行完后,我们在 ZK 上查看数据:


ls /clickhouse/tables/01/a1/blocks
复制代码


输出了如下的内容,插入命令执行后,在本地完成分区的目录的写入,接着向 Block 写入该分区的 block_id:


[zk: localhost:2181(CONNECTED) 6] ls /clickhouse/tables/01/a1/blocks[202408_16261221490105862188_1058020630609096934][zk: localhost:2181(CONNECTED) 7] 
复制代码

查看日志

接下来,h121.wzk.icu 副本发起向 log 日志推送操作日志:


[zk: localhost:2181(CONNECTED) 7] ls /clickhouse/tables/01/a1/log[log-0000000000][zk: localhost:2181(CONNECTED) 8] 
复制代码


再次插入一条数据:


insert into table a1 values('A002',200,'2024-08-21 08:00:00');
复制代码


查看 LOG 日志:


ls /clickhouse/tables/01/a1/logget /clickhouse/tables/01/a1/log/log-0000000000get /clickhouse/tables/01/a1/log/log-0000000001
复制代码


输出内容如下:


[zk: localhost:2181(CONNECTED) 14] ls /clickhouse/tables/01/a1/log[log-0000000000, log-0000000001]
[zk: localhost:2181(CONNECTED) 13] get /clickhouse/tables/01/a1/log/log-0000000000format version: 4create_time: 2024-08-01 17:10:35source replica: h121.wzk.icublock_id: 202408_16261221490105862188_1058020630609096934get202408_0_0_0part_type: Compact
[zk: localhost:2181(CONNECTED) 16] get /clickhouse/tables/01/a1/log/log-0000000001format version: 4create_time: 2024-08-01 17:16:37source replica: h121.wzk.icublock_id: 202408_3260633639629896920_11326802927295833243get202408_1_1_0part_type: Compact
复制代码

拉取日志

接下来,第二个副本拉取 Log 日志:h122.wzk.icu 节点会一直监听 /log 节点的变化,当 h121.wzk.icu 推送了/log/log-000000、0000001 之后,h122.wzk.icu 节点便会触发日志的拉取任务,并更新 log_pointer。


执行结果如下图所示:


错误速查

其他系列

🚀 AI 篇持续更新中(长期更新)

AI 炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究,持续打造实用 AI 工具指南!AI-调查研究-108-具身智能 机器人模型训练全流程详解:从预训练到强化学习与人类反馈🔗 AI模块直达链接

💻 Java 篇持续更新中(长期更新)

Java-154 深入浅出 MongoDB 用 Java 访问 MongoDB 数据库 从环境搭建到 CRUD 完整示例 MyBatis 已完结,Spring 已完结,Nginx 已完结,Tomcat 已完结,分布式服务正在更新!深入浅出助你打牢基础!🔗 Java模块直达链接

📊 大数据板块已完成多项干货更新(300 篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT 案例 详解🔗 大数据模块直达链接

发布于: 刚刚阅读数: 4
用户头像

武子康

关注

永远好奇 无限进步 2019-04-14 加入

Hi, I'm Zikang,好奇心驱动的探索者 | INTJ / INFJ 我热爱探索一切值得深究的事物。对技术、成长、效率、认知、人生有着持续的好奇心和行动力。 坚信「飞轮效应」,相信每一次微小的积累,终将带来深远的改变。

评论

发布
暂无评论
大数据-141 ClickHouse 副本实战 | ReplicatedMergeTree + ZooKeeper 从 0–1:创建、选举、日志复制、排障_大数据_武子康_InfoQ写作社区