作者:吳帆 青云數(shù)據(jù)庫團(tuán)隊成員
主要負(fù)責(zé)維護(hù) MySQL 及 ClickHouse 產(chǎn)品開發(fā)哎垦,擅長故障分析囱嫩,性能優(yōu)化。
在多副本分布式 ClickHouse 集群中漏设,通常需要使用 Distributed 表寫入或讀取數(shù)據(jù)墨闲,Distributed 表引擎自身不存儲任何數(shù)據(jù),它能夠作為分布式表的一層透明代理愿题,在集群內(nèi)部自動開展數(shù)據(jù)的寫入损俭、分發(fā)、查詢潘酗、路由等工作。
Distributed 表實現(xiàn)副本數(shù)據(jù)同步有兩種方案:
- Distributed + MergeTree
- Distributed + ReplicateMergeTree
| Distributed + MergeTree
在使用這種方案時 internal_replication 需要設(shè)為 false雁仲,向 Distributed 表寫入數(shù)據(jù)仔夺,Distributed 表會將數(shù)據(jù)寫入集群內(nèi)的每個副本。Distributed 節(jié)點需要負(fù)責(zé)所有分片和副本的數(shù)據(jù)寫入工作攒砖。
1. 集群配置
<logical_consistency_cluster>
<shard>
<internal_replication>false</internal_replication>
<replica>
<host>shard1-repl1</host>
<port>9000</port>
</replica>
<replica>
<host>shard1-repl2</host>
<port>9000</port>
</replica>
</shard>
</logical_consistency_cluster>
2. 數(shù)據(jù)寫入
CREATE TABLE test.t_local on cluster logical_consistency_cluster
(
EventDate DateTime,
CounterID UInt32,
UserID UInt32
) ENGINE MergeTree() PARTITION BY toYYYYMM(EventDate) ORDER BY (CounterID, EventDate) ;
CREATE TABLE test.t_logical_Distributed on cluster logical_consistency_cluster
(
EventDate DateTime,
CounterID UInt32,
UserID UInt32
)
ENGINE = Distributed(logical_consistency_cluster, test, t_local, CounterID) ;
INSERT INTO test.t_logical_Distributed VALUES ('2019-01-16 00:00:00', 1, 1),('2019-02-10 00:00:00',2, 2),('2019-03-10 00:00:00',3, 3)
3. 數(shù)據(jù)查詢
# shard1-repl1
SELECT *
FROM test.t_local
Query id: bd031554-b1e0-4fda-9ff8-1145ffae5b02
┌───────────EventDate──┬─CounterID─┬─UserID─┐
│ 2019-03-10 00:00:00 │ 3 │ 3 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-02-10 00:00:00 │ 2 │ 2 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-01-16 00:00:00 │ 1 │ 1 │
└─────────────────────┴───────────┴────────┘
3 rows in set. Elapsed: 0.004 sec.
------------------------------------------
# shard1-repl2
SELECT *
FROM test.t_local
Query id: 636f7580-02e0-4279-bc9b-1f153c0473dc
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-01-16 00:00:00 │ 1 │ 1 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-03-10 00:00:00 │ 3 │ 3 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-02-10 00:00:00 │ 2 │ 2 │
└─────────────────────┴───────────┴────────┘
3 rows in set. Elapsed: 0.005 sec.
通過寫入測試我們可以看到每個副本數(shù)據(jù)是一致的缸兔。
即使本地表不使用 ReplicatedMergeTree 表引擎,也能實現(xiàn)數(shù)據(jù)副本的功能吹艇。但每個副本的數(shù)據(jù)是通過 Distributed 表獨立寫入惰蜜,文件存儲格式不會完全一致,可以理解這種方式為邏輯一致性受神。
Distributed 需要同時負(fù)責(zé)分片和副本的數(shù)據(jù)寫入工作抛猖,單點寫入很有可能會成為系統(tǒng)性能的瓶頸,所有有接下來的第二種方案鼻听。
| Distributed + ReplicateMergeTree
在使用這種方案時 internal_replication 需要設(shè)為 true财著,向 Distributed 表寫入數(shù)據(jù)。Distributed 表在每個分片中選擇一個合適的副本并對其寫入數(shù)據(jù)撑碴。
分片內(nèi)多個副本之間的數(shù)據(jù)復(fù)制會由 ReplicatedMergeTree 自己處理撑教,不再由 Distributed 負(fù)責(zé)。
1. 配置文件
<physical_consistency_cluster>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>shard1-repl1</host>
<port>9000</port>
</replica>
<replica>
<host>shard1-repl2</host>
<port>9000</port>
</replica>
</shard>
</physical_consistency_cluster>
2. 數(shù)據(jù)寫入
CREATE TABLE test.t_local on cluster physical_consistency_cluster
(
EventDate DateTime,
CounterID UInt32,
UserID UInt32
)
ENGINE = ReplicatedMergeTree('{namespace}/test/t_local', '{replica}')
PARTITION BY toYYYYMM(EventDate)
ORDER BY (CounterID, EventDate, intHash32(UserID))
SAMPLE BY intHash32(UserID);
CREATE TABLE test.t_physical_Distributed on cluster physical_consistency_cluster
(
EventDate DateTime,
CounterID UInt32,
UserID UInt32
)
ENGINE = Distributed(physical_consistency_cluster, test, t_local, CounterID);
INSERT INTO test.t_physical_Distributed VALUES ('2019-01-16 00:00:00', 1, 1),('2019-02-10 00:00:00',2, 2),('2019-03-10 00:00:00',3, 3)
3. 數(shù)據(jù)查詢
# shard1-repl1
SELECT *
FROM test.t_local
Query id: d2bafd2d-d0a8-41b4-8d79-ece37e8159e5
┌───────────EventDate──┬─CounterID─┬─UserID─┐
│ 2019-03-10 00:00:00 │ 3 │ 3 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-02-10 00:00:00 │ 2 │ 2 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-01-16 00:00:00 │ 1 │ 1 │
└─────────────────────┴───────────┴────────┘
3 rows in set. Elapsed: 0.004 sec.
------------------------------------------
# shard1-repl2
SELECT *
FROM test.t_local
Query id: b5f0dc80-f73f-427e-b04e-e5b787876462
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-01-16 00:00:00 │ 1 │ 1 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-03-10 00:00:00 │ 3 │ 3 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-02-10 00:00:00 │ 2 │ 2 │
└─────────────────────┴───────────┴────────┘
3 rows in set. Elapsed: 0.005 sec.
ReplicatedMergeTree 需要依靠 ZooKeeper 的事件監(jiān)聽機(jī)制以實現(xiàn)各個副本之間的協(xié)同醉拓,副本協(xié)同的核心流程主要有:INSERT伟姐、MERGE收苏、MUTATION 和 ALTER 四種。
通過寫入測試我們可以看到每個副本數(shù)據(jù)也是一致的愤兵,副本之間依靠 ZooKeeper 同步元數(shù)據(jù)鹿霸,保證文件存儲格式完全一致,可以理解這種方式是物理一致恐似。
ReplicatedMergeTree 也是在分布式集群中最常用的一種方案杜跷,但數(shù)據(jù)同步需要依賴 ZooKeeper,在一些 DDL 比較頻繁的業(yè)務(wù)中 Zookeeper 往往會成為系統(tǒng)性能的瓶頸矫夷,甚至?xí)?dǎo)致服務(wù)不可用葛闷。
我們需要考慮為 ZooKeeper 減負(fù),使用第一種方案 + 負(fù)載均衡輪詢的方式可以降低單節(jié)點寫入的壓力双藕。
總結(jié)
- internal_replication = false
使用 Distributed + MergeTree 可實現(xiàn)邏輯一致分布式淑趾。
數(shù)據(jù)內(nèi)容完全一致,數(shù)據(jù)存儲格式不完全一致忧陪,數(shù)據(jù)同步不依賴 ZooKeeper扣泊,副本的數(shù)據(jù)可能會不一致,單點寫入壓力較大嘶摊。
- internal_replication = true
使用 Distributed + ReplicateMergeTree 可實現(xiàn)物理一致分布式延蟹。
數(shù)據(jù)內(nèi)容完全一致,數(shù)據(jù)存儲格式完全一致叶堆。數(shù)據(jù)同步需要依賴 ZooKeeper阱飘,ZooKeeper 會成為系統(tǒng)瓶頸。