clickhouse集群方案很多资料过于凌乱,也有一些还不错,但是其最佳实践部分讲的不够详细,例如:
那我们来讲讲我们的实践及面临过的问题。
数据一致性问题
某些云服务厂商提供的其实是单机版,比如某个集群单分片,两副本,但其实只开放一台机器的ip和端口,所有读写都在一台机器上,这样就没有数据一致性问题,但这不是正确的集群,这种单机使用中建表都不需要on cluster 'clickhouse_cluster' ,这样也不会有数据一致性问题,而在真正的集群(所有节点都对外提供读写的时候)中便会有这样的问题,也就是查询某张表的数据是变动的,有时多有时少,原因是请求发送到不同的服务器上,MergeTree引擎还好一些,replacingMergeTree问题就更大了,上面链接的文章给了个方案是读本地表建分布式表,但其实这只适合MergeTree引擎,所以我讲讲我们的方案:
集群的配置
这里说的是配置文件,也就是分片和副本的存储,这个文章比较多不再赘述。
建立数据库
建立数据库要create database on cluster '集群名字',这个很好理解
建本地表
CREATE TABLE table_name_local on cluster 'jiqunname' (
`id` Int64 COMMENT '主键',
`name` String COMMENT '名字',
`age` String COMMENT '年龄'
) engine = ReplicatedMergeTree(
'/jiqunname/tables/{shard}/default/table_name_local',
'{replica}'
) partition by age
primary key (age, id)
order by
(age, id) settings index_granularity = 8192;
CREATE TABLE table_name_local on cluster 'jiqunname' (
`id` Int64 COMMENT '主键',
`name` String COMMENT '名字',
`age` String COMMENT '年龄'
) engine = ReplicatedReplacingMergeTree(
'/jiqunname/tables/{shard}/default/table_name_local',
'{replica}'
) partition by age
primary key (age, id)
order by
(age, id) settings index_granularity = 8192;
本地表同样要和集群关联,注意引擎,这里只用了常见的两种,其他的其实也是Replicated*MergeTree以此类推,
建分布式表
CREATE TABLE table_name on cluster 'jiqun' as table_local ENGINE = Distributed(
'jiqun',
'mydatabase',
'table_local',
xxHash64(age)
);
注意分布式表引擎,他会将各个本地表的数据汇总起来,本质是一张视图,数据是存在本地表的。那个xxHash64函数式分片函数,如果写分布式表的话,数据会按照这个函数在分片之间分发。
读写方式
MergeTree
这个也就是其他文章说的写本地表,读分布式表,效率会比读写分布式表更高。分布式表的数据分片函数使用rand()也不会有问题。
ReplacingMergeTree
这个引擎写本地表会出现问题,因为我们查询分布式表的时候往往是需要加上final字段的,当需要merge的数据在不同的分片或者分区的时候,去重的效果会有问题,写本地表肯定不行,所以需要我们读写都在分布式表,这样才能保证需要merge的数据在相同的分片或者分区。当然还要注意分布式表的数据分片函数,不能使用rand(),按照某个order by字段hash才能达到上面所说的效果。