
作者简介
马听,多年 DBA 实战经验,对 MySQL、 Redis、ClickHouse 等数据库有一定了解,专栏《一线数据库工程师带你深入理解 MySQL》、《Redis 运维实战》作者。
上一节内容,我们聊了 ClickHouse 两分片两副本的搭建(点击传送),那么多分片多副本的情况下,是不是一定得起至少 4 个实例呢?其实是不一定的,如果机器资源紧张,3 台机器甚至 2 台机器都可以搭建一个 ClickHouse 多分片多副本的集群(暂时只聊 1 台机器跑一个 CH 实例的场景),这一节内容就来聊聊 3 台机器搭建的集群。
对于一个由 3 台服务器搭建的 ClickHouse 环形架构,其大致情况就是第一个分片在第一和第二节点上,第二个分片在第二和第三节点上,第三个分片在第三和第一节点上。
架构图如下:

那么同一个节点放两个分片的数据,岂不是会有数据冲突的情况?
如果只使用单个库,那确实会出现数据冲突的情况,好在 ClickHouse 支持每个分片定义一个默认库,在配置文件中对应 default_database,从而使得两个不同的分片在同一节点上,实际是在两个不同的库中。
操作系统:CentOS 7.4
ClickHouse:20.4.6.53
Zookeeper:3.6.2
由于 ReplicatedMergeTree 引擎依赖 zk,有数据写入或者修改时,就借助 zk 的分布式协同能力,实现多个副本之间的同步。因此需要安装 zk。
生产环境建议配置 zk 集群,这一节内容就偷懒只用单节点讲解啦。
ZooKeeper 安装参考:https://zookeeper.apache.org/doc/r3.4.14/zookeeperStarted.html
ClickHouse 单机版安装参考:https://clickhouse.tech/docs/zh/getting-started/install/
编辑配置文件
vim /etc/clickhouse-server/config.xml去掉下面这行的注释
<listen_host>::</listen_host>编辑 hosts 文件,增加如下内容:
192.168.150.232 node1
192.168.150.253 node2
192.168.150.123 node3编辑集群配置文件:
vim /etc/clickhouse-server/config.d/metrika.xml加入如下内容:
<?xml version="1.0"?>
<yandex>
<zookeeper-servers>
<node index="1">
<host>node1</host>
<port>2181</port>
</node>
</zookeeper-servers>
<clickhouse_remote_servers>
<cluster_lzq>
<!-- 数据分片1 -->
<shard>
<internal_replication>true</internal_replication>
<replica>
<default_database>testcluster_shard_1</default_database>
<host>node1</host>
<port>9000</port>
</replica>
<replica>
<default_database>testcluster_shard_1</default_database>
<host>node2</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<default_database>testcluster_shard_2</default_database>
<host>node2</host>
<port>9000</port>
</replica>
<replica>
<default_database>testcluster_shard_2</default_database>
<host>node3</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<default_database>testcluster_shard_3</default_database>
<host>node3</host>
<port>9000</port>
</replica>
<replica>
<default_database>testcluster_shard_3</default_database>
<host>node1</host>
<port>9000</port>
</replica>
</shard>
</cluster_lzq>
</clickhouse_remote_servers>
<macros>
<cluster>cluster_lzq</cluster>
<shard>testcluster_shard_1</shard>
<replica>replica_1</replica>
</macros>
</yandex>注意把 zk 以及各个节点的信息修改成自己环境的。
修改主配置文件
vim /etc/clickhouse-server/config.xml引入上面新增的集群配置和 ZK 的配置。
<include_from>/etc/clickhouse-server/config.d/metrika.xml</include_from>
<zookeeper incl="zookeeper-servers" optional="false" />/etc/init.d/clickhouse-server startselect * from system.clusters;
首先创建复制表。
第一个节点:
CREATE DATABASE testcluster_shard_1;
CREATE TABLE testcluster_shard_1.tc_shard (label_id UInt32,label_name String,insert_time Date)Engine=ReplicatedMergeTree('/clickhouse/tables/testcluster_shard_1/tc_shard','replica_1',insert_time, (label_id, insert_time), 8192);
CREATE DATABASE testcluster_shard_3;
CREATE TABLE testcluster_shard_3.tc_shard (label_id UInt32,label_name String,insert_time Date)Engine=ReplicatedMergeTree('/clickhouse/tables/testcluster_shard_3/tc_shard','replica_2',insert_time, (label_id, insert_time), 8192);第二个节点:
CREATE DATABASE testcluster_shard_2;
CREATE TABLE testcluster_shard_2.tc_shard (label_id UInt32,label_name String,insert_time Date)Engine=ReplicatedMergeTree('/clickhouse/tables/testcluster_shard_2/tc_shard','replica_1',insert_time, (label_id, insert_time), 8192);
CREATE DATABASE testcluster_shard_1;
CREATE TABLE testcluster_shard_1.tc_shard (label_id UInt32,label_name String,insert_time Date)Engine=ReplicatedMergeTree('/clickhouse/tables/testcluster_shard_1/tc_shard','replica_2',insert_time, (label_id, insert_time), 8192);第三节点:
CREATE DATABASE testcluster_shard_3;
CREATE TABLE testcluster_shard_3.tc_shard (label_id UInt32,label_name String,insert_time Date)Engine=ReplicatedMergeTree('/clickhouse/tables/testcluster_shard_3/tc_shard','replica_1',insert_time, (label_id, insert_time), 8192);
CREATE DATABASE testcluster_shard_2;
CREATE TABLE testcluster_shard_2.tc_shard (label_id UInt32,label_name String,insert_time Date)Engine=ReplicatedMergeTree('/clickhouse/tables/testcluster_shard_2/tc_shard','replica_2',insert_time, (label_id, insert_time), 8192);其中:
在所有节点创建分布式总表(在不同节点,注意修改成对应的库名):
CREATE TABLE testcluster_shard_1.tc_shard_all as testcluster_shard_1.tc_shard ENGINE = Distributed('cluster_lzq', '', tc_shard, rand() )分布式总表建表语法可以参考上一节的解释:ClickHouse 实战笔记 第04期:ClickHouse 高可用集群搭建。
任选一个节点写入数据
insert into testcluster_shard_1.tc_shard_all (label_id ,label_name) values (1,'111');
insert into testcluster_shard_1.tc_shard_all (label_id ,label_name,insert_time) values (1,'111','2020-11-17');
insert into testcluster_shard_1.tc_shard_all (label_id ,label_name,insert_time) values (1,'111','2020-11-18');
insert into testcluster_shard_1.tc_shard_all (label_id ,label_name,insert_time) values (1,'111','2020-11-19');在任意一台机器执行数据读取 SQL:
select * from tc_shard_all;
在第 3 个节点中,执行下面两条 SQL:
select * from testcluster_shard_2.tc_shard;
select * from testcluster_shard_3.tc_shard;
说明有一部分数据是在第 3 个节点上的。
现在把第三个节点关闭:
/etc/init.d/clickhouse-server stop然后在第一个节点执行:
select * from testcluster_shard_1.tc_shard_all;
集群仍然可以使用。
说明环形复制集群架构下,挂一个节点,集群可以继续使用。
7 参考资料
https://altinity.com/blog/2018/5/10/circular-replication-cluster-topology-in-clickhouse
专栏《ClickHouse 实战笔记》系列文章推荐
第02期:ClickTail+CH 实现 MySQL 慢查询实时展示