Map(LowCardinality(String), String). ClickHouse также поддерживает строго типизированный тип JSON, а в ClickStack есть его поддержка в статусе бета в качестве замены Map.
Для типичных рабочих нагрузок обсервабилити мы рекомендуем использовать схему по умолчанию на основе Map. Тип JSON доступен пользователям, которые хотят оценить его на рабочих нагрузках с небольшим стабильным набором ключей атрибутов, но для общего применения эта схема не рекомендуется.
Почему Map рекомендуется по умолчанию
Map(LowCardinality(String), String) хранит ключи и значения в единой структуре. Исторически недостаток Map заключался в том, что чтение одного ключа требовало чтения всего столбца Map. Теперь это уже не так: ClickHouse поддерживает сериализацию Map по бакетам, которая разбивает Map на бакеты, так что запросы читают только нужные им бакеты. В сочетании с текстовыми индексами по ключам и значениям Map — именно так настроена схема ClickStack по умолчанию — это делает Map избирательным и быстрым при чтении без дополнительных затрат на приём новых ключей.
На практике это означает следующее:
- Стабильные затраты на приём по мере роста числа ключей. Добавление нового ключа атрибута не меняет структуру столбцов на диске и не создаёт новые файлы столбцов. Затраты на приём ограничиваются объёмом данных, а не мощностью ключей.
- Без взрывного роста метаданных. Количество файлов столбцов на диске не зависит от числа уникальных ключей атрибутов.
- Избирательные lookup через индексы. Текстовые индексы по ключам и значениям Map позволяют выполнять точечные lookup без сканирования каждой строки.
- Предсказуемое поведение при высокой пропускной способности. Map справляется со всплесками бессхемных наборов атрибутов, которые часто встречаются в трассировке и журналах, без накладных расходов на каждый ключ.
Почему не JSON по умолчанию
JSON использует другой подход: при вставке ClickHouse динамически создаёт отдельный строго типизированный подстолбец для каждого обнаруженного пути. При чтении это удобно, поскольку считываются только запрошенные подстолбцы, типы сохраняются и не требуется приведение типов во время выполнения запроса.
Однако компромисс проявляется на этапе приёма. Создание и управление большим количеством динамических подстолбцов увеличивает накладные расходы при записи и усложняет метаданные. Для рабочих нагрузок обсервабилити, где обычно встречаются очень большие или сильно меняющиеся наборы атрибутов и высокая пропускная способность приёма, эти накладные расходы оказываются существенными. Ограничение max_dynamic_paths может частично смягчить проблему, помещая дополнительные пути в общий столбец, но доступ к общему столбцу медленнее, чем к выделенным подстолбцам, что снижает преимущество при чтении, ради которого JSON изначально и выбирают.
Поскольку сериализация Map по бакетам устраняет большую часть исторических накладных расходов Map при чтении, преимущество JSON при чтении для типичных рабочих нагрузок обсервабилити больше не перевешивает его стоимость на этапе приёма.
Когда JSON всё ещё стоит рассмотреть
- Набор ключей атрибутов небольшой и стабильный, то есть у вас не появляются тысячи уникальных ключей, а новые ключи возникают редко.
- Пропускная способность приёма умеренная по сравнению с мощностью атрибутов.
- Вам нужен строго типизированный доступ к атрибутам без приведения типов на уровне запроса (числа остаются числами, булевы значения — булевыми).
- Вы готовы использовать бета-возможность в ClickStack и принимаете, что интеграция может измениться.
Map.
Статус бета
2.0.4.
Включение поддержки JSON
Map, используемых по умолчанию, задайте следующие переменные окружения.
Управляемый ClickStack
OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json' в коллекторе. Например:
ClickStack с открытым исходным кодом
OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json' в любом развертывании, где используется коллектор, и BETA_CH_OTEL_JSON_SCHEMA_ENABLED=true на уровне приложения HyperDX, чтобы оно могло выполнять запросы к схемам, использующим тип JSON.
Например:
Миграция со схемы на основе Map на JSON
1
Остановите OTel коллектор
2
Переименуйте существующие таблицы и обновите источники данных
Переименуйте существующие таблицы и обновите источники данных в HyperDX.Например:3
Разверните коллектор
Разверните коллектор, задавOTEL_AGENT_FEATURE_GATE_ARG.4
Перезапустите контейнер HyperDX с поддержкой схемы JSON
5