Storage — то место, где решения принимаются один раз и живут годами. Ошибка в выборе класса диска на старте потом стоит миграции всего кластера.
Локальные диски против сетевых
Фундаментальный компромисс:
Локальные NVMe — максимальная пропускная способность и низкая латентность, что для ClickHouse (сканирование больших объёмов, постоянные слияния) даёт заметный выигрыш. Цена: том привязан к конкретной ноде. Умерла нода — умерла реплика; восстановление означает полное копирование данных с соседней реплики, а это часы на больших объёмах.
Сетевые тома (EBS, PD, Ceph RBD) — под переезжает на другую ноду вместе с данными, восстановление быстрое. Цена: выше латентность и, что важнее, плавающий IOPS-бюджет, который может резать слияния в самый неподходящий момент.
Практическое правило: локальные диски оправданы, когда у вас есть реплики (иначе отказ ноды = потеря данных) и объёмы такие, что сетевой диск не тянет. Для большинства инсталляций разумный старт — быстрый сетевой SSD с гарантированным IOPS, а к локальным NVMe переходить осознанно, померив.
Если берёте локальные тома, обязательно:
volumeBindingMode: WaitForFirstConsumerИначе PVC может привязаться к зоне, где под потом не запланируется.
PVC: то, что нужно сделать сразу
Три настройки, о которых жалеют, если забыли:
1. Reclaim policy — Retain для прода.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: clickhouse-ssd
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "16000"
throughput: "1000"
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumerС Delete неаккуратное удаление кастомного ресурса унесёт данные вместе с PVC. Retain оставит том — его можно вернуть.
2. allowVolumeExpansion: true — иначе расширить диск без пересоздания не выйдет. Данные в ClickHouse растут всегда; закладывайте возможность расширения с первого дня.
3. Запас по месту. ClickHouse нужно свободное место для слияний: чтобы слить куски, надо временно разместить результат рядом. Держите заполнение ниже ~70–80%; при нехватке места слияния встают, куски копятся, и вы получаете too many parts. Мониторьте свободное место как критичную метрику, а не как «когда-нибудь посмотрим».
Многоуровневое хранение
Аналитические данные почти всегда имеют «температуру»: свежее читают часто, старое — редко, но выбрасывать нельзя. ClickHouse умеет разносить это по томам через политики хранения.
Идея: горячий том на быстром SSD, холодный — в объектном хранилище (S3/GCS), а перемещение — автоматическое по TTL.
Конфигурация дисков и политики (в storage_configuration, задаётся через оператор):
<storage_configuration>
<disks>
<hot>
<type>local</type>
<path>/var/lib/clickhouse/</path>
</hot>
<cold_s3>
<type>s3</type>
<endpoint>https://s3.example.com/clickhouse-cold/</endpoint>
<use_environment_credentials>true</use_environment_credentials>
</cold_s3>
</disks>
<policies>
<hot_to_cold>
<volumes>
<hot>
<disk>hot</disk>
</hot>
<cold>
<disk>cold_s3</disk>
</cold>
</volumes>
</hot_to_cold>
</policies>
</storage_configuration>И применение в таблице — данные старше 30 дней уезжают в S3, старше года удаляются:
CREATE TABLE events (
ts DateTime,
user_id UInt64,
event LowCardinality(String)
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(ts)
ORDER BY (event, user_id, ts)
TTL ts + INTERVAL 30 DAY TO VOLUME 'cold',
ts + INTERVAL 1 YEAR DELETE
SETTINGS storage_policy = 'hot_to_cold';Это одна из самых выгодных практик по стоимости: объектное хранилище на порядок дешевле блочного, а запросы к историческим данным обычно редкие и терпят большую латентность.
Кэш для объектного хранилища
Запросы к S3 медленнее — латентность на каждое обращение. Поэтому для «холодных» дисков включают локальный кэш: часто читаемые куски оседают на быстром диске. Без кэша дашборд, случайно захвативший старый период, будет неприятно тормозить. Заложите под кэш отдельное место и следите за его hit rate.
Отдельно про credentials: не зашивайте ключи в конфиг. В Kubernetes используйте IRSA/Workload Identity либо секрет, монтируемый оператором, — и права на бакет по минимуму.
Отдельные тома под разные задачи
Хорошая практика — не сваливать всё в один PVC:
- данные — основной большой том;
- Keeper — свой небольшой быстрый том (см. часть 3);
- логи и временные файлы — можно отдельно, чтобы всплеск временных файлов от тяжёлого запроса не забил диск с данными под завязку.
Временные файлы заслуживают внимания: когда запросу не хватает памяти на сортировку/агрегацию, он льёт данные на диск. Один тяжёлый запрос способен занять десятки гигабайт. Ограничивайте это настройками (max_temporary_data_on_disk_size_for_query) и следите за метрикой временных файлов.
Типичные ошибки
reclaimPolicy: Deleteна проде — одно неосторожное удаление ресурса, и данных нет.- Диск забит выше 85% — слияния встают, кластер деградирует лавинообразно.
- Один медленный сетевой диск на всё — упираетесь в IOPS и не понимаете почему.
- Нет расширения тома — расти можно только через пересоздание реплики.
- S3 без кэша и без понимания, какие запросы туда попадут.
- Reclaim
Retain, но никто не чистит осиротевшие тома — со временем платите за мусор. Заведите процедуру.
Дальше: Часть 5. Проектирование таблиц: ORDER BY, партиции, кодеки, TTL.