三條服務器,每台服務器安裝兩個clickhouse實例
一、服務器規划
單機兩個clickhouse實例安裝,參考Clickhouse 單機雙實例
zookeeper集群安裝,參考: Zookeeper 集群搭建--單機偽分布式集群
我這里用的是三台服務器,分別為第一台sever1 118.xx.xx.101,第二台 server2 49.xx.xx.125, 第三台server3 110.xx.xx.67

二、配置
1、集群配置 config.xml
<remote_servers>
<perftest_3shards_2replicas>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>server1</host>
<port>9000</port>
<user>larrylin2</user>
<password>123456</password>
</replica>
<replica>
<host>server2</host>
<port>9001</port>
<user>larrylin2</user>
<password>123456</password>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>server2</host>
<port>9000</port>
<user>larrylin2</user>
<password>123456</password>
</replica>
<replica>
<host>server3</host>
<port>9001</port>
<user>larrylin2</user>
<password>123456</password>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>server3</host>
<port>9000</port>
<user>larrylin2</user>
<password>123456</password>
</replica>
<replica>
<host>server1</host>
<port>9001</port>
<user>larrylin2</user>
<password>123456</password>
</replica>
</shard>
</perftest_3shards_2replicas>
</remote_servers>
2、zk集群配置 config.xml
<zookeeper>
<node>
<host>server1</host>
<port>2181</port>
</node>
<node>
<host>server2</host>
<port>2181</port>
</node>
<node>
<host>server3</host>
<port>2181</port>
</node>
</zookeeper>
3、副本配置 config.xml
<macros>
<layer>01</layer>
<shard>01</shard>
<replica>01-01-1</replica>
</macros>
另外5個實例的副本配置分別為
<macros>
<layer>01</layer>
<shard>01</shard>
<replica>01-01-2</replica>
</macros>
<macros>
<layer>01</layer>
<shard>02</shard>
<replica>01-02-1</replica>
</macros>
<macros>
<layer>01</layer>
<shard>02</shard>
<replica>01-02-2</replica>
</macros>
<macros>
<layer>01</layer>
<shard>03</shard>
<replica>01-03-1</replica>
</macros>
<macros>
<layer>01</layer>
<shard>03</shard>
<replica>01-03-2</replica>
</macros>
4、用戶配置 users.xml
<users>
<larrylin2>
<password>123456</password>
<networks incl="networks" replace="replace">
<ip>0.0.0.0</ip>
</networks>
<profile>default</profile>
<quota>default</quota>
</larrylin2>
</users>
三、創建本地表
CREATE TABLE IF NOT EXISTS default.test_local ON CLUSTER 'perftest_3shards_2replicas' (
ts_date Date,
ts_date_time DateTime,
user_id Int64,
event_type String,
site_id Int64,
groupon_id Int64,
category_id Int64,
merchandise_id Int64,
search_text String
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/default/test_local','{replica}')
PARTITION BY ts_date
ORDER BY (ts_date,toStartOfHour(ts_date_time),site_id,event_type)
SETTINGS index_granularity = 8192;

ON CLUSTER 表示分布式DDL, 一次執行所有實例上創建同樣的本地表。
perftest_3shards_2replicas為集群名稱
{shard} 分片標識符
{replica} 副本標識符,來自config.xml 中的macros
ReplicatedMergeTree引擎接收兩個參數:
1、ZK中該表相關數據的存儲路徑,Clickhouse官方建議格式 /clickhouse/tables/{shard}/[database_name]/[table_name]
2、副本名稱,一般用{replica}
四、ZK路徑的znode結構和內容

metadata的value值
metadata format version: 1 date column: sampling expression: index granularity: 8192 mode: 0 sign column: primary key: ts_date, toStartOfHour(ts_date_time), site_id, event_type data format version: 1 partition key: ts_date granularity bytes: 10485760
colums的value值
columns format version: 1 9 columns: `ts_date` Date `ts_date_time` DateTime `user_id` Int64 `event_type` String `site_id` Int64 `groupon_id` Int64 `category_id` Int64 `merchandise_id` Int64 `search_text` String
ReplicatedMergeTree引擎在ZK中存儲了大量的數據,包括表結構信息,元數據、操作日志、副本狀態、數據塊校驗值、數據part merge過程中的選主信息等。
ZK在復制表機制下有元數據存儲、日志框架、分布式協調器服務三種角色,任務很重,所以要保證ZK集群的可用性以及資源(尤其是硬盤資源)。
五、創建分布式表
CREATE TABLE IF NOT EXISTS default.test_all ON CLUSTER 'perftest_3shards_2replicas' AS default.test_local ENGINE = Distributed(perftest_3shards_2replicas, default, test_local,rand());

Distributed引擎需要以下幾個參數
1) 集群標識符
2)本地表所在的數據庫名稱
3) 本地表名稱
4)分片鍵sharding key(可選)
該鍵與config.xml 中配置的分片權重(weight) 一同決定寫入分布式表時的路由。它可以時表中的一列原始數據(如site_id),也可以是函數調用的結果,如上面的SQL語句采用了隨機值rand()。 注意該鍵要盡量保證數據均勻分布,另外一個常用的操作是采用區分度較高的列的哈希值,如intHash64(user_id).
直接寫分布式表的優點自然是可以讓clickhouse控制數據到分片的路由,
缺點:
數據是先寫到一個分布式表的實例中緩存起來,再逐漸分發到各個分片上去,實際是雙寫了數據(寫入放大),浪費資源。
數據寫入默認是異步的,短時間內可能造成不一致。
目標表中會產生較多的小parts,使merge(即compaction)過程壓力增大。
相對而言,直接寫本地表是同步操作,更快,parts的大小也比較合適,但是要求應用層額外實現路由邏輯,如輪詢或者隨機等。
六、驗證
在第一台9000中增加數據
insert into test_local (ts_date, ts_date_time, user_id, event_type, site_id,
groupon_id, category_id, merchandise_id,
search_text)
values ('2021-11-11','2021-11-11 10:00:00',5,'stand',1,1,1,1,'world');
可以看到數據已經添加select * from test_local where user_id= 5; 
查詢分布式表

在另外一台查看本地表 select * from test_local where user_id= 5;

說明數據已經復制到副本了。
