前言
- 集群是副本和分片的基礎(chǔ)波附,它將 clickhouse 的服務拓撲由單節(jié)點延伸到多個節(jié)點姜骡。
- ClickHouse集群配置很靈活弃理,既可以將所有節(jié)點組成一個單一的大集群,也可以按照業(yè)務需求滔金,把節(jié)點劃分為多個小集群色解。
- 在每個小集群區(qū)域之間,它們的節(jié)點餐茵、分區(qū)和副本數(shù)量可以各不相同冒签。
ClickHouse集群的工作更多是針對邏輯層面,集群定義了多個節(jié)點的拓撲關(guān)系钟病,這些節(jié)點在后續(xù)服務過程中很可能會協(xié)同工作萧恕,在執(zhí)行層面的具體工作則交給了副本和分片來執(zhí)行刚梭。
- 副本與分片的區(qū)別:
- 1、從數(shù)據(jù)層面上區(qū)分票唆,假設 clickhouse 有 N 個節(jié)點朴读,在集群的各個節(jié)點上都有一張結(jié)構(gòu)相同的數(shù)據(jù)表 Y , 如果 N1,N2 兩個節(jié)點的數(shù)據(jù)完全相同,則互為副本走趋,如果數(shù)據(jù)完全不同則互為分片衅金。
-
2、從功能層面上看簿煌,副本的主要目的是為了防止數(shù)據(jù)丟失氮唯,而數(shù)據(jù)分片是為了實現(xiàn)數(shù)據(jù)的水平切分。
一姨伟、數(shù)據(jù)副本
副本的目的主要是保障數(shù)據(jù)的高可用性惩琉,即使一臺 ClickHouse 節(jié)點宕機,那么也可以從其他服務器獲得相同的數(shù)據(jù)夺荒。
官網(wǎng)地址如下:
https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication/
如果在 MergeTree 表引擎前面加上 Replicated 前綴瞒渠,就能夠組合成一個新的引擎即 Replicated-mergeTree 復制表。
只有使用了 ReplicatedMergeTree 系列復制表引擎才能使用副本技扼。ReplicatedMergeTree是 MergeTree 的派生表引擎伍玖,在 MergeTree 的基礎(chǔ)上加入了分布式協(xié)同能力。
在 MergeTree 中剿吻,一個分區(qū)由開始創(chuàng)建到全部完成會經(jīng)歷兩個存儲區(qū)域
- 內(nèi)存:數(shù)據(jù)首先會被寫入內(nèi)存緩存區(qū)
- 本地磁盤:數(shù)據(jù)接著會被寫入到tmp 臨時目錄分區(qū)窍箍,待全部完成后,再將臨時目錄重命名為正式分區(qū)
ReplicatedMergeTree 在上述基礎(chǔ)上增加了 zookeeper 的部分丽旅,它會進一步在 zookeeper 內(nèi)部創(chuàng)建一系列的監(jiān)聽節(jié)點仔燕,并以此實現(xiàn)多個實例之間的通信,在整個通信過程中 zookeeper 并不會設計數(shù)據(jù)的傳輸魔招。
目前只有MergeTree系列里的表可以支持副本:
- ReplicatedMergeTree
- ReplicatedSummingMergeTree
- ReplicatedReplacingMergeTree
- ReplicatedAggregatingMergeTree
- ReplicatedCollapsingMergeTree
- ReplicatedVersionedCollapsingMergeTree
- ReplicatedGraphiteMergeTree
ClickHouse 的數(shù)據(jù)副本機制是表級別的,不是整個服務器級的五辽,也就是說只針對表進行復制办斑,一個數(shù)據(jù)庫中可以同時包含復制表和非復制表。副本機制對于 select 查詢是沒有影響的杆逗,查詢復制表和非復制表的速度是一樣的乡翅。而寫入數(shù)據(jù)時,ClickHouse 的集群沒有主從之分罪郊,大家都是平等的蠕蚜。只不過配置了復制表后,Insert 以及 Alter 操作會同步到對應的副本機器中悔橄。對于復制表靶累,每個 Insert 語句會往 Zookeeper 中寫入十來條記錄腺毫,相比非復制表,寫 Zookeeper 會導致 Insert 語句的延遲時間略長挣柬。但是潮酒,在 ClickHouse 建議的每秒不超過一個 Insert 語句的執(zhí)行頻率下,這個延遲時間不會有太大的影響邪蛔。
1.1 數(shù)據(jù)副本的特點
- 依賴 zookeeper:在執(zhí)行 insert 和 alert 查詢的時候急黎,ReplicatedMergeTree 需要借助 zookeeper 的分布式協(xié)調(diào)能力,以實現(xiàn)多個副本之間的數(shù)據(jù)同步侧到,但是在查詢的時候勃教,并不需要使用 zookeeper。
- 表級別的副本:副本是在表級別定義的匠抗,所以每張表的副本配置都可以按照它的實際需求進行個性化故源,包括副本數(shù)量,以及副本在集群內(nèi)的分布式位置等戈咳。
- 多主架構(gòu)(Multi Master):可以在任意一個副本上執(zhí)行 insert 和 alter 查詢心软,他們的效果是相同的,這些操作會借助 zookeeper 的協(xié)調(diào)能力被分發(fā)至每個副本以本地形式執(zhí)行著蛙。
- Block 數(shù)據(jù)塊:在執(zhí)行 insert 命令時删铃,會依據(jù) max_insert_block_size 的大小(默認 1048576 行)將數(shù)據(jù)切分成若干個 Block 數(shù)據(jù)塊踏堡。所以數(shù)據(jù)塊是數(shù)據(jù)寫入的基本單元猎唁,并且具有寫入的原子性和唯一性。
- 原子性:在數(shù)據(jù)寫入時顷蟆,一個 Block 塊內(nèi)的數(shù)據(jù)要么全部寫入成功诫隅,要么全部失敗。
- 唯一性:在寫入一個 Block 數(shù)據(jù)塊的時候帐偎,會按照當前的 Block 數(shù)據(jù)塊的數(shù)據(jù)順序逐纬、數(shù)據(jù)行和數(shù)據(jù)大小等指標計算 Hash 信息摘要記錄。在此之后削樊,如果某個待寫入的 Block 數(shù)據(jù)塊與先前已被寫入的 Block 數(shù)據(jù)塊擁有相同的 Hash 摘要豁生,則該 Block 數(shù)據(jù)塊會被忽略,這個設計可以預防由于異常原因引起的 Block 數(shù)據(jù)塊重復寫入的問題漫贞。
1.2 副本寫入流程
在這其中甸箱,其實還有很多的實現(xiàn)細節(jié)。數(shù)據(jù)副本需要經(jīng)過網(wǎng)絡傳輸迅脐,所以副本中寫入數(shù)據(jù)是有延遲的芍殖。默認情況下,ClickHouse 對于 Insert 語句谴蔑,只會等待一個副本寫入成功后就會返回豌骏。如果有多個副本的情況下龟梦,ClickHouse 是有可能丟失數(shù)據(jù)的。寫入數(shù)據(jù)時肯适,ClickHouse 只保證單個數(shù)據(jù)塊的寫入是原子的变秦,而不能保證所有的數(shù)據(jù)寫入是原子的。一個數(shù)據(jù)塊的大小可以根據(jù)max_insert_block_size=1048576行進行分塊框舔。數(shù)據(jù)塊寫入時是會去重的蹦玫,一個同樣的 Insert 語句多次重復執(zhí)行,數(shù)據(jù)庫塊只會執(zhí)行一次刘绣。這是為了防止用戶重復插入數(shù)據(jù)或者網(wǎng)絡波動等原因造成的數(shù)據(jù)重發(fā)樱溉。這個去重機制只對應Replicated*MergeTree系列的表引擎,普通的MergeTree是不帶這個去重功能的纬凤。
1.3 副本配置步驟
ClickHouse 的集群搭建依賴 Zookeeper福贞。如果沒有配置 Zookeeper 的話,依然可以創(chuàng)建復制表停士,但是這些復制表都將變成只讀挖帘。另外,官方建議恋技,不要在 ClickHouse 所在的服務器上運行 Zookeeper拇舀。因為 Zookeeper 對數(shù)據(jù)延遲非常敏感,而 ClickHouse 可能會占用所有可用的系統(tǒng)資源蜻底。
另外需要注意的是骄崩,當前版本要求 Zookeeper 版本最低為3.4.5。并且薄辅,官方對于 Zookeeper 的優(yōu)化配置也提出了指導意見要拂。具體如下:
https://clickhouse.com/docs/zh/operations/tips。
服務器準備完成后站楚,開始配置 ClickHouse脱惰。打開 ClickHouse 的配置文件/etc/clickhouse-server/config.xml,指定 Zookeeper 集群地址:
zookeeper 的配置方式
在配置 zookeeper 之前需要先安裝 zookeeper窿春,zookeeper 的安裝方式可以查看文檔:zookeeper 安裝
clickhouse 使用量一組 zookeeper 標簽定義了相關(guān)配置拉一,在默認情況下,在全局配置 config.xml 中定義即可谁尸,但是為了方便在多個節(jié)點中復制,通常會把配置文件抽離出來纽甘,獨立使用一個文件保存良蛮。
編寫 zookeeper 配置文件
# 1. /etc/clickhouse-server/config.xml 修改如下配置
vim metrika.xml
<zookeeper>
<node>
<host>node2</host>
<port>2181</port>
</node>
</zookeeper>
- clickhouse 提供了一張名為 zookeeper 的代理表,可以使用 SQL 查詢 zookeeper 中的數(shù)據(jù)悍赢。
-- 查詢 zookeeper 中的數(shù)據(jù)决瞳,必須指定 path 條件
SELECT
name,
value,
ctime
FROM system.zookeeper
WHERE path = '/'
┌─name───────┬─value─┬───────────────ctime─┐
│ zookeeper │ │ 1970-01-01 08:00:00 │
│ clickhouse │ │ 2021-07-21 11:29:59 │
└────────────┴───────┴─────────────────────┘
副本的定義形式
- 使用副本可以增加數(shù)據(jù)的冗余货徙,降低數(shù)據(jù)的丟失風險
- 副本才用了多主架構(gòu),每個副本示例都可以作為數(shù)據(jù)讀寫的入口皮胡,分攤了節(jié)點的負載
- 使用 ReplicatedMergeTree 定義副本
CREATE TABLE [IF NOT EXISTS] [db_name.]table_name(
name1 [type] [DEFAULT|MATERIALIZED|ALIAS expr],
name2 [type] [DEFAULT|MATERIALIZED|ALIAS expr],
...
) ENGINE = ReplicatedMergeTree('zk_path','replica_name')
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]
- zk_path:用于指定 zookeeper 中創(chuàng)建的表的路徑痴颊,值可自定義,但是 clickhouse 建議設置的值為 /clickhouse/tables/{shard}/table_name
- /clickhouse/tables:固定路徑前綴屡贺,表示存放表的根路徑
- {shard}:表示分片編號蠢棱,通常使用數(shù)值代替,一張表可以有多個分片甩栈,每個分片都擁有自己的副本
- table_name:表名泻仙,為了方便維護,通常與表的物理名稱相同量没。
- replica_name:定義在 zookeeper 中創(chuàng)建的副本名稱玉转,該名稱是區(qū)分不同副本實例的唯一標識,約定的方式是使用服務器的域名
示例:
# 1 個分片殴蹄,1 個副本
ReplicatedMergeTree('/clickhouse/tables/01/t_replicated','node3')
ReplicatedMergeTree('/clickhouse/tables/01/t_replicated','node4')
# 多 個分片究抓,1 個副本
ReplicatedMergeTree('/clickhouse/tables/01/t_replicated','node3')
ReplicatedMergeTree('/clickhouse/tables/01/t_replicated','node4')
ReplicatedMergeTree('/clickhouse/tables/02/t_replicated','node3')
ReplicatedMergeTree('/clickhouse/tables/03/t_replicated','node4')
二、ReplicatedMergeTree 原理解析
2.1 數(shù)據(jù)結(jié)構(gòu)
在 ReplicatedMergeTree 的核心邏輯大量使用量 zookeeper袭灯,以實現(xiàn)多個 ReplicatedMergeTree 副本實例之間的協(xié)同刺下,包括副本選舉、副本狀態(tài)感知妓蛮、操作分發(fā)日志怠李、任務隊列和 BlockID 去重判斷等。
在執(zhí)行 insert 蛤克、merge 和 mutation 操作的時候捺癞,都會涉及與 zookeeper 的通信。
在與 zookeeper通信時并不會涉及任何數(shù)據(jù)的傳輸构挤,在查詢數(shù)據(jù)的時候也不會訪問 zookeeper髓介,因此不必擔心 zookeeper 承擔太多壓力。
2.1.1 zookeeper 內(nèi)的節(jié)點結(jié)構(gòu)
ReplicatedMergeTree 需要依靠 zookeeper 的事件監(jiān)聽機制實現(xiàn)各個副本之間的協(xié)同筋现,當ReplicatedMergeTree 表創(chuàng)建過程中會以 zk_path 為根路徑唐础,在 zookeeper 中為這張表創(chuàng)建一組監(jiān)聽節(jié)點,按照作用不同矾飞,監(jiān)聽節(jié)點可以分為如下幾類:
1一膨、元數(shù)據(jù):
- /metadata:保存元數(shù)據(jù)信息,包括主鍵洒沦、分區(qū)間豹绪、采樣表達式等
- /columns:保存列字段信息,包括列名稱和數(shù)據(jù)類型
- /replicas:保存副本名稱申眼,對應設置參數(shù)中的 replica_name
2瞒津、判斷標識:
- /leader_election:對于副本的選舉工作蝉衣,主副本會主導 Merge 和 mutation 操作(alter delete/和alter update),這些任務在主副本完成之后巷蚪,借助 zookeeper 將消息時間分發(fā)至其他副本病毡。
- /blocks:記錄 Block 數(shù)據(jù)庫的 Hash 摘要,以及對應的 partition id 屁柏。通過 Hash 摘要能夠判斷 Block 是否重復啦膜,通過 partition ID 能夠找到需要同步的分區(qū)。
- /block_numbers:按照分區(qū)的寫入順序前联,以相同順序記錄 partition ID功戚。各個副本在本地進行 Merge 時,都會依照相同的 block_numbers順序進行似嗤。
- /quorum:記錄 quorum 的數(shù)量啸臀,當至少有 quorum 數(shù)量的副本寫入成功后,整個寫操作才算成功烁落,quorum 的數(shù)量有 insert_quorum 參數(shù)控制乘粒,默認為 0。
3伤塌、日志操作:
- /log:常規(guī)日志節(jié)點(insert灯萍、Merge 和 drop table),它是整個工作機制中最為重要的一環(huán)每聪,保存了副本需要執(zhí)行的任務指令旦棉。log 使用了 zookeeper 的持久節(jié)點,每條指令以 log- 為前綴遞增药薯,每個副本實例都會監(jiān)聽 /log 節(jié)點绑洛,當有新的指令加入時,他們會把指令加入副本各自的任務隊列童本,并執(zhí)行任務真屯。
- /mutatios:mutation操作(alter delete/和alter update)日志節(jié)點,節(jié)點命名沒有前綴穷娱,其余邏輯與 /log 相同绑蔫。
- /replicas/{replica_name}/*:每個副本各自的節(jié)點下的一組監(jiān)聽節(jié)點,用于指導副本在本地執(zhí)行具體的任務指令泵额,比較重要的有下面幾個:
- /queue:任務隊列節(jié)點配深,用于執(zhí)行具體的操作任務從/log 或/mutations 節(jié)點監(jiān)聽到操作指令時,會將執(zhí)行任務添加到該節(jié)點下嫁盲,并給基于列執(zhí)行篓叶。
- /log_pointer:log日志指針節(jié)點,記錄了最后一次執(zhí)行 log 日志下標信息。
- /mutation_pointer:mutation日志指針節(jié)點澜共,記錄了最后一次執(zhí)行 mutation 日志下標信息。
2.1.2 Entry日志對象的數(shù)據(jù)結(jié)構(gòu)
在 zookeeper 中的兩個重要的節(jié)點 log和 mutation 在clickhouse 中被抽象成了兩個 Entry 對象锥腻。
LogEntry(封裝 log 節(jié)點的信息)擁有以下核心屬性
- source replica:發(fā)送這條 log 指令的來源嗦董,對應 replica_name
- type:操作指令類型,主要有 get瘦黑、merge京革、mutate 三種,分別對應從遠程副本下載分區(qū)幸斥,合并分區(qū)和 mutation 操作
- block_id:當前分區(qū)的 BlockID匹摇,對應/blocks 路徑下的子節(jié)點名稱。
- partition_name:當前分區(qū)目錄的名稱
- MutationEntry(封裝 mutation 接節(jié)點信息)
- source replica:發(fā)送這條 mutation 指令的來源甲葬,對應 replica_name
- commands:操作指令廊勃,alter delete/和alter update
- mutation_id:mutation 操作的版本號
- partition_id:當前分區(qū)目錄 ID
2.2 副本操作流程
副本操作一般有數(shù)據(jù)寫入,分區(qū)合并经窖,數(shù)據(jù)修改和元數(shù)據(jù)修改 4 部分
數(shù)據(jù)寫入和元數(shù)據(jù)修改時分布式執(zhí)行的坡垫,借助 zookeeper 的事件監(jiān)聽機制,多個副本之間會自動進行同步画侣,但是這些操作不會使用 zookeeper 存儲任何數(shù)據(jù)冰悠。
其他操作不支持分布式執(zhí)行,如 select配乱、create溉卓、drop、rename搬泥、attach 等
2.2.1 insert 的執(zhí)行流程
- 1桑寨、創(chuàng)建測試表,該表由一個分片 0 個副本構(gòu)成
create table t_replicated(
id UInt8,
name String,
date DateTime
)ENGINE=ReplicatedMergeTree('/clickhouse/tables/01/t_replicated','node3')
partition by toYYYYMM(date)
order by id
在創(chuàng)建過程中 ReplicatedMergeTree 會進行如下操作:
- 根據(jù) zk_path 除吃華所有的 zookeeper 節(jié)點
- 在 /replicas/節(jié)點下注冊自己的副本實例 node3
- 啟動監(jiān)聽任務佑钾,監(jiān)聽 /log 日志節(jié)點
- 參與副本選舉西疤,選舉出出副本,選舉的方式是向/leader_election 插入子節(jié)點休溶,第一個插入成功的副本就是主副本
- 查看zookeeper 中節(jié)點數(shù)據(jù)相關(guān)命令
ls /clickhouse
get /clickhouse
ls /clickhouse/tables
get /clickhouse/tables
ls /clickhouse/tables/01
get /clickhouse/tables/01
get /clickhouse/tables/01/t_replicated
ls /clickhouse/tables/01/t_replicated
get /clickhouse/tables/01/t_replicated/metadata
ls /clickhouse/tables/01/t_replicated/metadata
get /clickhouse/tables/01/t_replicated/temp
ls /clickhouse/tables/01/t_replicated/temp
get /clickhouse/tables/01/t_replicated/mutations
ls /clickhouse/tables/01/t_replicated/mutations
get /clickhouse/tables/01/t_replicated/log
ls /clickhouse/tables/01/t_replicated/log
get /clickhouse/tables/01/t_replicated/leader_election
ls /clickhouse/tables/01/t_replicated/leader_election
ls /clickhouse/tables/01/t_replicated/leader_election/leader_election-0000000001
get /clickhouse/tables/01/t_replicated/leader_election/leader_election-0000000001
get /clickhouse/tables/01/t_replicated/columns
ls /clickhouse/tables/01/t_replicated/columns
get /clickhouse/tables/01/t_replicated/nonincrement_block_numbers
ls /clickhouse/tables/01/t_replicated/nonincrement_block_numbers
get /clickhouse/tables/01/t_replicated/replicas
ls /clickhouse/tables/01/t_replicated/replicas
get /clickhouse/tables/01/t_replicated/replicas/node3
ls /clickhouse/tables/01/t_replicated/replicas/node3
get /clickhouse/tables/01/t_replicated/replicas/node2/is_lost
ls /clickhouse/tables/01/t_replicated/replicas/node2/is_lost
get /clickhouse/tables/01/t_replicated/replicas/node2/is_active
ls /clickhouse/tables/01/t_replicated/replicas/node2/is_active
get /clickhouse/tables/01/t_replicated/replicas/node2/metadata
ls /clickhouse/tables/01/t_replicated/replicas/node2/metadata
get /clickhouse/tables/01/t_replicated/replicas/node2/mutation_pointer
ls /clickhouse/tables/01/t_replicated/replicas/node2/mutation_pointer
get /clickhouse/tables/01/t_replicated/replicas/node2/columns
ls /clickhouse/tables/01/t_replicated/replicas/node2/columns
get /clickhouse/tables/01/t_replicated/replicas/node2/max_processed_insert_time
ls /clickhouse/tables/01/t_replicated/replicas/node2/max_processed_insert_time
get /clickhouse/tables/01/t_replicated/replicas/node2/flags
ls /clickhouse/tables/01/t_replicated/replicas/node2/flags
get /clickhouse/tables/01/t_replicated/replicas/node2/log_pointer
ls /clickhouse/tables/01/t_replicated/replicas/node2/log_pointer
get /clickhouse/tables/01/t_replicated/replicas/node2/min_unprocessed_insert_time
ls /clickhouse/tables/01/t_replicated/replicas/node2/min_unprocessed_insert_time
get /clickhouse/tables/01/t_replicated/replicas/node2/host
ls /clickhouse/tables/01/t_replicated/replicas/node2/host
get /clickhouse/tables/01/t_replicated/replicas/node2/parts
ls /clickhouse/tables/01/t_replicated/replicas/node2/parts
get /clickhouse/tables/01/t_replicated/replicas/node2/queue
ls /clickhouse/tables/01/t_replicated/replicas/node2/queue
get /clickhouse/tables/01/t_replicated/replicas/node2/metadata_version
ls /clickhouse/tables/01/t_replicated/replicas/node2/metadata_version
get /clickhouse/tables/01/t_replicated/quorum
ls /clickhouse/tables/01/t_replicated/quorum
ls /clickhouse/tables/01/t_replicated/quorum/last_part
get /clickhouse/tables/01/t_replicated/quorum/last_part
ls /clickhouse/tables/01/t_replicated/quorum/parallel
get /clickhouse/tables/01/t_replicated/quorum/parallel
ls /clickhouse/tables/01/t_replicated/quorum/failed_parts
get /clickhouse/tables/01/t_replicated/quorum/failed_parts
ls /clickhouse/tables/01/t_replicated/block_numbers
get /clickhouse/tables/01/t_replicated/block_numbers
- 2代赁、創(chuàng)建第二個副本實例 表的構(gòu)成是 1 分片 1 副本
create table t_replicated(
id UInt8,
name String,
date DateTime
)ENGINE=ReplicatedMergeTree('/clickhouse/tables/01/t_replicated','node2')
partition by toYYYYMM(date)
order by id;
在創(chuàng)建第二個副本實例的時候
會在/clickhouse/tables/01/t_replicated/replicas 節(jié)點下 注冊自己的副本 node2
啟動監(jiān)聽任務,監(jiān)聽 /log 日志節(jié)點
-
參與主副本選舉
3兽掰、向第一個副本寫入數(shù)據(jù)
insert into t_replicated values (1,'xiaoming','2021-07-21 18:01:49')
# 向 /blicks 節(jié)點寫入該數(shù)據(jù)分區(qū)的 block_id
db_merge.t_replicated (f43ce61c-6253-473c-a54d-4d9d6da57613) (Replicated OutputStream): Wrote block with ID '202107_8139788293933794752_9955392769311530712', 1 rows
# 向本地完成分區(qū)目錄的寫入
<Trace> db_merge.t_replicated (f43ce61c-6253-473c-a54d-4d9d6da57613): Renaming temporary part tmp_insert_202107_1_1_0 to 202107_0_0_0.
- 查看zookeeper 中 blocks 的元數(shù)據(jù)變化
[zk: localhost:2181(CONNECTED) 2] ls /clickhouse/tables/01/t_replicated/blocks
[202107_8139788293933794752_9955392769311530712] # block_id 跟前面日志可以對應芭碍,該block_id 將作為后續(xù)去重操作的判斷依據(jù)
[zk: localhost:2181(CONNECTED) 3] get /clickhouse/tables/01/t_replicated/blocks/202107_8139788293933794752_9955392769311530712
202107_0_0_0 # 保存的值為數(shù)據(jù)所在分區(qū)
如果設置了 insert_quorum 參數(shù),且 insert_quorum>=2 則 node3會進一步監(jiān)控已經(jīng)寫完操作的副本個數(shù)孽尽,只有寫成功的副本數(shù) 大于等于 2 時窖壕,整個寫操作才算成功。
- 4、由第一個副本推送 log 日志
在上面執(zhí)行完成之后瞻讽,會繼續(xù)由執(zhí)行了 insert 的副本想 /log 節(jié)點推送操作日志鸳吸。上面寫入操作中,會由 node3 完成此操作
[zk: localhost:2181(CONNECTED) 5] ls /clickhouse/tables/01/t_replicated/log
[log-0000000000]
[zk: localhost:2181(CONNECTED) 8] get /clickhouse/tables/01/t_replicated/log/log-0000000000
format version: 4
create_time: 2021-07-21 12:29:59
source replica: node3
block_id: 202107_8139788293933794752_9955392769311530712
get # 操作類型為 get
202107_0_0_0 # 分區(qū)
part_type: Compact
- 5速勇、第二個副本拉取 log 日志
node3 會一直監(jiān)聽 /log 節(jié)點的變化晌砾,當 node3 推送了 log-0000000000 之后,node3 會觸發(fā)日志拉取任務并更新 log_pointer 將其指向最新日志下標烦磁。
[zk: localhost:2181(CONNECTED) 25] get /clickhouse/tables/01/t_replicated/replicas/node2/log_pointer
1
在拉取了 logEntry 之后养匈,并不會直接執(zhí)行,而是將其轉(zhuǎn)為任務對象放到隊列都伪,因為在復雜情況下呕乎,同一時間內(nèi)可能收到多個 logEntry 使用隊列形式消化任務是一種更為合理的方式。
6陨晶、第二個副本實例向其他副本發(fā)起下載請求
node3基于/queue 隊列開始執(zhí)行任務猬仁,當看到 type 為 get 的時候,就會知道遠端的副本已經(jīng)成功寫入數(shù)據(jù)分區(qū)先誉,而自己需要同步這些數(shù)據(jù)逐虚,node3 同步數(shù)據(jù)流程大概如下:從 replicas 節(jié)點拿到所有的副本節(jié)點
遍歷副本,選取擁有最大的 log_pointerde 且/queue 子節(jié)點數(shù)量最少的副本谆膳,log_pointer 下標最大叭爱,意味著該副本執(zhí)行的日志最多,數(shù)據(jù)更加完整漱病,/queue 最小意味著該副本目前的任務執(zhí)行負擔較小买雾。
如果第一次請求失敗,會再次請求杨帽,默認請求五次漓穿,由 max_fetch_partition_retries_count 參數(shù)控制。
7注盈、第一個副本響應數(shù)據(jù)下載
node3 的 DataPartsExchange 端口服務接收到調(diào)用請求晃危,在得拉取數(shù)據(jù)請求后根據(jù)參數(shù)做出響應,將本地分區(qū) 202107_0_0_0基于 DataPartsExchange 的服務響應發(fā)送會 node2老客。8僚饭、第二個副本實例下載數(shù)據(jù)并完成本地寫入
node2 在收到分區(qū)數(shù)據(jù)后先將其寫到臨時目錄,等到數(shù)據(jù)全部接收完之后胧砰,將目錄重命名鳍鸵,至此整個寫入數(shù)據(jù)流程結(jié)束。
在寫入的整個過程中尉间,zookeeper 不會進行實質(zhì)性的數(shù)據(jù)傳輸偿乖。
2.2.2 merge 的執(zhí)行流程
當 ReplicatedMergeTree 觸發(fā)合并分區(qū)击罪,即進入了這部分的流程。
無論 Merge 操作從哪個副本發(fā)起贪薪,其合并計劃都會交給主副本來指定媳禁。整個流程從上至下按照時間順序進行,大致分成 5 個步驟画切。
1损话、創(chuàng)建遠程連接,嘗試與主副本通信
如果在非主副本節(jié)點執(zhí)行 optimize 操作槽唾,強制觸發(fā) merge 合并,這時該節(jié)點會通過 /replicas 找到主副本光涂,并與其建立連接庞萍。2、主副本接收通信
主副本接收并建立與遠端副本的連接3忘闻、主副本指定 merge 計劃并推送 log
由主副本指定 merge 計劃钝计,并判斷哪些分區(qū)需要被合并。選定之后將合并計劃轉(zhuǎn)為 log 日志對象推送到 log 日志齐佳,以通知所有副本開始合并私恬,與此同時,主副本還會鎖住執(zhí)行線程炼吴,對日志的接收情況進行監(jiān)聽本鸣,監(jiān)聽行為由 replication_alter_partition_sync 參數(shù)控制,默認值為 1硅蹦,當參數(shù)為 0 時荣德,不做任何等待,當參數(shù)為 1 時童芹,只等待主副本自身完成涮瞻,當為 2 時,會等待所有副本拉取完成假褪。
[zk: localhost:2181(CONNECTED) 33] ls /clickhouse/tables/01/t_replicated/log
[log-0000000001, log-0000000000]
[zk: localhost:2181(CONNECTED) 34] get /clickhouse/tables/01/t_replicated/log/log-0000000001
format version: 4
create_time: 2021-08-12 17:18:32
source replica: node2
block_id:
merge # 合并操作
202107_0_0_0 #合并的分區(qū)
into
202107_0_0_1 #合并后的分區(qū)
deduplicate: 0
part_type: Compact
4署咽、各個副本分別拉取 log 日志
當各個副本監(jiān)聽到 log-0000000001 的日志推送后,他們分別拉取本地日志生音,并推送到各自的 queue 任務隊列宁否。5、各個副本分別在本地執(zhí)行 merge
各個副本基于各自的/queue 隊列開始執(zhí)行任務缀遍,Merge 流程到此結(jié)束家淤。
2.2.3 mutation 的執(zhí)行流程
當對 ReplicatedMergeTree 執(zhí)行 alter delete 和 alter update 操作時,就會進行 mutation 的執(zhí)行流程
與 merge 類似瑟由,無論從哪個節(jié)點發(fā)起 mutation 操作絮重,都會由主副本進行相應冤寿。
- 1、推送 mutation 日志
在某個節(jié)點嘗試通過 delete 刪除數(shù)據(jù)青伤,命令如下:
alter table t_replicated delete where id = 1;
執(zhí)行之后該副本會做兩個操作督怜,
- 創(chuàng)建 mutation id
- 將 mutation 轉(zhuǎn)換為 mutationEntry 日志,并推送到 /clickhouse/tables/01/t_replicated/mutations
[zk: localhost:2181(CONNECTED) 37] ls /clickhouse/tables/01/t_replicated/mutations
[0000000000]
[zk: localhost:2181(CONNECTED) 40] get /clickhouse/tables/01/t_replicated/mutations/0000000000
format version: 1
create time: 2021-07-21 17:56:27 # 創(chuàng)建時回見
source replica: node2
block numbers count: 1
202107 1
commands: DELETE WHERE id = 1 # 刪除條件
alter version: -1
mutation 操作日志由 /clickhouse/tables/01/t_replicated/mutations 分發(fā)至各個副本
2狠角、所有副本實例各自監(jiān)聽mutation 日志
所有副本都會監(jiān)聽 /clickhouse/tables/01/t_replicated/mutations 号杠,當有新的日志節(jié)點創(chuàng)建時他們都能監(jiān)聽到,但并不是每個副本都會響應丰歌,他們會先判斷自己是否是主副本3姨蟋、由主副本實例響應 mutation 日志并推送 log 日志
主副本會響應 mutation 日志,將 mutation 日志轉(zhuǎn)換為 logEntry 日志并推送到 /log節(jié)點立帖,以通知各個副本執(zhí)行具體操作
[zk: localhost:2181(CONNECTED) 42] ls /clickhouse/tables/01/t_replicated/log
[log-0000000003, log-0000000001, log-0000000002, log-0000000000]
[zk: localhost:2181(CONNECTED) 44] get /clickhouse/tables/01/t_replicated/log/log-0000000003
format version: 4
create_time: 2021-08-12 17:56:32
source replica: node2
block_id:
drop
202107_0_0_999999999_1
4眼溶、各個副本分別拉取 log 日志
主副本推送 log 日志后,其余副本會監(jiān)聽到 log 日志節(jié)點的變化晓勇,根據(jù)日志內(nèi)容將相關(guān)操作推送到各自的/queue 隊列5堂飞、各個副本實例分別在本地執(zhí)行 mutation
各個副本會基于自己的/queue 隊列開始執(zhí)行任務,執(zhí)行結(jié)束后绑咱,mutation 流程執(zhí)行結(jié)束
2.2.4 alter 執(zhí)行流程
當 ReplicatedMergeTree 執(zhí)行 alter 操作時進行元數(shù)據(jù)修改的時候绰筛,就會進入 alter 邏輯,例如增加描融,刪除表字段等铝噩。
1、修改共享元數(shù)據(jù)
在一個節(jié)點增加一個列字段窿克,執(zhí)行之后薄榛,該節(jié)點會修改 zookeeper 內(nèi)的共享元數(shù)據(jù)節(jié)點,數(shù)據(jù)修改后让歼,節(jié)點的版本號同時提升敞恋,與此同時,該節(jié)點還會監(jiān)聽所有副本的修改完成情況谋右。2硬猫、監(jiān)聽共享元數(shù)據(jù)變更并各自執(zhí)行本地修改
共享元數(shù)據(jù)元數(shù)據(jù)更改之后,其余副本會將自身的元數(shù)據(jù)版本號與共享元數(shù)據(jù)版本號進行對比改执,如果自身元數(shù)據(jù)版本號低于共享元數(shù)據(jù)版本號啸蜜,則進行元數(shù)據(jù)更新。3辈挂、確認所有副本完成修改
當前確認所有副本均修改成功置吓,則 alter 流程結(jié)束
參考:
https://blog.csdn.net/qq_31557939/article/details/127019820
https://blog.csdn.net/weixin_44758876/article/details/123729984