ClickStack: единый observability-стек на ClickHouse
ClickStack — это flagship observability-бандл от ClickHouse Inc., анонсированный в мае 2025 года. Стек объединяет три компонента: ClickHouse в качестве хранилища (logs/metrics/traces/session replay), OpenTelemetry Collector как ingestion-слой и HyperDX как пользовательский интерфейс. ClickStack позиционируется как открытая альтернатива DataDog, Splunk и Elastic+APM с кросс-сигнальной корреляцией на уровне БД и стоимостью хранения от трёх центов за гигабайт в месяц в Managed-варианте.
HyperDX был приобретён ClickHouse Inc. 13 марта 2025 года. На базе HyperDX UI и официального clickhouseexporter из OpenTelemetry Collector Contrib команда ClickHouse собрала единый дистрибутив, получивший имя ClickStack. Релиз GA состоялся 29 мая 2025 года; во второй половине 2025 года добавились RBAC, alerting и Managed ClickStack в облаке.
Архитектура ClickStack
Ключевое архитектурное решение: HyperDX UI работает поверх ClickHouse напрямую, без посредников. Это снижает количество сервисов в production и устраняет дополнительный слой кэширования.
Зачем единый стек: проблема трёх пиллар
Классическая модель «трёх пиллар» — logs, metrics, traces — приводит к фрагментации данных по разным backend-ам:
В Grafana LGTM-стеке (Loki + Tempo + Mimir) каждый сигнал живёт в своём хранилище. Чтобы перейти от лога ошибки к соответствующему трейсу, UI должен сделать lookup в Tempo по trace_id — это корреляция на уровне приложения. В ClickStack корреляция выполняется обычным SQL JOIN внутри одной БД:
-- Найти все логи и спаны конкретного запроса в одном запросе
SELECT
'log' AS signal,
Timestamp,
SeverityText AS level,
Body AS message,
NULL AS duration_ns
FROM otel_logs
WHERE TraceId = 'a1b2c3d4e5f6...'
UNION ALL
SELECT
'trace' AS signal,
Timestamp,
StatusCode AS level,
SpanName AS message,
Duration AS duration_ns
FROM otel_traces
WHERE TraceId = 'a1b2c3d4e5f6...'
ORDER BY Timestamp;
OpenTelemetry → ClickHouse: схема и формат данных
Официальный clickhouseexporter живёт в opentelemetry-collector-contrib и поддерживает все три сигнала. По умолчанию создаются следующие таблицы:
-- Логи: одна строка на лог-событие
CREATE TABLE otel_logs (
Timestamp DateTime64(9) CODEC(Delta(8), ZSTD(1)),
TraceId String CODEC(ZSTD(1)),
SpanId String CODEC(ZSTD(1)),
TraceFlags UInt32 CODEC(ZSTD(1)),
SeverityText LowCardinality(String) CODEC(ZSTD(1)),
SeverityNumber Int32 CODEC(ZSTD(1)),
ServiceName LowCardinality(String) CODEC(ZSTD(1)),
Body String CODEC(ZSTD(1)),
ResourceSchemaUrl String CODEC(ZSTD(1)),
ResourceAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ScopeSchemaUrl String CODEC(ZSTD(1)),
ScopeName String CODEC(ZSTD(1)),
ScopeVersion String CODEC(ZSTD(1)),
ScopeAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
LogAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
INDEX idx_trace_id TraceId TYPE bloom_filter(0.001) GRANULARITY 1,
INDEX idx_body Body TYPE tokenbf_v1(32768, 3, 0) GRANULARITY 8
)
ENGINE = MergeTree
PARTITION BY toDate(Timestamp)
ORDER BY (ServiceName, SeverityText, toUnixTimestamp(Timestamp), TraceId)
TTL toDateTime(Timestamp) + INTERVAL 30 DAY;
Для production используйте create_schema: false в конфигурации экспортёра и создавайте таблицы вручную. Иначе несколько процессов Collector будут гонять CREATE TABLE IF NOT EXISTS параллельно, а апгрейд экспортёра становится проблемой: нужно сначала альтерить схему вручную, иначе старые писатели сломают тип. Дефолтные DDL лежат в internal/sqltemplates репозитория contrib.
Похожая схема существует для трейсов (otel_traces) и для каждого типа метрики: otel_metrics_sum, otel_metrics_gauge, otel_metrics_histogram, otel_metrics_exponential_histogram, otel_metrics_summary. Каждый тип метрики отделён, потому что у них разная форма payload.
Materialized columns для дешёвых агрегаций
Запросы вида «топ-10 endpoints по количеству ошибок за час» могут стоить дорого, если каждый раз парсить LogAttributes['http.route'] из Map. Материализованные колонки решают это:
ALTER TABLE otel_logs
ADD COLUMN HttpRoute LowCardinality(String)
MATERIALIZED LogAttributes['http.route'];
ALTER TABLE otel_logs
ADD COLUMN HttpStatusCode UInt16
MATERIALIZED toUInt16OrZero(LogAttributes['http.status_code']);
Materialized колонка вычисляется при вставке и пишется на диск как обычная колонка. Запрос GROUP BY HttpRoute теперь читает только одну компактную LowCardinality-колонку, а не полную Map.
Конфигурация OTel Collector
# otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 5s
send_batch_size: 100000
resource:
attributes:
- key: deployment.environment
value: production
action: upsert
exporters:
clickhouse:
endpoint: tcp://clickhouse:9000?dial_timeout=10s
database: otel
username: default
password: ${CLICKHOUSE_PASSWORD}
create_schema: false # Production: таблицы созданы заранее
logs_table_name: otel_logs
traces_table_name: otel_traces
metrics_tables:
sum:
name: otel_metrics_sum
gauge:
name: otel_metrics_gauge
histogram:
name: otel_metrics_histogram
ttl: 720h # 30 дней (если schema создаётся экспортёром)
timeout: 10s
sending_queue:
enabled: true
num_consumers: 10
queue_size: 100
service:
pipelines:
logs:
receivers: [otlp]
processors: [resource, batch]
exporters: [clickhouse]
traces:
receivers: [otlp]
processors: [resource, batch]
exporters: [clickhouse]
metrics:
receivers: [otlp]
processors: [resource, batch]
exporters: [clickhouse]
Используйте batch processor с send_batch_size: 100000 — ClickHouse оптимально принимает крупные батчи. Слишком частые мелкие inserts создают много мелких parts и нагружают background merge. Для backpressure включайте sending_queue — Collector будет буферизовать события, если ClickHouse временно недоступен.
HyperDX UI: что доступно из коробки
Session replay — отличительная фича HyperDX, унаследованная при приобретении: HyperDX SDK для браузера записывает DOM-события и пользовательские взаимодействия, отправляет их через OTel Collector, и в UI становится доступен player ровно для той сессии, в которой случилась ошибка. Запись полностью совместима с rrweb.
Развёртывание
Self-hosted: Helm chart
ClickHouse Inc. публикует официальный Helm chart в репозитории ClickHouse/clickstack-helm-charts:
# 1. Установить операторы и CRDs
helm repo add clickstack https://clickhouse.github.io/clickstack-helm-charts
helm repo update
helm install clickstack-operators clickstack/clickstack-operators \
--namespace clickstack-system \
--create-namespace
# 2. Установить сам ClickStack (CH + OTel Collector + HyperDX)
helm install my-clickstack clickstack/clickstack \
--namespace clickstack \
--create-namespace \
--set hyperdx.ingress.enabled=true \
--set hyperdx.ingress.host=hyperdx.example.com
Чарт разворачивает: StatefulSet для ClickHouse (или ClickHouse Operator с шардированием), Deployment для OTel Collector с автоскейлингом, Deployment для HyperDX UI, Ingress, Secrets для credentials.
Managed ClickStack в ClickHouse Cloud
С конца 2025 года в ClickHouse Cloud доступен Managed ClickStack (beta) — onboarding одной кнопкой: Cloud сам разворачивает Collector endpoint, создаёт схему и подключает HyperDX UI к существующему сервису. Цена позиционируется как «менее трёх центов за гигабайт в месяц» (включая хранение, сжатие и compute для запросов), что делает решение конкурентным DataDog при удержании full-fidelity high-cardinality данных.
Storage layout: TTL, hot/cold, codecs
ClickStack использует тот же арсенал ClickHouse, что и обычные аналитические таблицы, но с настройками, оптимизированными для observability:
-- Production-схема логов с hot/cold S3 tiered storage
CREATE TABLE otel_logs (
Timestamp DateTime64(9) CODEC(Delta(8), ZSTD(1)),
ServiceName LowCardinality(String) CODEC(ZSTD(1)),
SeverityText LowCardinality(String) CODEC(ZSTD(1)),
Body String CODEC(ZSTD(3)),
TraceId String CODEC(ZSTD(1)),
-- ...
LogAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1))
)
ENGINE = MergeTree
PARTITION BY toStartOfHour(Timestamp) -- Маленькие партиции для precision-TTL
ORDER BY (ServiceName, SeverityText, Timestamp)
TTL
Timestamp + INTERVAL 7 DAY TO VOLUME 'cold', -- 7 дней hot SSD -> cold S3
Timestamp + INTERVAL 90 DAY DELETE -- 90 дней total retention
SETTINGS storage_policy = 'hot_cold';
Ключевые приёмы:
LowCardinality(String)дляServiceName,SeverityText, ключей вResourceAttributes. Эти поля имеют десятки уникальных значений на терабайт логов — компрессия x10-x50.ZSTD(1)— дефолт для текстовых полей.ZSTD(3)дляBodyдаёт ещё ~15% компрессии при terпимом увеличении CPU.Delta(8)+ ZSTD дляDateTime64(9)— хорошо упаковывает последовательные timestamps.PARTITION BY toStartOfHour(Timestamp)— позволяет TTL-движку перемещать парты между volumes гранулярнее, чем дневные партиции.- Bloom filter index на
TraceIdи token bloom filter наBody— ускоряют lookup без full scan.
В сравнении с Elasticsearch ClickStack даёт сжатие 10-30× на тех же логах. Сценарий: 100 ТБ raw-логов сжимаются до 5-10 ТБ в ClickHouse и до 30-50 ТБ в Elastic. Это базовая экономика, на которой строится тезис «менее трёх центов за гигабайт» в Managed ClickStack.
ClickStack vs альтернативы
Сравнение ключевых open-source и SaaS observability-стеков:
| Критерий | ClickStack | Grafana LGTM (Loki + Tempo + Mimir) | Elastic + APM | DataDog (SaaS) |
|---|---|---|---|---|
| Backends для 3 сигналов | 1 (ClickHouse) | 3 stateful-сервиса | 1 (Elastic) | proprietary |
| Корреляция logs/traces | DB-level (SQL JOIN) | App-level (trace_id lookup) | App-level | App-level |
| Запросы | Lucene + полный SQL | LogQL/PromQL/TraceQL | KQL/EQL | proprietary DSL |
| Сжатие vs raw | 10-30× | 5-10× (Loki) | 3-5× | n/a (SaaS billing) |
| Open source | Apache 2.0 | AGPLv3 / Apache 2.0 | SSPL/Elastic L. | proprietary |
| Self-hosted сложность | Helm, 1 chart | 3 отдельных stateful + Grafana | Cluster + APM | n/a |
| Managed offering | ClickHouse Cloud (beta) | Grafana Cloud | Elastic Cloud | DataDog (native) |
| Session replay | Native (HyperDX) | Faro (отдельно) | RUM (отдельно) | RUM (включён) |
| Стоимость high-cardinality | Низкая (columnar) | Средняя (Loki плох с метками) | Высокая | Очень высокая |
ClickStack выигрывает там, где важны: единое хранилище, кросс-сигнальный SQL, дешёвое хранение high-cardinality атрибутов, контроль над инфраструктурой. Grafana LGTM остаётся сильным выбором для команд, у которых уже есть экспертиза в Prometheus/PromQL и которым нужна best-in-class визуализация. DataDog стоит выбирать, если нужен полностью managed опыт без операционной нагрузки — за заметную премию в счёте.
Текущие ограничения ClickStack (актуально на конец 2025)
Стек активно развивается; на момент апреля 2026 года стоит знать о следующих границах:
RBAC появился в ClickStack осенью 2025: роли (no access / read / manage) для dashboards, saved searches, sources, alerts, webhooks, notebooks. Fine-grained access rules позволяют скрывать ресурсы от конкретных команд. На момент анонса RBAC доступен в Managed ClickStack и в self-hosted Enterprise-варианте; в OSS-сборке часть ролей упрощена.
Alerting доступен в Managed ClickStack для ClickHouse Cloud: search-based и chart-based alerts, интеграции со Slack, PagerDuty, generic webhook. Email и anomaly detection в roadmap. В self-hosted OSS-сборке alerting развёртывается отдельным компонентом.
Multi-tenancy реализован через RBAC + row-level security в ClickHouse: одна инсталляция HyperDX может обслуживать несколько команд через row-policies на ServiceName / namespace, но «жёсткий» tenant isolation (отдельные query-пулы, биллинг, лимиты) пока в roadmap Managed-варианта.
Также стоит понимать, что ClickStack — не turnkey-решение в стиле DataDog: в self-hosted-варианте требуется обслуживать ClickHouse-кластер (merges, ZooKeeper/Keeper, backups), настраивать OTel Collector pipeline и иногда вручную тюнить схему под конкретные нагрузки.
Production-чеклист
Перед деплоем ClickStack в production проверьте:
- Схема создана вручную:
create_schema: falseв clickhouseexporter, DDL версионируется в репозитории миграций (например, golang-migrate или сам ClickHouse keeper). - TTL и storage policy: определены hot tier (NVMe/SSD, 3-14 дней), cold tier (S3, до 90-180 дней), DELETE-TTL для соответствия GDPR/PCI.
- Materialized columns для частых GROUP BY атрибутов (
HttpRoute,HttpStatusCode,KubernetesNamespace). - Bloom filters на
TraceId,SpanId; tokenbf наBodyесли есть полнотекстовый поиск. - OTel Collector batch settings:
send_batch_size >= 50000,timeout5-10s,sending_queue.enabled: trueдля backpressure. - Replicated ClickHouse (минимум 2 реплики на шард), Keeper-ансамбль из 3 нод, регулярные backups через
BACKUP DATABASE otel TO S3(...). - Resource attributes whitelist на уровне Collector:
attributesprocessor сincludeрежимом, чтобы не разрастались уникальные ключи в Map. - Алерты на саму инфраструктуру:
system.errors,system.replicas.is_readonly, размерotel_logsparts, отставание Collector queue.
Ключевые выводы
- ClickStack — flagship observability bundle от ClickHouse Inc., анонсирован в мае 2025 после приобретения HyperDX в марте 2025. Состоит из ClickHouse (хранилище), OTel Collector с clickhouseexporter (ingestion) и HyperDX UI (фронтенд).
- Кросс-сигнальная корреляция на уровне БД — главное архитектурное преимущество. Logs/metrics/traces/session replay живут в одной OLAP-базе и соединяются обычным SQL JOIN по
TraceId/ServiceName, а не через application-layer lookup. - OpenTelemetry — единственный путь ingestion. Стандартные таблицы
otel_logs,otel_traces,otel_metrics_*создаются clickhouseexporter из collector-contrib. В production используйтеcreate_schema: falseи собственный DDL. - HyperDX UI работает поверх ClickHouse напрямую, без middleware и API-сервера. Поддерживает Lucene-style search, полный SQL, dashboards, trace explorer, session replay player и alerting (search-based + chart-based).
- Storage layout оптимизирован под observability:
LowCardinality(String)для атрибутов,ZSTDcodec,PARTITION BY toStartOfHour, TTL для hot/cold (S3) tiers, materialized columns для частых GROUP BY, bloom filters наTraceIdиBody. - Развёртывание: self-hosted через Helm chart (
ClickHouse/clickstack-helm-charts) или Managed ClickStack в ClickHouse Cloud (beta, цена от трёх центов за гигабайт в месяц с full-fidelity high-cardinality удержанием). - Сравнение: ClickStack даёт 10-30× сжатие vs Elastic, DB-level корреляцию vs application-level в Grafana LGTM, и контроль над инфраструктурой при существенно меньшей TCO по сравнению с DataDog для high-cardinality нагрузок.
- Текущие ограничения (конец 2025): RBAC, alerting, multi-tenancy появились во второй половине 2025 и продолжают развиваться. Self-hosted OSS-сборка отстаёт по этим возможностям от Managed ClickStack в облаке.
Для практики разверните ClickStack локально через Helm в kind/k3d-кластере: helm install my-clickstack clickstack/clickstack. Сгенерируйте нагрузку OpenTelemetry demo-приложением (otel-demo) и попробуйте написать SQL-запрос, который соединяет otel_logs и otel_traces по TraceId — это базовый паттерн root-cause-анализа в ClickStack.