ClickHouse 副本协同原理:ReplicatedMergeTree引擎
文章目錄
- ReplicatedMergeTree引擎
- 特點(diǎn)
- 數(shù)據(jù)結(jié)構(gòu)
- ZooKeeper內(nèi)的節(jié)點(diǎn)結(jié)構(gòu)
- Entry日志對(duì)象的數(shù)據(jù)結(jié)構(gòu)
- 副本協(xié)同的核心流程
- INSERT
- MERGE
- MUTATION
- ALTER
ReplicatedMergeTree引擎
ReplicatedMergeTree是MergeTree的派生引擎,它在MergeTree的基礎(chǔ)上加入了分布式協(xié)同的能力,只有使用了ReplicatedMergeTree復(fù)制表系列引擎,才能應(yīng)用副本的能力。或者用一種更為直接的方式理解,即使用ReplicatedMergeTree的數(shù)據(jù)表就是副本。
ReplicatedMergeTree與MergeTree的邏輯關(guān)系在MergeTree中,一個(gè)數(shù)據(jù)分區(qū)由開(kāi)始創(chuàng)建到全部完成,會(huì)歷經(jīng)兩類存儲(chǔ)區(qū)域。
- 內(nèi)存:數(shù)據(jù)首先會(huì)被寫入內(nèi)存緩沖區(qū)。
- 本地磁盤:數(shù)據(jù)接著會(huì)被寫入tmp臨時(shí)目錄分區(qū),待全部完成后再將臨時(shí)目錄重命名為正式分區(qū)。
ReplicatedMergeTree在上述基礎(chǔ)之上增加了ZooKeeper的部分,它會(huì)進(jìn)一步在ZooKeeper內(nèi)創(chuàng)建一系列的監(jiān)聽(tīng)節(jié)點(diǎn),并以此實(shí)現(xiàn)多個(gè)實(shí)例之間的通信。在整個(gè)通信過(guò)程中,ZooKeeper并不會(huì)涉及表數(shù)據(jù)的傳輸。
特點(diǎn)
作為數(shù)據(jù)副本的主要實(shí)現(xiàn)載體,ReplicatedMergeTree在設(shè)計(jì)上有一些顯著特點(diǎn)。
-
依賴ZooKeeper:在執(zhí)行INSERT和ALTER查詢的時(shí)候,ReplicatedMergeTree需要借助ZooKeeper的分布式協(xié)同能力,以實(shí)現(xiàn)多個(gè)副本之間的同步。但是在查詢副本的時(shí)候,并不需要使用ZooKeeper。
-
表級(jí)別的副本:副本是在表級(jí)別定義的,所以每張表的副本配置都可以按照它的實(shí)際需求進(jìn)行個(gè)性化定義,包括副本的數(shù)量,以及副本在集群內(nèi)的分布位置等。
-
多主架構(gòu)(Multi Master):可以在任意一個(gè)副本上執(zhí)行INSERT和ALTER查詢,它們的效果是相同的。這些操作會(huì)借助ZooKeeper的協(xié)同能力被分發(fā)至每個(gè)副本以本地形式執(zhí)行。
-
Block數(shù)據(jù)塊:在執(zhí)行INSERT命令寫入數(shù)據(jù)時(shí),會(huì)依據(jù)max_insert_block_size的大小(默認(rèn)1048576行)將數(shù)據(jù)切分成若干個(gè)Block數(shù)據(jù)塊。所以Block數(shù)據(jù)塊是數(shù)據(jù)寫入的基本單元,并且具有寫入的原子性和唯一性。
-
原子性:在數(shù)據(jù)寫入時(shí),一個(gè)Block塊內(nèi)的數(shù)據(jù)要么全部寫入成功,要么全部失敗。
-
唯一性:在寫入一個(gè)Block數(shù)據(jù)塊的時(shí)候,會(huì)按照當(dāng)前Block數(shù)據(jù)塊的數(shù)據(jù)順序、數(shù)據(jù)行和數(shù)據(jù)大小等指標(biāo),計(jì)算Hash信息摘要并記錄在案。在此之后,如果某個(gè)待寫入的Block數(shù)據(jù)塊與先前已被寫入的Block數(shù)據(jù)塊擁有相同的Hash摘要(Block數(shù)據(jù)塊內(nèi)數(shù)據(jù)順序、數(shù)據(jù)大小和數(shù)據(jù)行均相同),則該Block數(shù)據(jù)塊會(huì)被忽略。
數(shù)據(jù)結(jié)構(gòu)
ZooKeeper內(nèi)的節(jié)點(diǎn)結(jié)構(gòu)
ReplicatedMergeTree需要依靠ZooKeeper的事件監(jiān)聽(tīng)機(jī)制以實(shí)現(xiàn)各個(gè)副本之間的協(xié)同。所以,在每張ReplicatedMergeTree表的創(chuàng)建過(guò)程中,它會(huì)以zk_path為根路徑,在ZooKeeper中為這張表創(chuàng)建一組監(jiān)聽(tīng)節(jié)點(diǎn)。
按照作用的不同,監(jiān)聽(tīng)節(jié)點(diǎn)可以大致分成如下幾類:
- 元數(shù)據(jù)
- /metadata:保存元數(shù)據(jù)信息,包括主鍵、分區(qū)鍵、采樣表達(dá)式等。
- /columns:保存列字段信息,包括列名稱和數(shù)據(jù)類型。
- /replicas:保存副本名稱,對(duì)應(yīng)設(shè)置參數(shù)中的replica_name。
- 判斷標(biāo)識(shí)
- /leader_election:用于主副本的選舉工作,主副本會(huì)主導(dǎo)MERGE和MUTATION操作(ALTER DELETE和ALTER UPDATE)。這些任務(wù)在主副本完成之后再借助ZooKeeper將消息事件分發(fā)至其他副本。
- /blocks:記錄Block數(shù)據(jù)塊的Hash信息摘要,以及對(duì)應(yīng)的partition_id。通過(guò)Hash摘要能夠判斷Block數(shù)據(jù)塊是否重復(fù);通過(guò)partition_id,則能夠找到需要同步的數(shù)據(jù)分區(qū)。
- /block_numbers:按照分區(qū)的寫入順序,以相同的順序記錄partition_id。各個(gè)副本在本地進(jìn)行MERGE時(shí),都會(huì)依照相同的block_numbers順序進(jìn)行。
- /quorum:記錄quorum的數(shù)量,當(dāng)至少有quorum數(shù)量的副本寫入成功后,整個(gè)寫操作才算成功。quorum的數(shù)量由insert_quorum參數(shù)控制,默認(rèn)值為0。
- 操作日志
- /log:常規(guī)操作日志節(jié)點(diǎn)(INSERT、MERGE和DROP PARTITION),它是整個(gè)工作機(jī)制中最為重要的一環(huán),保存了副本需要執(zhí)行的任務(wù)指令。log使用了ZooKeeper的持久順序型節(jié)點(diǎn),每條指令的名稱以log-為前綴遞增,例如log-0000000000、log-0000000001等。每一個(gè)副本實(shí)例都會(huì)監(jiān)聽(tīng)/log節(jié)點(diǎn),當(dāng)有新的指令加入時(shí),它們會(huì)把指令加入副本各自的任務(wù)隊(duì)列,并執(zhí)行任務(wù)。
- /mutations:MUTATION操作日志節(jié)點(diǎn),作用與log日志類似,當(dāng)執(zhí)行ALERT DELETE和ALERT UPDATE查詢時(shí),操作指令會(huì)被添加到這個(gè)節(jié)點(diǎn)。mutations同樣使用了ZooKeeper的持久順序型節(jié)點(diǎn),但是它的命名沒(méi)有前綴,每條指令直接以遞增數(shù)字的形式保存,例如0000000000、0000000001等。
- /replicas/{replica_name}/*:每個(gè)副本各自的節(jié)點(diǎn)下的一組監(jiān)聽(tīng)節(jié)點(diǎn),用于指導(dǎo)副本在本地執(zhí)行具體的任務(wù)指令,其中較為重要的節(jié)點(diǎn)有如下幾個(gè):
- /queue:任務(wù)隊(duì)列節(jié)點(diǎn),用于執(zhí)行具體的操作任務(wù)。當(dāng)副本從/log或/mutations節(jié)點(diǎn)監(jiān)聽(tīng)到操作指令時(shí),會(huì)將執(zhí)行任務(wù)添加至該節(jié)點(diǎn)下,并基于隊(duì)列執(zhí)行。
- /log_pointer:log日志指針節(jié)點(diǎn),記錄了最后一次執(zhí)行的log日志下標(biāo)信息。
- /mutation_pointer:mutations日志指針節(jié)點(diǎn),記錄了最后一次執(zhí)行的mutations日志名稱。
Entry日志對(duì)象的數(shù)據(jù)結(jié)構(gòu)
ReplicatedMergeTree在ZooKeeper中有兩組非常重要的父節(jié)點(diǎn),那就/log和/mutations。它們的作用猶如一座通信塔,是分發(fā)操作指令的信息通道,而發(fā)送指令的方式,則是為這些父節(jié)點(diǎn)添加子節(jié)點(diǎn)。
所有的副本實(shí)例,都會(huì)監(jiān)聽(tīng)父節(jié)點(diǎn)的變化,當(dāng)有子節(jié)點(diǎn)被添加時(shí),它們能實(shí)時(shí)感知。這些被添加的子節(jié)點(diǎn)在ClickHouse中被統(tǒng)一抽象為Entry對(duì)象,而具體實(shí)現(xiàn)則由LogEntry和MutationEntry對(duì)象承載,分別對(duì)應(yīng)/log和/mutations節(jié)點(diǎn)
- LogEntry
- source replica:發(fā)送這條Log指令的副本來(lái)源,對(duì)應(yīng)replica_name。
- type:操作指令類型,主要有g(shù)et、merge和mutate三種,分別對(duì)應(yīng)從遠(yuǎn)程副本下載分區(qū)、合并分區(qū)和MUTATION操作。
- block_id:當(dāng)前分區(qū)的BlockID,對(duì)應(yīng)/blocks路徑下子節(jié)點(diǎn)的名稱。
- partition_name:當(dāng)前分區(qū)目錄的名稱。
- MutationEntry
- source replica:發(fā)送這條MUTATION指令的副本來(lái)源,對(duì)應(yīng)replica_name。
- commands:操作指令,主要有ALTER DELETE和ALTER UPDATE。
- mutation_id:MUTATION操作的版本號(hào)。
- partition_id:當(dāng)前分區(qū)目錄的ID。
副本協(xié)同的核心流程
副本協(xié)同的核心流程主要有INSERT、MERGE、MUTATION和ALTER四種,分別對(duì)應(yīng)了數(shù)據(jù)寫入、分區(qū)合并、數(shù)據(jù)修改和元數(shù)據(jù)修改。INSERT和ALTER是分布式執(zhí)行的,借助ZooKeeper的事件通知機(jī)制,多個(gè)副本之間會(huì)自動(dòng)進(jìn)行有效協(xié)同,但是它們不會(huì)使用ZooKeeper存儲(chǔ)任何分區(qū)數(shù)據(jù)。而其他操作并不支持分布式執(zhí)行,包括SELECT、CREATE、DROP、RENAME和ATTACH。
在下列例子中,使用ReplicatedMergeTree實(shí)現(xiàn)一張擁有1分片、1副本的數(shù)據(jù)表來(lái)分別執(zhí)行INSERT、MERGE、MUTATION和ALTER操作,演示執(zhí)行流程。
INSERT
當(dāng)需要在ReplicatedMergeTree中執(zhí)行INSERT查詢以寫入數(shù)據(jù)時(shí),即會(huì)進(jìn)入INSERT核心流程,它的核心流程如下圖所示
INSERT的核心執(zhí)行流程- 選擇一個(gè)遠(yuǎn)端的其他副本作為數(shù)據(jù)的下載來(lái)源。遠(yuǎn)端副本的選擇算法大致是這樣的:
- 從/replicas節(jié)點(diǎn)拿到所有的副本節(jié)點(diǎn)。
- 遍歷這些副本,選取其中一個(gè)。選取的副本需要擁有最大的log_pointer下標(biāo),并且/queue子節(jié)點(diǎn)數(shù)量最少。log_pointer下標(biāo)最大,意味著該副本執(zhí)行的日志最多,數(shù)據(jù)應(yīng)該更加完整;而/queue最小,則意味著該副本目前的任務(wù)執(zhí)行負(fù)擔(dān)較小。
在INSERT的寫入過(guò)程中,ZooKeeper不會(huì)進(jìn)行任何實(shí)質(zhì)性的數(shù)據(jù)傳輸。本著誰(shuí)執(zhí)行誰(shuí)負(fù)責(zé)的原則,在這個(gè)案例中由CH5首先在本地寫入了分區(qū)數(shù)據(jù)。之后,也由這個(gè)副本負(fù)責(zé)發(fā)送Log日志,通知其他副本下載數(shù)據(jù)。如果設(shè)置了insert_quorum并且insert_quorum>=2,則還會(huì)由該副本監(jiān)控完成寫入的副本數(shù)量。其他副本在接收到Log日志之后,會(huì)選擇一個(gè)最合適的遠(yuǎn)端副本,點(diǎn)對(duì)點(diǎn)地下載分區(qū)數(shù)據(jù)。
MERGE
當(dāng)ReplicatedMergeTree觸發(fā)分區(qū)合并動(dòng)作時(shí),即會(huì)進(jìn)入這個(gè)部分的流程,它的核心流程如下圖所示
MERGE的核心執(zhí)行流程無(wú)論MERGE操作從哪個(gè)副本發(fā)起,其合并計(jì)劃都會(huì)交由主副本來(lái)制定。
可以看到,在MERGE的合并過(guò)程中,ZooKeeper也不會(huì)進(jìn)行任何實(shí)質(zhì)性的數(shù)據(jù)傳輸,所有的合并操作,最終都是由各個(gè)副本在本地完成的。而無(wú)論合并動(dòng)作在哪個(gè)副本被觸發(fā),都會(huì)首先被轉(zhuǎn)交至主副本,再由主副本負(fù)責(zé)合并計(jì)劃的制定、消息日志的推送以及對(duì)日志接收情況的監(jiān)控。
MUTATION
當(dāng)對(duì)ReplicatedMergeTree執(zhí)行ALTER DELETE或者ALTER UPDATE操作的時(shí)候(ClickHouse把DELETE和UPDATE操作也加入到了ALTER TABLE的范疇中,它并不支持裸的DELETE或者UPDATE操作),即會(huì)進(jìn)入MUTATION部分的邏輯
MUTATION的核心執(zhí)行流程與MERGE類似,無(wú)論MUTATION操作從哪個(gè)副本發(fā)起,首先都會(huì)由主副本進(jìn)行響應(yīng)。
在MUTATION的整個(gè)執(zhí)行過(guò)程中,ZooKeeper同樣不會(huì)進(jìn)行任何實(shí)質(zhì)性的數(shù)據(jù)傳輸。所有的MUTATION操作,最終都是由各個(gè)副本在本地完成的。而MUTATION操作是經(jīng)過(guò)/mutations節(jié)點(diǎn)實(shí)現(xiàn)分發(fā)的。CH6負(fù)責(zé)了消息的推送。但是無(wú)論MUTATION動(dòng)作從哪個(gè)副本被觸發(fā),之后都會(huì)被轉(zhuǎn)交至主副本,再由主副本負(fù)責(zé)推送Log日志,以通知各個(gè)副本執(zhí)行最終的MUTATION邏輯。同時(shí)也由主副本對(duì)日志接收的情況實(shí)行監(jiān)控。
ALTER
當(dāng)對(duì)ReplicatedMergeTree執(zhí)行ALTER操作進(jìn)行元數(shù)據(jù)修改的時(shí)候,即會(huì)進(jìn)入ALTER部分的邏輯,例如增加、刪除表字段等,核心流程如下圖
ALTER的核心執(zhí)行流程ALTER的流程與前幾個(gè)相比簡(jiǎn)單很多,其執(zhí)行過(guò)程中并不會(huì)涉及/log日志的分發(fā),整個(gè)流程大致分成3個(gè)步驟
在ALTER整個(gè)的執(zhí)行過(guò)程中,ZooKeeper不會(huì)進(jìn)行任何實(shí)質(zhì)性的數(shù)據(jù)傳輸。所有的ALTER操作,最終都是由各個(gè)副本在本地完成的。本著誰(shuí)執(zhí)行誰(shuí)負(fù)責(zé)的原則,在這個(gè)案例中由CH6負(fù)責(zé)對(duì)共享元數(shù)據(jù)的修改以及對(duì)各個(gè)副本修改進(jìn)度的監(jiān)控。
總結(jié)
以上是生活随笔為你收集整理的ClickHouse 副本协同原理:ReplicatedMergeTree引擎的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ClickHouse 数据存储原理:Me
- 下一篇: ClickHouse 分布式原理:Dis