ClickHouse 原理 - ClickHouse 存算分離架構探索

背景

ClickHouse 作爲開源 OLAP 引擎,因其出色的性能表現在大數據生態中得到了廣泛的應用。區別於 Hadoop 生態組件通常依賴 HDFS 作爲底層的數據存儲,ClickHouse 使用本地盤來自己管理數據,官方推薦使用 SSD 作爲存儲介質來提升性能。但受限於本地盤的容量上限以及 SSD 盤的價格,用戶很難在容量、成本和性能這三者之間找到一個好的平衡。JuiceFS 的某個客戶近期就遇到了這樣的難題,希望將 ClickHouse 中的溫冷數據從 SSD 盤遷移到更大容量、更低成本的存儲介質,更好地支撐業務查詢更長時間數據的需求。

JuiceFS 是基於對象存儲實現並完全兼容 POSIX 的開源分佈式文件系統,同時 JuiceFS 的數據緩存特性可以智能管理查詢熱點數據,非常適合作爲 ClickHouse 的存儲系統,下面將詳細介紹這個方案。

MergeTree 存儲格式簡介

在介紹具體方案之前先簡單瞭解一下 MergeTree 的存儲格式。MergeTree 是 ClickHouse 最主要使用的存儲引擎,當創建表時可以通過 PARTITION BY 語句指定以某一個或多個字段作爲分區字段,數據在磁盤上的目錄結構類似如下形式:

1$ ls -l /var/lib/clickhouse/data/<database>/<table>
2drwxr-xr-x  2 test  test    64B Mar  8 13:46 202102_1_3_0
3drwxr-xr-x  2 test  test    64B Mar  8 13:46 202102_4_6_1
4drwxr-xr-x  2 test  test    64B Mar  8 13:46 202103_1_1_0
5drwxr-xr-x  2 test  test    64B Mar  8 13:46 202103_4_4_0
6

以 202102_1_3_0 爲例,202102 是分區的名稱,1 是最小的數據塊編號,3 是最大的數據塊編號,0 是 MergeTree 的深度。可以看到 202102 這個分區不止一個目錄,這是因爲 ClickHouse 每次在寫入的時候都會生成一個新的目錄,並且一旦寫入以後就不會修改(immutable)。每一個目錄稱作一個「part」,當 part 逐漸變多以後 ClickHouse 會在後臺對多個 part 進行合併(compaction),通常的建議是不要保留過多 part,否則會影響查詢性能。

每個 part 目錄內部又由很多大大小小的文件組成,這裏面既有數據,也有一些元信息,一個典型的目錄結構如下所示:

 1$ ls -l /var/lib/clickhouse/data/<database>/<table>/202102_1_3_0
 2-rw-r--r--  1 test  test     ?? Mar  8 14:06 ColumnA.bin
 3-rw-r--r--  1 test  test     ?? Mar  8 14:06 ColumnA.mrk
 4-rw-r--r--  1 test  test     ?? Mar  8 14:06 ColumnB.bin
 5-rw-r--r--  1 test  test     ?? Mar  8 14:06 ColumnB.mrk
 6-rw-r--r--  1 test  test     ?? Mar  8 14:06 checksums.txt
 7-rw-r--r--  1 test  test     ?? Mar  8 14:06 columns.txt
 8-rw-r--r--  1 test  test     ?? Mar  8 14:06 count.txt
 9-rw-r--r--  1 test  test     ?? Mar  8 14:06 minmax_ColumnC.idx
10-rw-r--r--  1 test  test     ?? Mar  8 14:06 partition.dat
11-rw-r--r--  1 test  test     ?? Mar  8 14:06 primary.idx
12
13

其中比較重要的文件有:

基於 JuiceFS 的存算分離方案

因爲 JuiceFS 完全兼容 POSIX,所以可以把 JuiceFS 掛載的文件系統直接作爲 ClickHouse 的磁盤來使用。這種方案下數據會直接寫入 JuiceFS,結合爲 ClickHouse 節點配置的緩存盤,查詢時涉及的熱數據會自動緩存在 ClickHouse 節點本地。整體方案如下圖所示。

ClickHouse 在寫入時會產生大量的小文件,因此如果寫入壓力較大這個方案對寫入和查詢性能都會有一定影響。建議在寫入數據時增大寫入緩存,儘量一次寫入更多數據來避免這個小文件過多的問題。最簡單的做法是使用 ClickHouse 的 Buffer 表,基本上不需要修改應用代碼就可以解決小文件過多的問題,適合當 ClickHouse 宕機時允許少量數據丟失的場景。這樣做的好處是存儲和計算完全分離,ClickHouse 節點完全無狀態,如果節點故障可以很快恢復,不涉及任何數據拷貝。未來可以讓 ClickHouse 感知到底層存儲是共享的,實現自動的無數據拷貝遷移。

同時由於 ClickHouse 通常應用在實時分析場景,這個場景對於數據實時更新的要求比較高,在分析時也需要經常性地查詢新數據。因此數據具有比較明顯的冷熱特徵,即一般新數據是熱數據,隨着時間推移歷史數據逐漸變爲冷數據。利用 ClickHouse 的存儲策略(storage policy)來配置多塊磁盤,通過一定條件可以實現自動遷移冷數據到 JuiceFS。整體方案如下圖所示。

這個方案中數據會先寫入本地磁盤,當滿足一定條件時 ClickHouse 的後臺線程會異步把數據從本地磁盤遷移到 JuiceFS 上。和第一個方案一樣,查詢時也會自動緩存熱數據。注意圖中爲了區分寫和讀因此畫了兩塊磁盤,實際使用中沒有這個限制,可以使用同一個盤。雖然這個方案不是完全的存儲計算分離,但是可以滿足對寫入性能要求特別高的場景需求,也保留一定的存儲資源彈性伸縮能力。下面會詳細介紹這個方案在 ClickHouse 中如何配置。

ClickHouse 支持配置多塊磁盤用於數據存儲,下面是示例的配置文件:

1<storage_configuration>
2    <disks>
3        <jfs>
4            <path>/jfs</path>
5        </jfs>
6    </disks>
7</storage_configuration>
8
9

上面的 /jfs 目錄即是 JuiceFS 文件系統掛載的路徑。在把以上配置添加到 ClickHouse 的配置文件中,併成功掛載 JuiceFS 文件系統以後,就可以通過 MOVE PARTITION 命令將某個 partition 移動到 JuiceFS 上,例如:

1ALTER TABLE test MOVE PARTITION 'xxx' TO DISK 'jfs';
2

當然這種手動移動的方式只是用於測試,ClickHouse 支持通過配置存儲策略的方式來將數據自動從某個磁盤移動到另一個磁盤。下面是示例的配置文件:

 1<storage_configuration>
 2    <disks>
 3        <jfs>
 4            <path>/jfs</path>
 5        </jfs>
 6    </disks>
 7    <policies>
 8        <hot_and_cold>
 9            <volumes>
10                <hot>
11                    <disk>default</disk>
12                    <max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
13                </hot>
14                <cold>
15                    <disk>jfs</disk>
16                </cold>
17            </volumes>
18            <move_factor>0.1</move_factor>
19        </hot_and_cold>
20    </policies>
21</storage_configuration>
22
23

上面的配置文件中有一個名爲 hot_and_cold 的存儲策略,其中定義了兩個 volume,名爲 hot 的 volume 是默認的 SSD 盤,名爲 cold 的 volume 即是上一步 disks 中定義的 JuiceFS 盤。這些 volume 在配置文件中的順序很重要,數據會首先存儲到第一個 volume 中,而 max_data_part_size_bytes 這個配置表示當數據 part 超過指定的大小時(示例中是 1GiB)自動從當前 volume 移動到下一個 volume,也就是把數據從 SSD 盤移動到 JuiceFS。最後的 move_factor 配置表示當 SSD 盤的磁盤容量超過 90% 時也會觸發數據移動到 JuiceFS。

最後在創建表時需要顯式指定要用到的存儲策略:

1CREATE TABLE test (
2  ...
3) ENGINE = MergeTree
4...
5SETTINGS storage_policy = 'hot_and_cold';
6
7

當滿足數據移動的條件時,ClickHouse 就會啓動後臺線程去執行移動數據的操作,默認會有 8 個線程同時工作,這個線程數量可以通過 background_move_pool_size 配置調整。

除了配置存儲策略以外,還可以在創建表時通過 TTL 將超過一段時間的數據移動到 JuiceFS 上,例如:

1CREATE TABLE test (
2  d DateTime,
3  ...
4) ENGINE = MergeTree
5...
6TTL d + INTERVAL 1 DAY TO DISK 'jfs'
7SETTINGS storage_policy = 'hot_and_cold';
8
9

上面的例子是將超過 1 天的數據移動到 JuiceFS 上,結合存儲策略一起可以非常靈活地管理數據的生命週期。

寫入性能測試

採用冷熱數據分離方案以後數據並不會直接寫入 JuiceFS,而是先寫入 SSD 盤,再通過後臺線程異步遷移到 JuiceFS 上。但是我們希望直接評估不同存儲介質在寫數據的場景有多大的性能差異,因此這裏在測試寫入性能時沒有配置冷熱數據分離的存儲策略,而是讓 ClickHouse 直接寫入不同的存儲介質。

具體測試方法是將真實業務中的某一張 ClickHouse 表作爲數據源,然後使用 INSERT INTO 語句批量插入千萬級行數的數據,比較直接寫入 SSD 盤、JuiceFS 以及對象存儲的吞吐。最終的測試結果如下圖:

**以 SSD 盤作爲基準,可以看到 JuiceFS 的寫入性能與 SSD 盤有 30% 左右的性能差距,但是相比對象存儲有 11 倍的性能提升。**這裏 JuiceFS 的測試中開啓了 writeback 選項,這是因爲 ClickHouse 在寫入時每個 part 會產生大量的小文件(KiB 級),客戶端採用異步寫入的方式能明顯提升性能,同時大量的小文件對於查詢性能也會造成一定影響。

在瞭解了直接寫入不同介質的性能以後,接下來測試冷熱數據分離方案的寫入性能。經過實際業務測試,基於 JuiceFS 的冷熱數據分離方案表現穩定,因爲新數據都是直接寫入 SSD 盤,因此寫入性能與上面測試中的 SSD 盤性能相當。SSD 盤上的數據可以很快遷移到 JuiceFS 上,在 JuiceFS 上對數據 part 進行合併也都是沒有問題的。

查詢性能測試

查詢性能測試使用真實業務中的數據,並選取幾個典型的查詢場景進行測試。其中 q1-q4 是掃描全表的查詢,q5-q7 是命中主鍵索引的查詢。測試結果如下圖:

**可以看到 JuiceFS 與 SSD 盤的查詢性能基本相當,平均差異在 6% 左右,但是對象存儲相比 SSD 盤有 1.4 至 30 倍的性能下降。**得益於 JuiceFS 高性能的元數據操作以及本地緩存特性,可以自動將查詢請求需要的熱數據緩存在 ClickHouse 節點本地,大幅提升了 ClickHouse 的查詢性能。需要注意的是以上測試中對象存儲是通過 ClickHouse 的 S3 磁盤類型進行訪問,這種方式只有數據是存儲在對象存儲上,元數據還是在本地磁盤。如果通過類似 S3FS 的方式把對象存儲掛載到本地,性能會有進一步的下降。

在完成基礎的查詢性能測試以後,接下來測試冷熱數據分離方案下的查詢性能。區別於前面的測試,當採用冷熱數據分離方案時,並不是所有數據都在 JuiceFS 中,數據會優先寫入 SSD 盤。

首先選取一個固定的查詢時間範圍,評估 JuiceFS 緩存對性能的影響,測試結果如下圖:

第一次查詢因爲沒有緩存相比後幾次慢一些,從第二次查詢開始 JuiceFS 的查詢性能就比較穩定,相比第一次有 70% 左右的性能提升。第四次查詢是間隔上一次 10 分鐘以後進行,性能略有波動(可能是受系統 page cache 影響),但屬於預期範圍之內,第五次又恢復之前的查詢時間。

然後採用不固定時間範圍進行查詢,同時還有數據在實時寫入,也就是說每次查詢都會涉及新的數據,測試結果如下圖:

跟固定時間範圍的查詢一樣,從第二次查詢開始因爲緩存的建立帶來了 78% 左右的性能提升。不同的地方在於第四次查詢因爲涉及到查詢新寫入或者合併後的數據,而 JuiceFS 目前不會在寫入時緩存大文件,會對查詢性能造成一定影響,之後會提供參數允許緩存寫入數據來改善新數據的查詢性能。

總結

通過 ClickHouse 的存儲策略可以很簡單地將 SSD 和 JuiceFS 結合使用,實現性能與成本的兩全方案。從寫入和查詢性能測試的結果上來看 JuiceFS 完全可以滿足 ClickHouse 的使用場景,用戶不必再擔心容量問題,在增加少量成本的情況下輕鬆應對未來幾倍的數據增長需求。JuiceFS 目前已經支持超過 20 家公有云的對象存儲,結合完全兼容 POSIX 的特性,不需要改動 ClickHouse 任何一行代碼就可以輕鬆接入雲上的對象存儲。

展望

在當前越來越強調雲原生的環境下,存儲計算分離已經是大勢所趨。ClickHouse 2021 年的 roadmap 上已經明確把存儲計算分離作爲了主要目標,雖然目前 ClickHouse 已經支持把數據存儲到 S3 上,但這個實現還比較粗糙。未來 JuiceFS 也會與 ClickHouse 社區緊密合作共同探索存算分離的方向,讓 ClickHouse 更好地識別和支持共享存儲,實現集羣伸縮時不需要做任何數據拷貝。

如果你對 JuiceFS 感興趣,就訪問 GitHub 開始試用吧:https://github.com/juicedata/juicefs

參考資料:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/AV2KZ3oLbWHkDldbe8odFw