什麼是邏輯叢集
ClickHouse
作為一個基於OLAP
場景的資料庫,對於叢集的支援自然也是理所當然的。我們通常所說的ClickHouse
叢集,指的是物理叢集。即叢集各節點之間被同一個zookeeper
叢集管理,資料的各種DDL
操作都是針對整個叢集有效的。
與物理叢集相對應的,還有一類叢集,我們叫它邏輯叢集。它是指在物理上沒有一定的必然關係的物理叢集,彼此又組成了一個邏輯叢集。可以用下面這幅圖形象地表達物理叢集和邏輯叢集的關係。
如上圖所示,三個物理叢集各自是相互獨立的,對cluster1
的各種資料操作,cluster2
和cluster3
並無法感知,但是對於logic
叢集來說,任何一個物理叢集的資料變化,邏輯叢集都能通過查詢獲取到。
為什麼需要邏輯叢集
那麼,既然有了物理叢集,為什麼還要邏輯叢集呢?它能解決使用者什麼痛點?又能帶來哪些好處?
首先,邏輯叢集能解決zookeeper壓力問題
我們知道,ClickHouse
叢集的資料一致性是通過Zookeeper
叢集來保證的。當叢集的資料量特別大或者操作特別頻繁的時候,帶來的就是zookeeper
的znode
節點數量多,更新頻繁。而zookeeper
的壓力是有上限的,如果叢集過大,或者一個zookeeper
叢集管理的clickhouse
叢集過多的話,很容易造成zookeeper
崩潰或者卡死。
正是因為“天下苦zookeeper
久矣”,邏輯叢集的出現正好能解決這一問題。
比如,某個物理叢集的資料量特別龐大, 龐大到單一的zookeeper
叢集無法支撐其後設資料管理,這時候我們可以將這個物理叢集拆分成多個物理叢集,分別使用不同的zookeeper
叢集去管理,然後通過邏輯叢集去查詢資料。這樣既分擔了zookeeper
的壓力,也保留了各個物理叢集之間的業務關聯性,不影響業務資料的查詢。
其次,邏輯叢集解決了多資料中心問題
還有一種比較常見的場景是多資料中心。隨著企業資料規模的擴張,不可能把所有的資料都存放在一個資料中心,面對這樣的多資料中心的場景,如果只建立一個物理叢集,那麼首先面臨的是網路的延遲問題,其次還有高昂的流量費用,這都是需要考慮的問題。
那麼比較好的做法是在每一個資料中心都分別建立各自的物理叢集,這樣無論是資料的插入還是查詢,都極大減少了網路上的限制,從而把延遲做到最小。
但是我們考慮這樣一個場景:某銀行機構在上海和合肥各有一個資料中心,分別建立了兩個物理叢集,叫做bench_shanghai
和bench_hefei
, 現在總行機構需要綜合上海和合肥的兩個資料中心的資料做資料分析。那麼我們還必須分別查詢上海的叢集和合肥的叢集,然後再進行彙總。如果資料中心比較多,那麼查詢的次數也就特別多,這樣顯然是事倍功半的。
如果我們建立一個邏輯叢集,將上海的叢集和合肥的叢集包含在內,我們就叫它bench
叢集,這樣我們只需要查詢bench
叢集,就能一次將資料全部查出來,如下圖所示:
再次,邏輯叢集能節約成本
邏輯叢集節約成本是肯定的。當然主要是網路流量方面的成本。尤其是雲上的伺服器,流量貴得驚人。設想一下,如果上海和合肥兩個資料中心只有一個物理叢集,而恰好一個shard
中的不同副本又分別位於不同的資料中心,當每天數TB
級別的資料寫入資料庫,在做副本之間資料同步的時候,產生的流量當有多麼可怕。
邏輯叢集能做什麼
我們不建議在邏輯叢集進行mutation
的相關操作。不建議對資料進行插入、刪除等。這些操作都應該在物理叢集去完成。
事實上,邏輯叢集天生也不擅長做上面這些操作。這主要取決於以下這幾層限制:
- 邏輯叢集可能包含多個物理叢集,這些物理叢集不一定在同一個
zookeeper
上,因此,不論是建表還是插入資料,一致性是一定不能保證的。 - 即使邏輯叢集的多個物理叢集使用同一個
zookeeper
,仍然無法建立邏輯叢集層面上的分散式表。因為有可能物理叢集A使用了副本,建立的本地表引擎是ReplicatedMergeTree
, 但是物理叢集B沒有使用副本,建立的本地表是MergeTree
,這樣即使本地表結構一模一樣,也無法在邏輯叢集上建立分散式表。 - 再退一步,就算物理叢集
A
和B
都使用了副本,建表的schema
一模一樣,使用的都是ReplicatedMergeTree
引擎,在邏輯叢集上建立分散式表仍然不可避免問題。因為為了防止叢集之間相互干擾,我們一般定義zookeeper
的路徑時,都會帶上叢集的名字,比如下面這樣:
CREATE TABLE default.t1
(
`@time` DateTime,
`@item_guid` String,
`@metric_name` LowCardinality(String),
`@alg_name` LowCardinality(String)
)
ENGINE = ReplicatedReplacingMergeTree('/clickhouse/tables/{cluster}/{shard}/default/t1', '{replica}')
PARTITION BY toYYYYMMDD(`@time`)
ORDER BY (`@time`, `@item_guid`, `@metric_name`)
SETTINGS index_granularity = 8192
因此不同的物理叢集在zookeeper
的路徑其實是不同的,而分散式表之所以能夠使用ON CLUSTER xxx
這種語法建立,主要就是因為在zookeeper
的task queue
中儲存了DDL
語句,而不同的叢集task queue
的路徑不同,就無法做到同步。因此建立分散式表也會失敗。
因此,邏輯叢集存在的意義主要是用來查詢。這也是它唯一能做的事情。
那麼,既然邏輯叢集在建立分散式表上有這麼多的限制(幾乎就是不可能建立成功),為什麼我們還能使用邏輯叢集進行查詢呢?這不是自相矛盾的麼?
事實上,我們可以在物理叢集上分別建立跨邏輯叢集的分散式表,只要表的schema
一樣,是可以實現查詢的。如下面這樣的寫法:
--上海叢集建立:
CREATE TABLE default.dist_logic_t123 on cluster bench_shanghai as t123 ENGINE = Distributed('bench', 'default', 't123', rand());
--合肥叢集建立
CREATE TABLE default.dist_logic_t123 on cluster bench_hefei as t123 ENGINE = Distributed('bench', 'default', 't123', rand());
這樣不論是往上海叢集還是合肥叢集插入資料,我們都能從dist_logic_t123
表中查詢出來。
如何建立一個邏輯叢集
建立邏輯叢集的方式和普通的物理叢集類似,只需要在metrika.xml
配置檔案中加入邏輯叢集的相關資訊即可。如下所示:
上海叢集metrika.xml
配置檔案:
合肥叢集metrika.xml
配置檔案:
建立邏輯叢集不復雜,複雜的是對邏輯叢集的後續運維。
假設我們現在要增加一個成都的資料中心,需要建立一個成都物理叢集,並將成都物理叢集增加到bench邏輯叢集中去,那麼還要同步修改上海和合肥叢集所有節點的配置檔案。
與之類似的操作還有增加節點、刪除節點、銷燬叢集等,有可能是某一個物理叢集的微小改動,就要連帶著所有邏輯叢集的配置檔案的重新整理,真可謂“牽一髮而動全身”。
這也是沒有辦法的事,世上沒有十全十美的事情。既然想要使用邏輯叢集帶來的便利,就得接受繁瑣的配置工作。
ckman對邏輯叢集的支援
ckman
是擎創科技自主研發的一款用來管理和監控clickhouse
叢集的運維工具。它的全稱是"ClickHouse Manager Console
",它通過直觀的視覺化介面,可以非常方便地對叢集進行建立、啟停、升級,以及增刪節點等操作,運維人員無需關注clickhouse
配置檔案變化的細節,一切都由ckman
主動完成。同時它還提供了資料表、會話以及節點級別的監控,可以直觀的觀察到叢集的使用情況。
在最新發布的ckman2.0beta
版中,ckman
加入了對邏輯叢集的支援。
誠如上面所說,對邏輯叢集的運維動作,比如增刪節點、增加和銷燬物理叢集,都需要同步重新整理邏輯叢集裡所有節點的配置,這項工作不僅費時費力,且容易出錯,人工去操作的話,很難保證效率。而ckman
的出現,恰好解決了這一問題。我們只需要在介面上進行簡單的點選,所有的配置檔案重新整理操作都會由ckman
去自主完成,從而大大簡化了操作步驟。
建立邏輯叢集
使用ckman
建立邏輯叢集非常簡單,只需要在"邏輯名稱"輸入框中輸入邏輯叢集的名稱即可。
邏輯叢集建立成功後,會在首先的叢集列表中展示出來。
同時,這些資訊會持久化到硬碟中,在conf/clusters.json
檔案中,有如下選項:
"logic_clusters": {
"bench": [
"bench_shanghai",
"bench_hefei"
]
}
它的意思是說bench
邏輯叢集由bench_shanghai
和bench_hefei
的物理叢集組成,該邏輯叢集的節點也就是其物理叢集的所有節點。
其他運維操作
ckman
支援邏輯叢集的增加節點、刪除節點、升級叢集以及銷燬叢集等操作。雖然這些操作是針對物理叢集的,但是如果設定了邏輯叢集,也會同步重新整理邏輯叢集所有節點的metrika.xml
配置,從而保證邏輯叢集的節點實時同步。
建立跨邏輯叢集的分散式表
前面提到過,我們可以在每個物理叢集建立跨邏輯叢集的分散式表,但是當邏輯叢集內的物理叢集比較多時,上述的建表操作還是很繁瑣的,ckman
提供了一個dist_table
的API
,這是一個POST
介面。
URL
:/api/v1/ck/dist_logic_table/{clusterName}
METHOD
:POST
BODY
:
{
"database":"default",
"table_name":"t123"
}
該介面會在邏輯叢集的每個物理叢集上建立跨邏輯叢集的分散式表,使用該分散式表,就可以實現在邏輯叢集上進行資料查詢。
寫在最後
本文簡單介紹了邏輯叢集的玩法,不可否認的是,邏輯叢集的引入,確實能解決不少客戶的痛點,但同樣也帶來了不小的運維阻力。雖然有類似於ckman
這樣的運維工具可以幫助解決,但某些高階的玩法,比如由多個邏輯叢集組成的父級邏輯叢集,也是ckman
不能支援的。但隨著clickhouse
周邊生態的原來越完善,相信會有更多優秀的叢集玩法誕生,也許下一個亮眼的點子就是你提出的,誰說不是呢?