在 Doris 中,數據都以表(Table)的形式進行邏輯上的描述
名詞解釋
- 數據分布:數據分布是將數據划分為子集, 按一定規則, 均衡地分布在不同節點上,以期最大限度地利用集群的並發性能
- 短查詢:short-scan query,指掃描數據量不大,單機就能完成掃描的查詢
- 長查詢:long-scan query,指掃描數據量大,多機並行掃描能顯著提升性能的查詢
數據分布概覽
常見的四種數據分布方式有:(a) Round-Robin、(b) Range、(c) List和(d) Hash (DeWitt and Gray, 1992)。如下圖所示:
其中:
- Round-Robin: 以輪轉的方式把數據逐個放置在相鄰節點上。
- Range: 按區間進行數據分布,圖中區間[1-3],[4-6]分別對應不同Range。
- List: 直接基於離散的各個取值做數據分布,性別、省份等數據就滿足這種離散的特性。每個離散值會映射到一個節點上,不同的多個取值可能也會映射到相同節點上。
- Hash: 按哈希函數把數據映射到不同節點上。
為了更靈活地划分數據,現代分布式數據庫除了單獨采用上述四種數據分布方式之外,也會視情況采用組合數據分布。常見的組合方式有Hash-Hash、Range-Hash、Hash-List。
分區(Partition)與分桶(Bucket)
在 Doris 的存儲引擎規則:
- 用戶數據首先被划分成若干個分區(Partition),划分的規則通常是按照用戶指定的分區列進行范圍划分,比如按時間划分。
- 而在每個分區內,數據被進一步的按照Hash的方式分桶,分桶的規則是要找用戶指定的分桶列的值進行Hash后分桶。每個分桶就是一個數據分片(Tablet),也是數據划分的最小邏輯單元。
-
Partition 可以視為是邏輯上最小的管理單元。數據的導入與刪除,都可以或僅能針對一個 Partition 進行。
- Tablet直接的數據是沒有交集的,獨立存儲的。Tablet也是數據移動、復制等操作的最小物理存儲單元。
DorisDB數據分布
DorisDB使用先分區后分桶的方式, 可靈活地支持支持二種分布方式:
- Hash分布: 不采用分區方式, 整個table作為一個分區, 指定分桶的數量.
- Range-Hash的組合數據分布: 即指定分區數量, 指定每個分區的分桶數量.
采用Hash分布的建表語句:
采用Range-Hash組合分布的建表語句
DorisDB中Range分布,被稱之為分區,用於分布的列也被稱之為分區列,上圖中的event_day就是分區列。Hash分布,則被稱之為分桶,用於分布的列也被稱之為分桶列,如上圖中分桶列都是site_id.
Range分區可動態添加和刪減,上圖中如果新來了隸屬於新月份的數據,就可以添加新分區。Hash分桶一旦確定,分桶數也就隨之固定,不能再進行調整。
分區列如何選擇
分區的主要作用是將整個分區作為管理單位, 選擇存儲策略, 比如副本數, 冷熱策略和存儲介質等等。
- 大多數情況下,近期的數據被查詢的可能性更大。將最近的數據放在一個分區之內,這樣可以通過DorisDB的分區裁剪功能,最大限度地減少掃描數據量,從而提高查詢性能。
- 同時,DorisDB支持在一個集群內使用多種存儲介質(SATA/SSD)。用戶可以將最新數據所在的分區放在SSD上,利用SSD的隨機讀寫性能來提高查詢性能。而老的數據可以放在SATA盤上,以節省數據存儲的成本。
- 在實際應用中,用戶一般選取時間列作為分區鍵,具體划分的粒度視數據量而定,單個分區原始數據量建議維持在100G以內。
分桶列如何選擇
DorisDB采用Hash算法作為分桶算法:
- 同一分區內, 分桶鍵的哈希值相同的數據形成(Tablet)子表, 子表多副本冗余存儲,
- 子表副本在物理上由一個單獨的本地存儲引擎管理, 數據導入和查詢最終都下沉到所涉及的子表副本上, 同時子表也是數據均衡和恢復的基本單位.
上圖中,site_access采用site_id作為分桶鍵, 這里選用site_id字段作為分桶鍵的原因在於,針對site_access表的查詢請求,基本上都以站點作為查詢過濾條件。采用site_id作為分桶鍵,可以在查詢時裁剪掉大量無關分桶。
如下圖中的查詢,可以裁剪掉10個bucket中的9個,只需要掃描site_access表的1/10的數據。
但是存在這樣一種情況,假設site_id分布十分不均勻,大量的訪問數據是關於少數網站的(冪律分布, 二八規則)。如果用戶依然采用上述分桶方式,數據分布會出現嚴重的數據傾斜, 導致系統局部的性能瓶頸。這個時候,用戶需要適當調整分桶的字段,以將數據打散,避免性能問題。如下圖5中,可以采用site_id、city_code組合作為分桶鍵,將數據划分得更加均勻。
上面兩種模式的選取是建表過程中經常需要面對的問題,采用site_id的分桶方式對於短查詢十分有利,能夠減少節點之間的數據交換,提供集群整體性能;采用site_id、city_code組合做分桶鍵的模式對於長查詢有利,能夠利用分布式集群的整體並發性能,提高吞吐。用戶在實際使用中,可以依據自身的業務特點進行相應模式的選擇。
分桶數如何確定
在DorisDB系統中,分桶是實際物理文件組織的單元。數據在寫入磁盤后,就會涉及磁盤文件的管理。一般而言,我們不建議分桶數據過大或過小,盡量適中會比較妥當。
- 根據經驗而言,一般每個分桶的數據不建議超過10G,此處的10G指代的是原始數據。考慮到壓縮比,壓縮后磁盤上每個分桶數據文件大小在4~5G左右。這種模式在多數情況下足以滿足業務需求。
- 建議用戶根據集群規模的變化,建表時調整分桶的數量。集群規模變化,主要指節點數目的變化。假設現有100G原始數據,依照上述標准,可以建10個分桶。但是如果用戶有20台機器,那么可以縮小每個分桶的數據量,加大分桶數。
最佳實踐
對於DorisDB而言,分區和分桶的選擇是非常關鍵的。在建表時選擇好的分區分桶列,可以有效提高集群整體性能。當然,在使用過程中,也需考慮業務情況,根據業務情況進行調整。以下是針對特殊應用場景下,對分區和分桶選擇的一些建議:
- 數據傾斜:業務方如果確定數據有很大程度的傾斜,那么建議采用多列組合的方式進行數據分桶,而不是只單獨采用傾斜度大的列做分桶。
- 高並發:分區和分桶應該盡量覆蓋查詢語句所帶的條件,這樣可以有效減少掃描數據,提高並發。
- 高吞吐:盡量把數據打散,讓集群以更高的並發掃描數據,完成相應計算。
動態分區管理
在很多實際應用場景中,數據的時效性很重要,需要為新達到數據創建新分區, 刪除過期. DorisDB的動態分區機制可以實現分區rollover: 對分區實現進行生命周期管理(TTL),自動增刪分區,減少用戶的使用心智負擔。
創建支持動態分區的表
圖中建表語句中通過指定PEROPERTIES來完成動態分區策略的配置。配置項可以描述如下:
- dynamic_partition.enable : 是否開啟動態分區特性,可指定為 TRUE 或 FALSE。如果不填寫,默認為 TRUE。
- dynamic_partition.time_unit : 動態分區調度的粒度,可指定為 DAY/WEEK/MONTH。
- dynamic_partition.start: 動態分區的開始時間。以當天為基准,超過該時間范圍的分區將會被刪除。如果不填寫,則默認為Integer.MIN_VALUE 即 -2147483648
- 指定為 DAY 時,分區名后綴需為yyyyMMdd,例如20200325。上圖 就是一個按天分區的例子,分區名的后綴滿足yyyyMMdd
- 指定為 WEEK 時,分區名后綴需為yyyy_ww,例如2020_13代表2020年第13周
- 指定為 MONTH 時,動態創建的分區名后綴格式為 yyyyMM,例如 202003
- dynamic_partition.end: 動態分區的結束時間。 以當天為基准,會提前創建N個單位的分區范圍
- dynamic_partition.prefix: 動態創建的分區名前綴
- dynamic_partition.buckets: 動態創建的分區所對應的分桶數量
上圖中創建了一張表,並同步開啟動態分區特性。圖中分區的區間為當前時間的前后3天,總共6天。假設當前時間為2020-03-25為例,在每次調度時,會刪除分區上界小於 2020-03-22 的分區,同時在調度時會創建今后3天的分區。調度完成之后,新的分區會是下列列表
調度的時機依賴於FE的配置,FE的常駐線程會根據 dynamic_partition_enable 和 dynamic_partition_check_interval_seconds 兩個參數來控制。每次調度時,讀取動態分區表的屬性,以此判斷是否增加/刪除分區。
語法:
1、查看表當前的分區:動態分區表運行過程中,會不斷地自動增減分區,可以通過下列命令查看當前的分區情況
- SHOW PARTITIONS FROM site_access;
2、修改表的分區屬性:態分區的屬性可以修改,例如需要起/停動態分區的功能,可以通過ALTER TABLE來完成。
- ALTER TABLE site_access SET("dynamic_partition.enable"="false");
- 注意:依照相同語句,也可以相應的修改其他屬性。
批量創建和修改分區
該功能在1.16版本中添加
1、建表時批量創建日期分區:用戶可以通過給出一個START值、一個END值以及一個定義分區增量值的EVERY子句批量產生分區。其中START值將被包括在內而END值將排除在外。
這樣DorisDB便會自動創建如下等價的分區
當前分區鍵僅支持日期類型和整數類型,分區類型需要與EVERY里的表達式匹配。
當分區鍵為日期類型的時候需要指定INTERVAL關鍵字來表示日期間隔,目前日期僅支持day、week、month、year,分區的命名規則同動態分區一樣。
2、建表時批量創建數字分區
當分區鍵為整數類型時直接使用數字進行分區,注意分區值需要使用引號引用,而EVERY則不用引號,如下
上面的語句將產生如下分區:
3、建表后批量創建分區
與建表時批量創建分區類似,DorisDB也支持通過ALTER語句批量創建分區。通過指定ADD PARITIONS關鍵字,配合START和END以及EVERY的值來創建分區。
小結:
1、Table: 在 Doris 中,數據都以表(Table)的形式進行邏輯上的描述
2、DorisDB的數據分布:使用先分區后分桶
- 分區:主要作用是將整個分區作為管理單位, 選擇存儲策略, 比如副本數, 冷熱策略和存儲介質。僅支持日期類型和整數類型。可動態調整
- 分桶:分桶是實際物理文件組織的單元。主要作用讓數據均勻分布,防止出現數據熱點。 不可動態調整。同一分區內, 分桶鍵的哈希值相同的數據形成(Tablet)子表。
3、Table (邏輯描述) -- > Partition(分區:管理單元) --> Bucket(分桶:存儲,每個分桶就是一個數據分片:Tablet,數據划分的最小邏輯單元。豈稱為子表) ,如下圖:
4、RANGE分區(partition): RANGE分區用於將數據划分成不同區間, 邏輯上可以理解為將原始表划分成了多個子表。 業務上,多數用戶會選擇采用按時間進行partition, 讓時間進行partition有以下好處:
- 可區分冷熱數據
- 可用上DorisDB分級存儲(SSD + SATA)的功能
- 按分區刪除數據時,更加迅速
5、HASH分桶(bucket): 根據hash值將數據划分成不同的bucket
- 建議采用區分度大的列做分桶, 避免出現數據傾斜
- 為方便數據恢復, 建議單個bucket的size不要太大, 保持在10GB左右, 所以建表或增加partition時請合理考慮buckets數目, 其中不同partition可指定不同的buckets數。
- random分桶的方式不建議采用,建表時請指定明確的hash分桶列。
參考資料
- https://www.kancloud.cn/dorisdb/dorisdb/2142135
- https://www.jianshu.com/p/d3742af8ecce
- https://www.yuque.com/zailushang-j5dyp/wn32ln/btgzby
- https://blog.csdn.net/kaede1209/article/details/112243447
- http://doris.apache.org/master/zh-CN/getting-started/data-partition.html
- https://blog.bcmeng.com/post/doris-colocate-join.html