客端日誌的收集、儲存和分析(二)

語言: CN / TW / HK

前言

上一節我們介紹瞭如何接收客戶端日誌及資料儲存方面ClickHouse的寫入和更新相關的知識。在寫入方面,我們提到了批量寫入,批量寫入是有利於ClickHouse處理新增資料的。但是,如果我們想保證擁有較快的查詢速度,該以怎樣的資料結構去組織資料寫入呢?這一結我們來介紹一下如何為高效的查詢組織資料寫入ClickHouse。

一、ClickHouse資料分割槽

資料分割槽就是按照一個或多個欄位,將資料放到不同的目錄中,在很多的OLAP資料庫中,都存在資料分割槽的設計,但是其它很多OLAP資料庫都沒有分割槽內小檔案自動合併的功能。ClickHouse會對分割槽內的小檔案定時進行合併,以便提高查詢效能。分割槽最常用的就是按天分割槽。在ClickHouse的MergeTree系列引擎表中,是在建立表時通過partition by指定分割槽欄位的,例如:

sql CREATE TABLE test ( event String, user_id Int64, event_time String, dt String ) ENGINE = MergeTree() partition by dt order by event 其中dt就是分割槽欄位。有了分割槽欄位之後,我們查詢資料時,就可以使用where條件通過分割槽欄位進行過濾,減小資料掃描的範圍,提高查詢效率。例如,我們只想查詢2021年09月1日到9月30日的資料量,可以執行如下sql獲取:

sql select count(1) from test where dt between '20210901' and '20210930' 下圖是分割槽的原理圖

image.png 如20210201是就一個大的分割槽,就是我們定義的dt欄位,在大分割槽中,還有很多小檔案,每個檔案都可能是一次insert的資料生成的檔案,如20210201_1_1_0、20210201_2_2_0等。
分割槽雖然能減小查詢時資料的掃描範圍,但是切記分割槽不能分的太細,比如說按照分鐘級別進行分割槽,因為MergeTree表引擎的一個分割槽對應一批檔案,分的太細,可能會造成檔案數過多,檔案數過多,在查詢時,就會掃描大量的小檔案,會產生大量的檔案定址,這無疑會增加查詢時間。再有,ClickHouse會定時合併每個分割槽中的小檔案,分割槽數過多,可能會導致ClickHouse合併小檔案的速度趕不上資料寫入生成的小檔案的速度。所以說,分割槽粒度不能太細。

二、ClickHouse MergeTree引擎一級索引

1. 一級索引使用示例

ClickHouse提供了一級索引,查詢時使用一級索引,能大幅度提高查詢效能,一級索引在建立表時通過order by關鍵字宣告,也可通過primary key宣告。如果不宣告primary key關鍵字,那麼預設情況下order by關鍵字宣告的欄位就是一級索引。示例如下:

sql CREATE TABLE heaven_eye_analyse.event_production ( event String, user_id Int64, $lib String, dt String ) ENGINE = MergeTree() partition by dt order by event 其中event就是一級索引。

下面我們來對比下使用一級索引和普通欄位的查詢時效。比較的總資料量是50億。 先來看下使用普通欄位的查詢時效

image.png

通過普通欄位$lib查詢30天資料總量,耗時15s。再來看下使用一級索引的查詢耗時

image.png 可以看到,耗時只有430ms,和使用普通欄位查詢相比,速度完全碾壓。

2.一級索引原理

接著我們介紹下ClickHouse一級索引的原理。下面是一級索引的原理圖

primary.idx、標記檔案、資料檔案的協同.png

MergeTree表中的每一列,都有兩個檔案,一個是.bin檔案,另外一個是.mrk檔案。一級索引除此之外還有一個primary.idx檔案。

.bin檔案

.bin檔案用於儲存資料。
由於同一列的資料大概率具有相似性,所以資料一般壓縮後儲存,可節省磁碟空間,但是ClickHosue的壓縮不是針對整個.bin檔案進行壓縮,而是將.bin檔案中的資料劃分為多個部分,每個部分壓縮在一起,稱為一個壓縮塊,這樣做的好處如下:比如說整個.bin檔案有1億條資料,如果是對整個檔案進行壓縮,那麼假設只用讀取其中一萬條資料,那麼需要對整個檔案進行解壓,這樣就浪費了很多時間。相對的,如果只解壓這一萬條資料所在的儲存塊,那麼效率會提升很多。
另外,每個壓縮塊中有一個元資料,元資料佔9個位元組,1個位元組表示壓縮演算法型別,4個位元組表示表示壓縮前的資料大小,4個位元組表示壓縮後的資料大小。

.mrk檔案

.mrk檔案用於描述這一列對應的.bin檔案中每個資料塊(預設每8192條資料一個間隔)的起始位置及資料在資料塊內的位置(解壓後)

primary.idx檔案

一級索引對應一個primary.idx檔案。ClickHouse MergeTree表每隔一定量的資料(預設8192條)就生成一個索引標記,對於一億條資料,使用12208行索引標記就能索引,由此來看,索引標記佔用的空間會非常小,所以索引檔案就可以常駐記憶體,加快存取速度。

primary.idx、標記檔案、資料檔案的協同

由上面的一級索引原理圖可以看出,primary.idx中的每行索引標記和索引對應列的.mrk檔案中的每個標記是一對一的關係,標記和壓縮塊根據一級索引對應的欄位壓縮前的大小,分為一對一、一對多和多對一。如果想根據一級索引欄位查詢某個範圍內的資料,可以將查詢條件和一級索引做交集,找到資料所在的區間對應的標記。舉個例子,比如說想查詢event between 5000 and 6000之間的資料,根據一級索引,發現索引4553和查詢條件有交集,然後根據索引4553找到標記1,標記1指向壓縮塊1,此時先解壓壓縮塊1,由於標記1的P2的位置是0,那麼就從解壓後的第一個元素開始,找到符合條件(event between 5000 和 6000)的資料。

總結

本節我們主要介紹ClickHouse提高查詢效率的兩個方式,即通過ClickHouse MergeTree表引擎的分割槽和一級索引存。兩種方式結合使用,可以讓我們在查詢時大幅度提高效能。
下面劃重點:
在使用分割槽時,切記分割槽不能分的太細。
在使用一級索引時,應該選擇查詢時能被經常命中的條件作為一級索引。
在知道如何高效的組織好資料儲存後,我們下一節將介紹如何基於ClickHouse做業務上的資料分析,例如典型的漏斗模型分析、業務留存分析等。