CK03# ClickHouse日志存儲(chǔ)設(shè)計(jì)點(diǎn)梳理
最近周末比較忙,卷的有點(diǎn)累,上周的文章掉了鏈子,這周趕一篇。本文主要梳理了使用ClickHouse作為日志存儲(chǔ)的設(shè)計(jì)點(diǎn),主要內(nèi)容有:
應(yīng)用日志存儲(chǔ)時(shí)長(zhǎng)定制 ClickHouse數(shù)據(jù)的冷熱存儲(chǔ) ClickHouse數(shù)據(jù)遷移與刪除 ClickHouse查詢(xún)性能調(diào)優(yōu)點(diǎn)
公司所有的應(yīng)用存儲(chǔ)日志時(shí)長(zhǎng)統(tǒng)一設(shè)置固定存儲(chǔ)時(shí)長(zhǎng),比如:1個(gè)月、2個(gè)月。
這種策略也常被公司采用,優(yōu)點(diǎn)是整體設(shè)計(jì)簡(jiǎn)單。
缺點(diǎn)不能滿(mǎn)足業(yè)務(wù)需要以及可能存在成本浪費(fèi)。
有的業(yè)務(wù)場(chǎng)景日志存儲(chǔ)3天,例如用戶(hù)推薦、行為分析等。
很多應(yīng)用要求存儲(chǔ)7天,核心鏈路場(chǎng)景卻希望存儲(chǔ)1個(gè)月。
對(duì)于逆向退貨場(chǎng)景類(lèi)的卻要2個(gè)月,甚至一些特殊場(chǎng)景要求3個(gè)月、6個(gè)月的。
小結(jié):也就是說(shuō)根據(jù)應(yīng)用設(shè)置不同的存儲(chǔ)時(shí)長(zhǎng),是一個(gè)不錯(cuò)的方案,即能滿(mǎn)足不同場(chǎng)景需求也兼顧存儲(chǔ)成本。
用ClickHouse做日志存儲(chǔ),通過(guò)冷/熱盤(pán)來(lái)存儲(chǔ)數(shù)據(jù)。
熱盤(pán)可以使用ESSD,存儲(chǔ)1~3天的數(shù)據(jù)。
冷盤(pán)可以使用普通盤(pán),存儲(chǔ)3天以上的數(shù)據(jù)。
通過(guò)TTL或者遷移命令將熱盤(pán)數(shù)據(jù)遷移到冷盤(pán)去。
下面是日志平臺(tái)簡(jiǎn)要架構(gòu)圖示。

下面是ClickHouse配置冷熱存儲(chǔ)的配置。
<storage_configuration>
<disks>
<hot>
<path>/data1/clickhouse/hot/data/</path>
<max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
</hot>
<cold>
<path>/data2/clickhouse/cold/data/</path>
</cold>
</disks>
<policies>
<ttl>
<volumes>
<hot>
<disk>hot</disk>
</hot>
<cold>
<disk>cold</disk>
</cold>
</volumes>
<move_factor>0.1</move_factor>
</ttl>
</policies>
</storage_configuration>
合并分區(qū)或者一次性寫(xiě)入的分區(qū)大小超過(guò)max_data_part_size_bytes,也會(huì)被寫(xiě)入到COLD卷中。
當(dāng)存儲(chǔ)磁盤(pán)空間小move_factor時(shí),默認(rèn)為0.1即磁盤(pán)小于10%時(shí),數(shù)據(jù)會(huì)自動(dòng)移動(dòng)到下一個(gè)磁盤(pán)volume組。
也就是熱盤(pán)磁盤(pán)剩余10%時(shí),clickhouse會(huì)將熱數(shù)據(jù)向冷盤(pán)遷移。
通過(guò)下面命令查看冷熱存儲(chǔ)策略以及對(duì)應(yīng)的磁盤(pán)空間和剩余空間。
SELECT name, path, formatReadableSize(free_space) AS free, formatReadableSize(total_space) AS total, formatReadableSize(keep_free_space) AS reserved FROM system.disks;
運(yùn)行結(jié)果圖示

通過(guò)下面命令查看max_data_part_size以及move_factor的配置。
SELECT policy_name, volume_name, volume_priority, disks, formatReadableSize(max_data_part_size) AS max_data_part_size, move_factor FROM system.storage_policies;
運(yùn)行結(jié)果圖示

小結(jié):通過(guò)冷熱多路徑存儲(chǔ)策略,非常適合日志的場(chǎng)景。
盡管ClickHouse提供表級(jí)別和列級(jí)別的數(shù)據(jù)TTL遷移和數(shù)據(jù)過(guò)期策略。
然而在數(shù)據(jù)遷移和刪除不可避免造成磁盤(pán)IO增加,影響集群的整體性能。
那我們?cè)跇I(yè)務(wù)低峰期比如凌晨?jī)牲c(diǎn),定時(shí)執(zhí)行指定的分區(qū)遷移,能將影響降到最小。
下面就走一把,如何通過(guò)命令來(lái)執(zhí)行數(shù)據(jù)分區(qū)的遷移。
下面是查看分區(qū)所在磁盤(pán)的命令。
SELECT partition, name, disk_name FROM system.parts WHERE table='tb_logs_local';
可以看出,分區(qū)Part (000125d45a217a0d121f99b0cdfda94c_908003_1097483_4) 存儲(chǔ)在hot磁盤(pán)中。

同樣在system.parts還可以查詢(xún)更多的信息,比如database
SELECT partition,name, database,table,disk_name FROM system.parts WHERE table='tb_logs_local';
執(zhí)行結(jié)果圖示

通過(guò)move命令將hot盤(pán)的分區(qū)遷移到冷盤(pán)中。
alter table dw_log.tb_logs_local on cluster default move partition ('xxx-clasp','xx','2022-07-01 19:00:00') to disk 'cold'
執(zhí)行結(jié)果圖示

通過(guò)再次查看,該分區(qū)已被遷移到冷盤(pán)中了。

同樣通過(guò)drop命令,可以將分區(qū)刪除。
alter table dw_log.tb_logs_local on cluster default drop partition ('scp-pink-clasp','MF7','2022-07-01 19:00:00') ;

刪除結(jié)果查詢(xún),該分區(qū)檢索不到。

小結(jié):在創(chuàng)建表時(shí)可以設(shè)置應(yīng)用名稱(chēng)、日期為分區(qū)鍵,在system.parts有詳細(xì)的應(yīng)用以及創(chuàng)建日期,進(jìn)而通過(guò)move/drop命令執(zhí)行分區(qū)的轉(zhuǎn)移和刪除。
如何提高ClickHouse的查詢(xún)性能?
優(yōu)化方向一,一個(gè)超大集群切分兩個(gè)中等規(guī)模集群。
優(yōu)化方向二,通過(guò)對(duì)表字段設(shè)置合理的索引。
一級(jí)索引,通常primary key與order by定義相同。
MergeTree會(huì)根據(jù)index_granularity間隔為數(shù)據(jù)表生成一級(jí)索引保存在primary.idx文件中。
index_granularity默認(rèn)8192行,也就是使用的是稀疏索引。
也就是數(shù)據(jù)被分割為 n=數(shù)據(jù)總行數(shù)/index_granularity 個(gè)區(qū)間,每一個(gè)區(qū)間一個(gè)索引。
二級(jí)索引又稱(chēng)跳數(shù)索引,主要有minmax、set、ngrambf_v1和tokenbf_v1四種類(lèi)型。
二級(jí)索引共同參數(shù)granularity,指跳過(guò)幾個(gè)區(qū)間再生成一條索引。
具體跳數(shù)索引的含義以及原理,再起一篇梳理。
下面是一個(gè)測(cè)試樣例。
CREATE TABLE logs_demo
(
`application` String,
`environment` String,
`ip` String,
`filename` String,
`keys` Array(Nullable(String)) CODEC(ZSTD(1)),
`values_string` Array(Nullable(String)) CODEC(ZSTD(1)),
`values_number` Array(Nullable(Float64)) CODEC(ZSTD(1)),
`file_offset` Nullable(UInt32),
`message` String CODEC(ZSTD(1)),
`log_type` String,
`log_time` DateTime64(3),
INDEX environment environment TYPE SET(100) GRANULARITY 2,
INDEX message message TYPE tokenbf_v1(32768,
2,
0) GRANULARITY 2
)
ENGINE = MergeTree
PARTITION BY (application,
toStartOfHour(log_time))
ORDER BY (environment,
log_time,
ip,
file_offset)
SETTINGS allow_nullable_key = 1,
storage_policy = 'ttl',
index_granularity = 8192;
其中environment使用SET類(lèi)型的跳數(shù)索引。
message使用了布隆過(guò)濾器tokenbf_v1類(lèi)型的跳數(shù)索引。
小結(jié):總之可通過(guò)調(diào)整跳數(shù)索引與集群規(guī)模來(lái)優(yōu)化查詢(xún)查詢(xún)性能。
