ClickHouse 入門:MergeTree 與用 S3 做冷熱儲存

ClickHouse 是一個 columnar 的 OLAP 資料庫,掃幾億列做聚合快得誇張。這篇講最低限度的上手、MergeTree 幾個有趣的地方,以及怎麼用 AWS S3 把舊資料丟到冷儲存省錢。

用 Docker 快速跑起來

最快的方式是 compose,用現成範本(clickhouse_4.8,跑 clickhouse/clickhouse-server:24.8):

git clone https://github.com/yshengliao/docker-compose-templates
cd docker-compose-templates/clickhouse_4.8
docker compose up -d

起來後有兩個介面:8123 是 HTTP、9000 是原生 TCP。連進去下 SQL:

docker exec -it clickhouse clickhouse-client
# 或走 HTTP 介面
curl 'http://localhost:8123/?query=SELECT%20version()'

範本把 clickhouse-server/ 掛成設定目錄,等一下加 S3 設定就丟這裡。

MergeTree:parts 與背景合併

MergeTree 是 ClickHouse 的主力引擎,核心行為是:每次 INSERT 不是逐列塞進一個大檔,而是產生一個獨立、依 primary key 排序好的 part;背景再用一支程序把這些 part 慢慢合併成更大的 part。名字 MergeTree 就是這麼來的,概念上接近 LSM-tree。

CREATE TABLE events
(
    ts       DateTime,
    user_id  UInt64,
    event    LowCardinality(String),
    payload  String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(ts)
ORDER BY (user_id, ts);

ORDER BY 是排序鍵,也預設兼任 primary key。MergeTree 家族還有幾個有趣的變體:ReplacingMergeTree(合併時依鍵去重)、SummingMergeTree / AggregatingMergeTree(合併時就把同鍵的數值加總 / 聚合)。把「合併」這個動作賦予語意,是 ClickHouse 很聰明的地方。

稀疏主鍵索引

ClickHouse 的 primary index 是稀疏的:它不是每列建一筆索引,而是每 index_granularity(預設 8192)列為一個 granule,只記每個 granule 的起點。好處是即使幾十億列,索引也小到能整個放進記憶體。

查詢時若條件落在 ORDER BY 的前綴上,ClickHouse 直接跳過不相干的 granule(data skipping),只讀需要的區塊。所以 ORDER BY 怎麼挑,幾乎決定了查詢快不快,把最常拿來過濾的欄位放前面。

PARTITION BY 與 TTL

PARTITION BY toYYYYMM(ts) 把資料按月切。它不是索引,而是讓你能整塊操作:查特定月份時自動 partition pruning、要刪舊資料 DROP PARTITION 一秒搞定、跨儲存層搬移也以 partition 為單位。

TTL 有兩種用法。一是讓列過期被刪:

ALTER TABLE events MODIFY TTL ts + INTERVAL 90 DAY;

二是更有趣的,時間到就把資料搬到別的儲存層,這正是冷熱分層的鉤子(下一節)。

用 S3 做冷熱暖儲存

熱資料放本機 SSD 查得快,舊資料丟 S3 省錢,ClickHouse 用 storage_configuration 把這件事做成宣告式。在 clickhouse-server/config.d/ 放一個 storage.xml(範本已經把這個目錄掛進去了):

<clickhouse>
  <storage_configuration>
    <disks>
      <s3_cold>
        <type>s3</type>
        <endpoint>https://YOUR_BUCKET.s3.ap-northeast-1.amazonaws.com/clickhouse/</endpoint>
        <access_key_id>YOUR_KEY</access_key_id>
        <secret_access_key>YOUR_SECRET</secret_access_key>
      </s3_cold>
    </disks>
    <policies>
      <hot_cold>
        <volumes>
          <hot><disk>default</disk></hot>   <!-- 本機 SSD -->
          <cold><disk>s3_cold</disk></cold> <!-- AWS S3 -->
        </volumes>
        <move_factor>0.2</move_factor>
      </hot_cold>
    </policies>
  </storage_configuration>
</clickhouse>

move_factor 是「某個 volume 剩餘空間低於這個比例(0.2 = 20%)時,自動把資料往下一層搬」。表掛上這個 policy,再用 TTL 指定多久搬到冷層:

CREATE TABLE events ( /* …同上… */ )
ENGINE = MergeTree
PARTITION BY toYYYYMM(ts)
ORDER BY (user_id, ts)
TTL ts + INTERVAL 30 DAY TO VOLUME 'cold'
SETTINGS storage_policy = 'hot_cold';

30 天內的資料留在本機 SSD(熱),之後背景自動搬到 S3(冷),查詢語法完全不變,只是冷資料慢一點。想要三層「熱 / 溫 / 冷」,就在中間多一個本機 HDD 的 volume,TTL 寫成 … + 7 DAY TO VOLUME 'warm', … + 30 DAY TO VOLUME 'cold'

重點整理

  • ClickHouse 是 columnar OLAP,MergeTree 是主力引擎:INSERT 產生排序好的 part,背景合併成大 part(概念近 LSM)。
  • primary index 稀疏(每 8192 列一個 granule),索引小、可常駐記憶體;ORDER BY 的選法決定查詢能跳過多少資料。
  • PARTITION BY 讓你以分區為單位 pruning、刪除、搬移;MergeTree 家族的 Replacing / Summing / Aggregating 把「合併」變成有語意的動作。
  • TTL ... TO VOLUME + storage_configuration 就能做冷熱分層:熱資料留 SSD、舊資料自動搬 S3,查詢語法不變。
  • clickhouse_4.8 範本 docker compose up -d 最快上手,S3 設定丟進 clickhouse-server/config.d/ 即生效。

內文由 Claude 協助整理 · 環境 ClickHouse 24.8(LTS)+ Docker · 列入 20260613 blog 翻新計劃,新漆未乾。