引言
在大數據時代的江湖,數據量呈爆炸式增長,如何高效地處理和分析海量數據成為了一個關鍵問題。各路英雄豪杰紛紛亮出自己的絕技,爭奪數據處理的巔峰寶座。而在這場激烈的角逐中,ClickHouse 以其“獨孤九劍”般的絕世武功,橫空出世,令群雄側目。
ClickHouse 是一個用于聯機分析處理(OLAP)的開源分布式數據管理系統。它由俄羅斯的 Yandex 公司開發,為海量數據的實時分析處理提供高效的解決方案。
今天,就讓我們一同走進 ClickHouse 的江湖,揭開它極速查詢的終極秘籍。
ClickHouse “九劍”
總決式:整體架構
從架構角度來看,數據庫至少由存儲層和查詢處理層組成。存儲層負責保存、加載和維護表數據,而查詢處理層則執行用戶查詢。與其他數據庫相比,ClickHouse 在這兩個層上都提供了創新,可實現極快的插入和選擇查詢。不同于其他大數據計算引擎(如 Spark、Presto 等)的“計算服務于存儲”,ClickHouse 自有存儲層,不依賴外部存儲,可以在存儲層為查詢計算做出很多的優化特性,即存儲服務于計算。
ClickHouse 采用 MPP(大規模并行處理)架構,集群中的每個節點都是對等的,可以獨立對外提供服務。這種架構使得 ClickHouse 能夠高效地處理分布式查詢,通過將任務并行地分散到多個服務器節點上,在每個服務器節點進行計算。
同時,ClickHouse 對主鍵預排序,數據基于列式存儲,并采用向量化引擎等方式保證了 ClickHouse 的快速查詢分析。
破劍式:列式存儲
列式存儲,被廣泛應用于大數據領域,Parquet、ORC 等文件格式都是列式存儲格式。
在存儲引擎的設計上,ClickHouse 同樣采用了基于列存儲的存儲結構。每個列的數據單獨存儲在一個文件中,這種結構使得讀取和過濾數據時可以只訪問相關的列,在很多場景中極大地降低了數據分析過程中讀取的數據量。
列存儲還為 ClickHouse 帶來另一個非常明顯的優勢就是大幅提高了數據壓縮率。由于列中的數據通常具有相似的特征,壓縮效率更高,從而大幅減少壓縮后的數據大小,極大減少了磁盤的 I/O 時間。并且,每一列都可以使用不同的壓縮算法。在實際生產中,ClickHouse 基本可以達到 8:1 的壓縮比。
在查詢過程中,ClickHouse 只解壓涉及的列數據塊,而不是解壓整個數據塊,這樣可以減少解壓縮過程中的 I/O 操作,進一步提高查詢效率。
破刀式:向量化
向量化執行不是一次處理一條數據,而是將數據分成批量(通常是固定大小的數據塊),然后一次性處理整個批次的數據。例如,一次處理1024個數據元素。
在計算引擎上,ClickHouse 首次使用向量化計算引擎。ClickHouse 利用現代 CPU 提供的 SIMD(單指令多數據)指令集進行向量化加速。SIMD 允許在一個指令中同時對多個數據進行操作,從而顯著提高了數據處理的速度。
并且,由于數據是批量處理的,數據的訪問模式更具順序性,減少了 CPU 緩存的未命中率。
因為采用了向量化計算引擎,從而使 ClickHouse 很大程度上提升了單機性能。在實際場景中,上億乃至幾十億的數據,都可以使用單機解決。符合當前大環境下的降本增效,而且,很大程度上解決了傳統大數據倉庫的效率低及成本高的問題。
特別地,受 ClickHouse 的影響,Spark、Presto、Doris、StarRocks 等都開始了向量化引擎的改造,像 Spark、Presto 的向量化引擎 Velox,甚至現在連 Flink 都開始搞起來向量化引擎。
破槍式:預排序
ClickHouse 使用類 LSM 的算法,在將數據寫入磁盤前進行排序,以保證數據在磁盤上有序。數據在寫入后定期在后臺進行 Compaction。通過類 LSM Tree 的結構,順序寫磁盤,充分利用了磁盤的吞吐能力。
ClickHouse 在建表時,需要指定主鍵及排序鍵。如果只指定排序鍵,那么主鍵會被隱式設置為排序鍵。如果同時指定了主鍵和排序鍵,則主鍵必須是排序鍵的前綴。
并且,由于數據是有序的,在設計范圍查找及排序操作時,可以用來減少磁盤讀取的數據量,進而提升查詢速度。數據的預排序是 ClickHouse 很多特性的基礎。
破鞭式:表引擎
在 ClickHouse 中,表引擎通過各自的設計和優化機制,使得 ClickHouse 能夠在不同的場景下實現高效的查詢性能,滿足各種數據分析需求。
表引擎決定了:
數據存儲的方式和位置、向何處寫入數據以及從何處讀取數據; 支持哪些查詢,以及如何支持; 并發數據訪問; 使用索引(如果有的話); 是否可以執行多線程請求; 數據復制參數;
破索式:數據類型
Clickhouse 支持 100 多種數據類型。
·基本數據類型 ·Bool:布爾類型,在內部存儲為 Uint8,true 為 1,false 為 0; ·UInt8, UInt16, UInt32, UInt64:無符號整數類型,分別占用 1 字節、2 字節、4 字節、8 字節; ·Int8, Int16, Int32, Int64:有符號整數類型,分別占用 1 字節、2 字節、4 字節、8 字節; ·Float32, Float64:浮點數類型,分別單精度和雙精度,分別占用 4 字節、8字節; ·Decimal32,Decimal64,Decimal128:高精度類型,原生方式為 Decimal(P, S); ·String:字符串類型,可變長度; ·FixedString(N):固定長度字符串類型,指定長度為 N,插入的字符串長度少于 N,則補空,對于 N,則報異常; ·日期和時間數據類型 ·Date:日期類型,以 YYYY-MM-DD 格式存儲; ·DateTime:日期時間類型,以 YYYY-MM-DD HH:MM:SS 格式存儲; ·DateTime64(N):帶有精度 N 的日期時間類型,N 為從 1 到 9 的精度值; ·復雜類型 ·Array(T):數組類型,包含元素類型 T 的數組; ·Nested:嵌套類型,支持嵌套結構; ·Tuple(T1, T2, …):元組類型,包含多個字段,字段類型可以是不同的數據類型; ·Map(K ,V):鍵值類型,映射不唯一,即一個映射可以包含兩個具有相同鍵的元素; ·Enum:枚舉類型,用來定義常量; ·聚合類型 ·AggregateFunction:聚合函數類型,具有實現定義的中間狀態,可以將其序列化為 AggregateFunction(...) 數據類型并存儲在表中,通常使用物化視圖來存儲。產生聚合函數狀態的常用方法是調用帶后綴的聚合函數 -State。將來要獲得聚合的最終結果,必須使用帶 -Merge 后綴的相同聚合函數; ·SimpleAggregateFunction:產生聚合函數值的常見方法是調用帶有 -SimpleState 后綴的聚合函數,如 min、max、sum、groupArrayArray 等。SimpleAggregateFunction 比使用相同的聚合函數具有更好的性能 AggregateFunction; ·其他數據類型 ·UUID:UUID類型,用于存儲全局唯一標識符; ·IPv4,IPv6 類型:IP類型,IPv4 基于 UInt32 封裝,IPv6 基于 FixedString(16) 封裝,包含格式檢查; ·Nullable(T):可空類型,包裝類型 T,允許存儲 NULL 值; ·LowCardinality(T):將其他數據類型的內部表示更改為字典編碼,使用字典編碼數據進行操作可顯著提高許多應用程序的 SELECT 查詢性能,一般而言字典包含少于 1 W 個不同的值,則會有更好的讀取及存儲效率,如果大于 10 W 的不同值,那么相比其他數據類型性能可能會更差; |
數據類型決定了數據在內存中的組織形式、在磁盤中存儲的持久化和序列化方式以及在計算時的處理機制。
ClickHouse 中的列 (IColumn) 事實上是一個數組,存儲某一列的一個或多個數據。ClickHouse 會將列中的數據當成整體進行處理,而不是將列中的數據一行一行地處理。
列是不可變的,任何對列的操作都會產生一個全新的對象。不可變的語義使得某些對列的操作可以并行處理,從而充分利用多核處理器。
在 ClickHouse 中,內存對齊的數據類型只保存數據數組,內存中無法對齊的數據還額外保存了一個用于定界的 offset 數組。
由于內存對齊的數據類型在存儲時不需要額外存儲數據的邊界,在計算時也不需要額外處理數據邊界,因此內存對齊的數據具有更高的存儲與計算效率。
在列式存儲中,每個列的數據單獨存儲,同一種數據類型的數據,對于數據壓縮更加友好,壓縮效率更高。(詳見《破劍式:列式存儲》章節)
數據類型的設計充分考慮了大數據場景下的性能,帶來了極高的查詢效率,但同時也對使用者提出了更高的要求,使用者必須正確了解數據特點且必須正確使用數據類型,否則可能造成內存浪費、查詢緩慢等問題。
破掌式:分片與副本策略
在 ClickHouse 中,為了提升查詢性能及增加數據容錯性,分別在水平方向和垂直方向上劃分為分片(shard)及副本(replica)。
在分布式模式下,ClickHouse 會將數據在水平方向上分為多個分片,并且分布到不同節點上,不同分片間的數據不同。分片的目的主要是為了提升查詢性能,方便多線程及分布式查詢。在分布式查詢時,按照分片數量拆分成若干個對本地表的子查詢,然后依次查詢每個分片的數據,再合并匯總返回。
在數據寫入時,需要考慮如何均勻地寫入至各個分片,以及在數據查詢時,需要考慮如何路由到每個分片,并計算匯總形成結果集,這是分片就需要結合 Distributed 表引擎一起使用。在集群配置分片規則時,每一個分片會配置一個權重,分片權重會影響數據在分片中的傾斜程度,分片權重越大,被寫入的數據越多。在創建 Distributed 表時,需要指定 sharding_key 即分片鍵,它必須是一個整數類型的值。分片鍵的分片策略一般有以下幾種:
?固定字段:按照用于指定的字段的余數進行劃分,字段需要是整數類型;
?隨機函數:按照隨機數進行劃分;
?hash 函數:按照指定字段的 hash 值進行劃分;
?
ClickHouse 會將數據在垂直方向上分為多個副本,即同一個數據可以在不同的節點上存儲,并且數據副本間的每份數據相同,通過增加數據存儲容易來防止數據丟失。可以在任意一個副本上執行 INSERT 、ALTER 操作,效果是相同的,都會借助 Zookeeper 的協同能力被分發至每個副本以本地形式執行。
?
在數據查詢時,一個表的一個分片會擁有多個副本,那么這時會存在分布式表引擎選擇哪個副本計算的問題。ClickHouse 使用負載均衡算法從多個副本中選擇一個,算法是由 load_balancing 參數控制,并提供了以下選擇副本的算法策略:
?Random(默認):會對每個副本計算錯誤數,查詢將發送到錯誤最少的副本,如果多個副本同時擁有同樣最小錯誤數,則隨機選擇一個;
?Nearest hostname(最近主機):系統同樣會對每個副本計算錯誤數,每 5 分鐘錯誤數會除以 2,同樣會選擇錯誤最少的副本,如果有多個副本有最小的錯誤數,則會將查詢發送到配置文件中的服務器主機名同當前分布式表所在節點的主機名最相似的副本;
?Hostname levenshtein distance(主機名編輯):類似 Nearest hostname,但它是以編輯距離的方式比較主機名;
?In Order(排序):具有相同錯誤數的副本將按照配置中指定的順序進行訪問,當確切知道哪個副本更可取時,此方法是合適的。
?First or Random(第一個或者隨機):此算法選擇集合中第一個副本,如果第一個副本不可用,則隨機選擇副本。
?Round Robin(循環遍歷):此算法在具有相同錯誤數的副本中使用循環遍歷的策略選擇。
破箭式:索引設計
在 ClickHouse 中,索引是優化查詢性能的關鍵部分。ClikcHouse 中主要支持是稀疏索引和跳數索引。
在 ClickHouse 中,主鍵索引采用稀疏索引實現,僅對每個顆粒(index_granularity,默認為 8192 行為一個顆粒)記錄一個索引條目(mark),索引條目存儲的是顆粒(index_granularity)第一行的主鍵列值,存儲到單獨的索引文件(primary.idx),并在標記文件({列}.mrk)存儲每個顆粒到文件物理位置的映射。通過索引文件和標記文件,才能共同確定一個數據所在的文件位置。在查詢時,首先通過索引確認數據所在的個顆粒,然后依據標記確認個顆粒所在的物理地址,最后通過物理地址從硬盤上讀取數據。
這種索引設計允許主鍵索引很小,必須完全適合加載到內存,同時仍可顯著加快查詢執行的時間,尤其是對數據分析中常見的范圍查找。其核心邏輯是通過索引降低需要讀取的數據量,從而減少磁盤 I/O 時間,達到加速查詢的效果。
除了主鍵索引,ClickHouse 還支持跳數索引。跳數索引允許在查詢時跳過沒有匹配值的數據塊,減少掃描數據范圍。主要的跳數索引有 minmax、set、布隆過濾器三種類型。
minmax 類型的跳數索引,存儲每個塊的索引表達式的最大值及最小值。這種類型非常適合傾向于按值松散排序的列,且只能與標量或者元組表達式一起正確工作(永遠不會應用于返回數組或 MAP 數據類型的表達式),通常是查詢處理過程中成本最低的索引類型。
眾所周知,布隆過濾器允許以極小的誤差來高效地判斷一個元素是否存在于集合中。由于布隆過濾器可以更有效地處理大量離散值的測試,因此適用于產生更多值進行測試的條件表達式,比如數組和 MAP,以及對文本搜索也很多有用,特別是沒有單詞分隔符的語言(比如中文)。
通常,set 索引和布隆過濾器索引都是無序的,因此不適合用于范圍查找。相反,minmax 索引特別適合于范圍判斷,因為確定范圍是否相交是非常快的。
破氣式:計算引擎
從功能和整體架構上講,ClickHouse 的計算引擎與其他數據庫的計算引擎并沒有很大的不同。功能都是將可描述的結構化查詢語言(SQL)轉化翻譯為可以執行的物理計劃以及執行計算并獲得計算結果,而整體架構都有包含 SQL 解析、翻譯解釋、計算執行等部分。
從實現方面,ClickHouse 同樣采用了多線程及分布式查詢,成為其高性能和高擴展性的關鍵。通過線程級并行的方式提升性能,利用多核 CPU 的計算能力;通過采用分布式架構,支持分片和副本,通過將數據分布到多個節點實現存儲和計算的擴展。
特別地,ClickHouse 的計算引擎是相當被詬病的。ClickHouse 沒有成熟的執行計劃優化器,并且對 JOIN 的支持相比其他數據庫及計算引擎相當薄弱。所以,有人認為 ClickHouse 的計算引擎缺乏優化及對分布式的支持,就是個半成品。
?
最后
通過上述特點,我們可以清楚地看到,ClickHouse 的高性能查詢能力并非偶然,而是其架構設計和技術創新的必然結果。無論是列式存儲、向量化執行引擎,還是數據壓縮技術、分布式架構,這些特點共同作用,使得 ClickHouse 在處理大規模數據分析時表現出色,在大數據的江湖中獨步天下。
?
參考資料
陳峰 《Clickhouse 性能之巔:從架構設計解讀性能之謎》 機械工業出版社
朱凱 《ClickHouse 原理解析與應用實踐》 機械工業出版社
?ClickHouse官網?
?《ClickHouse 教程》?
?ClickHouse 的副本與分片?
審核編輯 黃宇
-
數據庫
+關注
關注
7文章
3922瀏覽量
66149 -
大數據
+關注
關注
64文章
8959瀏覽量
140088
發布評論請先 登錄
青銅劍技術亮相第九屆電氣化交通前沿技術論壇
10K-100K B3950-B3435NTC熱敏電阻快速查詢對照表
IP地址查詢技術

ClickHouse:強大的數據分析引擎

九章云極DataCanvas公司「算力包」產品璀璨亮相2024中國算力大會!

根據ip地址查網頁怎么查詢?

常見的IP地址查詢技術

《七劍下天山》之“七劍利刃”:“新一代”漏洞掃描管理系統
供應鏈場景使用ClickHouse最佳實踐

評論