clickhouse 通常有两种比较常用的数据复制方案来做数据的备份
1.基于cluster+Distributed的复制方案
2.基于Zookeeper+ReplicatedMergeTree的复制方案
下面详细介绍一下两种复制方案的配置、原理及优缺点,数据库架构基于下图
从数据层面上来区分,1A 和 2A数据完全不同,1A和2A互为分片;1A和1B数据完全相同,1A和1B互为副本;
副本的目的是防止数据丢失增加数据安全;分片的目的是实现数据水平切分,加速查询。
1.基于cluster+Distributed的复制方案
--物理表DDL建表语句
create table if not exists eos_appstatistics.tb_mytest on cluster eos_ck_cluster
(
id String,
code String
)
engine = MergeTree ORDER BY id
SETTINGS index_granularity = 8192;
--分布式表DDL建表语句
create table eos_appstatistics.tb_mytest_dist on cluster eos_ck_cluster
(
id String,
code String
)
engine = Distributed('eos_ck_cluster', 'eos_appstatistics', 'tb_mytest', rand());
集群配置文件如下
<!-- 集群配置 -->
<clickhouse_remote_servers>
<eos_ck_cluster>
<!-- 数据分片1 -->
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>server01</host>
<port>9000</port>
<user>default</user>
<password></password>
</replica>
<replica>
<host>server02</host>
<port>9000</port>
<user>default</user>
<password></password>
</replica>
</shard>
<!-- 数据分片2 -->
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>server03</host>
<port>9000</port>
<user>default</user>
<password></password>
</replica>
<replica>
<host>server04</host>
<port>9000</port>
<user>default</user>
<password></password>
</replica>
</shard>
</eos_ck_cluster>
</clickhouse_remote_servers>
要注意<internal_replication>true</internal_replication>这个配置
经测试,想要基于分布式表进行数据复制,<internal_replication>必须设置为false;
在对分布式表进行写入的时候,会自动写入分布式表对应的两张子表中。
这样的数据复制方式被官方称为poor man's replication,需要自行处理存量数据、数据迁移等工作,官方不太建议使用。
2.基于Zookeeper+ReplicatedMergeTree的复制方案
集群配置文件中增加zookeeper的配置
<!-- ZK -->
<zookeeper-servers>
<node index="1">
<host>10.**.**.**</host>
<port>2181</port>
</node>
<node index="2">
<host>10.**.**.**</host>
<port>2182</port>
</node>
<node index="3">
<host>10.**.**.**</host>
<port>2183</port>
</node>
</zookeeper-servers>
建表语句
--物理表DDL建表语句
create table eos_appstatistics.tb_test on cluster eos_ck_cluster
(
id String,
code String
)
--{shard}同一分片下相同,{replica}必须保证唯一
engine = ReplicatedMergeTree('/clickhouse/tables/{shard}/eos_appstatistics/tb_test', '{replica}')
ORDER BY id
SETTINGS index_granularity = 8192;
--分布式表DDL建表语句
create table eos_appstatistics.tb_test_dist on cluster eos_ck_cluster
(
id String,
code String
)
engine = Distributed('eos_ck_cluster', 'eos_appstatistics', 'tb_test', rand());
ReplicatedMergeTree为复制表引擎
ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/table_name', '{replica}')
此句为官方给的例子,括号中的参数为zk的路径
{layer}指代的是第几层,同一层数据一样,可忽略不用
{shard}指的是分片编号,同一层的同一分片,数据互相复制
table_name 推荐和物理表名一致,方便分辨
{replica}指的是副本名称,必须保证在同一分片下唯一
其它要注意的配置
<!--此处必须设置为true-->
<internal_replication>true</internal_replication>
<!--集群配置中节点的用户必须有相应的权限,在user.xml配置文件中-->
<access_management>1</access_management>
<!--clickhouse docker启动时指定的hostname要与 集群配置文件中的host一致-->
此时可以直接往物理表插入数据,其副本会自动同步数据;
也可以直接往分布式表插入数据,即只写一个shard里面的一个副本,副本之间会自动同步数据。
该方案使用的是基于复制表ReplicatedMergeTree+Zookeeper的协调一致性完成数据的复制和数据一致性,副本之间的数据相互复制且会进行数据验证,自动保证数据一致性,这样的方案强依赖zookeeper,由于对zk的使用经验较少,先在测试环境观察一段时间可靠性。
3.总结
基于ClickHouse的集群的常见方案,结合业界的架构方案,优质的选择是基于ReplicatedMergeTree + Distributed的集群架构方案,也是分布式高可用的集群架构方案,在使用该集群架构的过程中,需要注意:
写表的方式:写本地表,读分布式表
由于分布式表的逻辑简单,仅仅是转发请求,所以在转发安全性上,会有风险,并且rand的方式,可能会造成不均衡,业界建议,通过LB轮询,写本地表,这样最保险和均衡。
此处我采用的是在clickhouse集群外加了一层nginx做负载均衡,写本地表,读分布式表(各个节点都创建分布式表)