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