作者:耿宏宇
1 表引擎簡述
1.1 官方描述
MergeTree 系列的引擎被設計用于插入極大量的資料到一張表當中,資料可以以資料片段的形式一個接著一個的快速寫入,資料片段在后臺按照一定的規則進行合并,相比在插入時不斷修改(重寫)已存盤的資料,這種策略會高效很多,
ReplacingMergeTree 引擎和 MergeTree 的不同之處在于它會洗掉排序鍵值相同的重復項,
資料的去重只會在資料合并期間進行,合并會在后臺一個不確定的時間進行,因此你無法預先作出計劃,有一些資料可能仍未被處理,盡管你可以呼叫 OPTIMIZE 陳述句發起計劃外的合并,但請不要依靠它,因為 OPTIMIZE 陳述句會引發對資料的大量讀寫,
1.2 本地表語法
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE = ReplacingMergeTree([ver])
[PARTITION BY expr]
[PRIMARY KEY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]
[SETTINGS name=value, ...]
引數介紹
-
ver — 版本列,型別為 UInt*, Date 或 DateTime,可選引數,
在資料合并的時候,ReplacingMergeTree 從所有具有相同排序鍵的行中選擇一行留下:
1.如果 ver 列未指定,保留最后一條,
2.如果 ver 列已指定,保留 ver 值最大的版本, -
PRIMARY KEY expr 主鍵,如果要 選擇與排序鍵不同的主鍵,在這里指定,可選項,
默認情況下主鍵跟排序鍵(由 ORDER BY 子句指定)相同, 因此,大部分情況下不需要再專門指定一個 PRIMARY KEY 子句, -
SAMPLE BY EXPR 用于抽樣的運算式,可選項
-
PARTITION BY expr 磁區鍵
-
ORDER BY expr 排序鍵
1.3 磁區表語法
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE = Distributed(cluster, database, table[, sharding_key[, policy_name]])
[SETTINGS name=value, ...]
引數介紹
- cluster 集群名
- table 遠程資料表名
- sharding_key 分片規則
- policy_name 規則名,它會被用作存盤臨時檔案以便異步發送資料
2 鍵的概念
Clickhouse的部署,分為單機模式和集群模式,還可以開啟副本,兩種模式,資料表在創建語法、創建步驟和后續的使用方式上,存在一定的差異,
在定義表結構時,需要指定不同的鍵,作用如下,
分片:所有分片節點的權重加和得到S,可以理解為sharing動作取模的依據,權重X=W/S,分片鍵 Mod S 得到的值,與哪個分片節點匹配,則會寫入哪個分片,不同分片可能存在于不同的集群節點,即便不同分片在同一節點,但ck在merge時,維度是同一磁區+同一分片,這是物理檔案的合并范圍,
如果我們權重分別設定為1,2,3 那么總權重是6,那么總區間就是[0,6),排在shard配置第一位的node01,權重占比為1/6,所以屬于區間[0,1),排在shard配置第二位的node02,占比2/6,所以區間為[1,3),至于最后的node03就是[3,6).所以如果rand()產生的數字除以6取余落在哪個區間,資料就會分發到哪個shard,通過權重配置,可以實作資料按照想要的比重分配.
3 分片的作用
3.1 分片規則
在分布式模式下,ClickHouse會將資料分為多個分片,并且分布到不同節點上,不同的分片策略在應對不同的SQL Pattern時,各有優勢,ClickHouse提供了豐富的- - - sharding策略,讓業務可以根據實際需求選用,
- random隨機分片:寫入資料會被隨機分發到分布式集群中的某個節點上,
- constant固定分片:寫入資料會被分發到固定一個節點上,
- column value分片:按照某一列的值進行hash分片,
- 自定義運算式分片:指定任意合法運算式,根據運算式被計算后的值進行hash分片,
3.2 類比
以MySQL的分庫分表場景為例:
- 2個庫,1個表分4個子表,采用一主一從模式,
- db01包含tab-1和tab-2,db-2包含tab-3和tab-4;
- 在配置sharding規則時,需要設定分庫規則、分表規則;
一條記錄寫入時,會計算它要寫入哪個表、哪個庫,寫入的記錄會被從節點復制,
這個MySQL的例子,與CK的磁區+分片+副本在邏輯上基本一致,磁區理解為資料寫入哪個表,分片可以理解為資料寫入哪個庫,副本則是從節點的拷貝,
3.3 分片、磁區與副本
Clickhouse分片是集群模式下的概念,可以類比MySQL的Sharding邏輯,副本是為了解決Sharing方案下的高可用場景所存在的,
下圖描述了一張Merge表的各類鍵的關系,也能反映出一條記錄的寫入程序,
4 資料合并限制
理清了磁區與分片的概念,也就明白CK的資料合并,為什么要限制相同磁區、相同分片,因為它們影響資料的存盤位置,merge操作只能針對相同物理位置(磁區目錄)的資料進行操作,而分片會影響資料存盤在哪個節點上,
一句話,使用CK的ReplacingMergeTree引擎的去重特性,期望去重的資料,必須滿足擁有 相同排序鍵、同一磁區、同一分片,
接下來針對這一要求,在資料上進行驗證,
5 資料驗證
5.1 場景設定
這里是要驗證上面的結論,“期望去重的資料,必須滿足在相同排序鍵、同一磁區、同一分片”;
首先擁有相同排序鍵才會在merge操作時進行判斷為重復,因此保證測驗資料的排序鍵相同;剩余待測驗場景則是磁區與分片,
由此進行場景設定:
- 相同記錄,能夠寫入同一磁區、同一分片
- 相同記錄,能夠寫入同一磁區,不同分片
- 相同記錄,能夠寫入不同磁區,不同分片
- 相同記錄,能夠寫入不同磁區、相同分片
再疊加同步寫入方式: - 直接寫本地表
- 直接寫分布式表
補充:磁區鍵與分片鍵,是否必須相同?
5.2 第一天測驗
場景1: 相同記錄,能夠寫入同一磁區、同一分片
一次執行3條插入,插入本地表
[main_id=101,sku_id=SKU0002;barnd_code=BC01,BC02,BC03]
select * from test_ps.sku_detail_same_partition_same_shard_all;
分三次執行,插入本地表
[main_id=101,sku_id=SKU0001;barnd_code=BC01,BC02,BC03]
select * from test_ps.sku_detail_same_partition_same_shard_all;
分三次執行,插入分布式表
[main_id=101,sku_id=SKU0001;barnd_code=BC001,BC002,BC003]
select * from test_ps.sku_detail_same_partition_same_shard_all;
select * from test_ps.sku_detail_same_partition_same_shard_all final;
結論1
1.采用分布式表插入資料,保證分片鍵、磁區鍵的值相同,才能保證merge去重成功
排除本地表插入場景
2.采用本地表插入資料,在分片鍵、磁區鍵相同的情況下,無法保證merge去重
- 在一個session(一次提交)里面包含多個記錄,直接會得到一條記錄,插入程序去重
在第一次insert時,準備的3條insert陳述句是一次執行的,查詢后只有1條記錄, - 在多個session(多次提交)記錄,不會直接去重,但有可能寫到不同集群節點,導致無法去重
分3次執行3條insert陳述句,查詢后有3條記錄,且通過final查詢后有2條記錄,合并去重的那2條記錄是寫入在同一集群節點,【參考SKU0002的執行結果】
后面直接驗證插入分布式表場景,
場景2:相同記錄,能夠寫入同一磁區,不同分片
- 分片鍵采用的rand()方式,隨機生成,
分三次執行,插入分布式表
[main_id=103,sku_id=SKU0003;barnd_code=BC301,BC302,BC303]
檢查資料插入狀態
select * from test_ps.sku_detail_same_partition_diff_shard_all where main_id =103 ;
檢查merge的去重結果
select * from test_ps.sku_detail_same_partition_diff_shard_all final where main_id =103 ;
分五次執行,插入分布式表
[main_id=104,sku_id=SKU0004;barnd_code=BC401,BC402,BC403,BC404,BC405]
檢查資料插入狀態
select * from test_ps.sku_detail_same_partition_diff_shard_all where main_id =104 ;
檢查merge的去重結果
select * from test_ps.sku_detail_same_partition_diff_shard_all final where main_id =104 ;
結論2
采用分布式表插入資料,保證磁區鍵的值相同、分片鍵的值隨機,無法保證merge去重
- 如果插入記錄時,通過rand()生成的數字取模后的值一樣,很幸運最終可以merge去重成功
- 如果插入記錄時,通過rand()生成的數字取模后的值不一樣,最終無法通過merge去重
場景3:相同記錄,能夠寫入不同磁區,不同分片
- 分片鍵采用的rand()方式,隨機生成;
- 磁區鍵為了方便測驗,采用創建時間,
分五次執行,插入分布式表
[main_id=105,sku_id=SKU0005;barnd_code=BC501,BC502,BC503,BC504,BC505]
檢查資料插入狀態
select * from test_ps.sku_detail_diff_partition_diff_shard_all where main_id =105 ;
檢查merge的去重結果
select * from test_ps.sku_detail_diff_partition_diff_shard_all final where main_id =105;
結論3
采用分布式表插入資料,磁區鍵的值與排序鍵不一致、分片鍵的值隨機,無法保證merge去重
- 按當前測驗結果,雖然create_time都不相同,也就是磁區不同,也發生了資料合并
- 資料發生合并,但結果并不是完全按排序鍵進行合并的
場景4:相同記錄,能夠寫入 不同磁區、相同分片
- 分片鍵采用main_id;
- 磁區鍵為了方便測驗,采用創建時間,
分六次執行,插入分布式表
[main_id=106,sku_id=SKU0006;barnd_code=BC601,BC602,BC603,BC604,BC605,BC606]
檢查資料插入狀態
select * from test_ps.sku_detail_diff_partition_same_shard_all where main_id =106 ;
檢查merge的去重結果
select * from test_ps.sku_detail_diff_partition_same_shard_all final where main_id =106;
此場景,經過第二天檢索,資料并沒有進行merge,而是用final關鍵字依然能檢索出去重后的結果,也就是說final關鍵字只是在記憶體中進行去重,由于所在磁區不同,檔案是沒有進行merge合并的,也就沒有去重,反觀相同磁區、相同分片的資料表,資料已經完成了merge合并,普通檢索只能得到一條記錄,
結論4
采用分布式表插入資料,磁區鍵的值與排序鍵不一致、分片鍵的值固定,無法實作merge去重
5.3 第二天檢查
以下均采用普通查詢,發現如下情況
- 分片不同的表,其資料沒有合并
- 分片相同、磁區不同的沒有合并
- 分片相同、磁區相同的已經完成了合并
select * from test_ps.sku_detail_same_partition_same_shard_all;
select * from test_ps.sku_detail_same_partition_diff_shard_all;
select * from test_ps.sku_detail_diff_partition_diff_shard_all;
select * from test_ps.sku_detail_diff_partition_same_shard_all;
6 總結
根據測驗結果,在不同場景下的合并情況:
- 如果資料存在在相同分片,且相同磁區,絕對可以實作合并去重,
- 如果資料存盤在不同分片,不同磁區,將不會進行合并去重,
- 如果資料存盤在不同分片,但同一分片內保證在相同磁區,會進行此分片下的merge去重,
- 如果資料存在在相同分片,但不同磁區,不會進行merge去重,但通過final關鍵字可以在CK記憶體中對相同磁區、相同分片的資料進行去重,
在Clickhouse的ReplacingMergeTree進行merge操作時,是根據排序鍵(order by)來識別是否重復、是否需要合并,而磁區和分片,影響的是資料的存盤位置,在哪個集群節點、在哪個檔案目錄,那么最終ReplacingMergeTree表引擎在合并時,只會在當前節點、且物理位置在同一表目錄下的資料進行merge操作,
最后,我們在設計表時,如果期望利用到ReplacingMergeTree自動去重的特性,那么必須使其存盤在相同磁區、相同分片下; 而在設定磁區鍵、分片鍵時,二者不要求必須相同,但必須穩定,穩定的含義是入參相同出參必須相同,
?
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/540489.html
標籤:其它
上一篇:華為云解鎖云原生資料庫發展新動能
下一篇:MySQL-執行計劃
