客端日誌的收集、存儲和分析(二)
前言
上一節我們介紹瞭如何接收客户端日誌及數據存儲方面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'
下圖是分區的原理圖
如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億。 先來看下使用普通字段的查詢時效
通過普通字段$lib查詢30天數據總量,耗時15s。再來看下使用一級索引的查詢耗時
可以看到,耗時只有430ms,和使用普通字段查詢相比,速度完全碾壓。
2.一級索引原理
接着我們介紹下ClickHouse一級索引的原理。下面是一級索引的原理圖
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做業務上的數據分析,例如典型的漏斗模型分析、業務留存分析等。