ClickHouse副本同步及分布式DDL的原理

相信了解大数据的小伙伴们都知道,基本上所有的分布式存储系统都有一个共同的特点,将庞大的数据量分成多个小块存储在不同的机器上,通常称为分片,每个分片为了保证它数据不丢失,它们又有各自副本。ClickHouse也不例外,一起来看看ClickHouse是怎么实现的

副本同步原理

副本同步的原理其实我们在前面的篇幅中我们已经提到过,现在再用一张手画图复习一下
在这里插入图片描述
简单来说它们的副本同步机制是通过Zookeeper的监听机制实现的,当我们向Node1发送写入操作请求,Node1会推送操作日志到zookeeper集群中,Node2通过监听发现Node1有新的数据写入,于是从zookeeper上下载操作日志,然后从Node1下载副本到本地。下面我们就动手实验一下,看看具体现象。

实操

创建副本实例

我们在server1下执行以下建表语句

CREATE TABLE user_order
(
    `id` UInt32,
    `uid` UInt32,
    `price` Float64,
    `create_time` DateTime
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/01/user_order', 'server1')
PARTITION BY toYYYYMM(create_time)
ORDER BY id

在server2下执行以下建表语句

CREATE TABLE user_order
(
    `id` UInt32,
    `uid` UInt32,
    `price` Float64,
    `create_time` DateTime
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/01/user_order', 'server2')
PARTITION BY toYYYYMM(create_time)
ORDER BY id

在这里插入图片描述
解释一下上面执行的建表语句的含义,首先字段名和类型这里就不赘述了大家都懂,这里介绍以下我们上面使用的表引擎是ReplicatedMergeTree,该引擎会自动同步副本,MergeTree的话是ClickHouse的一大特色,它会将具有相同特征的数据进行合并,极大提高查询效率。使用该引擎需要传入两个参数,第一个参数是元数据在zookeeper的存在路径,第二个参数节点的名称。
执行完建表语句后,我们向server1插入一条数据,看看server2是否会自动同步

副本同步验证

在server1节点上插入数据

insert into table user_order values(2,101,3800,'2020-08-07 14:33:28');

登录server2验证同步副本数据:
在这里插入图片描述
由图可见,server2已经正常同步了server1的数据。下面我们来看看具体同步的原理。

副本同步原理

当我们在server1执行插入语句,第一个副本实例会推送log日志到zookeeper指定目录下,我们可以到zk上查看具体的日志信息,使用我们上一章节提到的知识点,zk的内容可以直接在ClickHouse查询到

select * from system.zookeeper where path='/clickhouse/tables/01/user_order/log';

在这里插入图片描述
可以清晰的看到,我们操作的事件,源副本所在的节点,以及数据所在的文件名,都能准确的呈现。
那么此时server2就监听到了/clickhouse/tables/01/user_order/log该路径下发生变化,便会触发日志的拉取并更新/clickhouse/tables/01/user_order/replicas/server2/log_pointer该路径下指示的日志下标,可以看到这里日志的下标是2,因为我之前插入过一条数据了,所以更新为2
在这里插入图片描述

副本选择策略

这里存在一个问题,当副本可以从多个不用节点下载时,会如何选择,这里ClickHouse有一个选择算法:
(1)首先server2会从/clickhouse/tables/01/user_order/replicas获取所有副本节点
(2)遍历所有副本后,选择其中一个。选择的策略是,选取log_pointer下标最大且/queue子节点数量最少的副本。log_pointer越大,说明该副本执行的日志最多,数据最完整;/queue子节点最少,说明该副本最空闲。

在整个插入数据过程中,zookeeper不会进行任何实质性数据传输本着谁执行谁负责的原则,server1将数据写入本地分区之后,接着推送log日志,然后通知其他副本下载数据,其他副本接收到log日志后,会选择一个最合适的副本,实现点对点下载分区数据。server1接收到server2的调用请求后,server1会根据参数将本地分区202008_0_0_0发送给server2,server2写入本地磁盘

存在问题

其实我们上面使用的这种方式有点挫,因为我们是在每个节点上手动创建每个副本表,如果我有成百上千个节点,是绝对不可能使用这种方式的,下面就给大家介绍分布式DDL的实操

分布式DDL实操

我们之前在metrika.xml中定义的集群信息在这里就派上用场了。

前置条件

先来看看我们metrika.xml中的集群信息
在这里插入图片描述
我们定义了集群名为cluster_1shards_1replicas,其中一个分片下有两个副本,分别是server1和server2。
以及宏变量
server1的宏变量
在这里插入图片描述
server2的宏变量
在这里插入图片描述

执行分布式DDL语句

有了以上前置条件之后,我们可以执行分布式DDL语句了

CREATE TABLE my_order_local ON CLUSTER cluster_1shards_1replicas(id UInt32,uid UInt32,price Float64,create_time DateTime) engine = ReplicatedMergeTree('/clickhouse/tables/{shard}/my_order','{replica}') PARTITION BY toYYYYMM(create_time) ORDER BY id;

在这里插入图片描述
这样我们的分布式DDL操作的执行完成了

原理

推送DDL日志

分布式DDL的原理其实和副本同步是类似的,**当我们在server1执行分布式DDL语句时,本着谁执行谁负责的原则,server1节点负责创建日志并将日志推送到zookeeper,同时也由serve1节点负责监控任务的执行进度。**推送的日志对应zookeeper的以下路径:
在这里插入图片描述

拉取日志并执行

看一下操作日志中都有什么内容,zk路径

get /clickhouse/task_queue/ddl/query-0000000001

在这里插入图片描述
可以看到这个日志中的信息包含版本号,执行的语句以及需要执行该语句的hosts列表。其它节点监听到此操作日志后,后判断自己是否在该hosts列表内,如果包含,则进入执行流程,执行完毕后写入
/clickhouse/task_queue/ddl/query-0000000001/finished
在这里插入图片描述
从上图我们可以看见finished下存在server1和server2,说明它们都已经执行完成了。

确认执行进度

在第一步客户端执行DDL语句之后,客户端会阻塞等待180秒,以期望所有节点都执行DDL完毕。如果等待事件大于180秒,则会转入后台线程继续等待。

这样我们的分布式表就创建成功了,是不是很简单。

今天ClickHouse副本同步及分布式DDL的原理和实操就到这里啦,下一篇讲给大家介绍分片的原理以及实操

微信公众号:喜讯Xicent

image

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值