Адаптивный пересказ статьи Scaling Observability beyond 100PB by embracing wide events and replacing OTel из блога ClickHouse. Текст мой, цифры — из оригинала.
Две идеи, которые стоит забрать из этой истории: как хранить телеметрию (широкие события) и сколько стоит лишняя сериализация (очень дорого).
Что такое широкое событие
Обычно телеметрию режут на три несовместимых куска: логи (текст), метрики (числа с ограниченной размерностью), трейсы (структура вызовов). Каждый по-своему теряет информацию.
Широкое событие (wide event) — это одна строка, в которой лежат все относящиеся к событию измерения и метрики сразу: имя пода, IP, имя таблицы, длительность вставки, лаг — вместе, без предварительной агрегации.
Разница проявляется в вопросах, которые можно задать. Классический подход отвечает «сколько вставок было медленными» (если вы догадались завести такую метрику заранее). Широкие события отвечают на вопрос «какая именно вставка вызвала этот всплеск» — и вопрос задаётся во время запроса, а не во время инструментирования.
Три типичные альтернативы и их потери:
- логировать только stdout — узко и теряет контекст;
- предагрегировать в метрики — гистограммы ограничивают размерность, детали не восстановить;
- жёсткая схема заранее — не гнётся и порождает взрыв схем.
Ключевое требование к базе для такого подхода — высокая кардинальность не должна быть проблемой. Именно поэтому широкие события естественно ложатся на ClickHouse и плохо — на системы с индексацией по размерностям.
Почему выкинули OTel-конвейер
Здесь важно правильно понять область применения: речь про сбор внутренней телеметрии самого ClickHouse Cloud, а не про отказ от OpenTelemetry вообще.
Две причины.
Первая — стоимость сериализации. Путь данных выглядел так:
JSON → stdout → диск → парсинг OTel → маршалинг →
формат OTel → преобразование клиентом → вставкаНа 20 миллионах строк в секунду поддержание такого конвейера без потерь потребовало бы, по оценке, около 8000 ядер CPU. Почти вся эта работа — перекладывание одних и тех же данных из формата в формат.
Вторая — доступ к данным. OTel забирал только stdout-логи, а самое ценное у ClickHouse лежит в системных таблицах: выполнение запросов, дисковый I/O, состояние фоновых задач. Через логи это просто не видно (см. часть 8).
Решение: ClickHouse → ClickHouse напрямую
Инструмент под названием SysEx делает побайтовый перенос между базами: SELECT из системных таблиц, поток в нативном формате, вставка — без десериализации и обратной сборки. Вклад в Go-клиент позволил обойти встроенный маршалинг.
Результат говорит сам за себя:
| Пропускная способность | CPU | |
|---|---|---|
| OTel-конвейер | 2 млн логов/с | 800+ ядер |
| Прямой перенос | 37 млн логов/с | 70 ядер |
Двадцатикратный рост объёма обошёлся менее чем 10% прежнего CPU на самом критичном источнике данных.
Вывод, применимый далеко за пределами этой инсталляции: если источник и приёмник говорят на одном формате — не переводите данные через промежуточный. Сериализация на больших объёмах стоит дороже, чем кажется.
Как жить с меняющимися схемами
Широкие события упираются в практическую проблему: схема системных таблиц меняется от версии к версии, а данные собираются со множества инсталляций разом.
Решение изящное и переносимое:
- При встрече с таблицей её схема хешируется.
- Совпал хеш — пишем в существующую таблицу.
- Не совпал — создаётся новая версия:
text_log_6,text_log_7и так далее. - Поверх всех версий строится логическое представление на движке
Merge, который объединяет их при запросе и сам разбирается с совместимостью колонок.
То есть версионирование схемы решается на уровне хранения, а пользователь запроса видит одну таблицу.
Про Map и JSON
Практическая заметка по типам для полуструктурированных атрибутов:
Mapхорошо работает, когда набор атрибутов небольшой и стабильный;JSON(стал стабильным в v25.3) рассматривают для действительно полуструктурированных данных, но с оговоркой: поиск строки по всем JSON-блобам может обернуться сканированием тысяч колонок.
Это ровно тот компромисс, о котором стоит помнить, проектируя схему под события с произвольными атрибутами: гибкость типа JSON не бесплатна на чтении.
Что забрать себе
- Кладите в событие всё сразу. Одна широкая строка вместо трёх разрезанных представлений — и вопросы можно задавать после инцидента, а не до.
- Считайте стоимость перекладывания форматов. На высоких объёмах именно сериализация, а не запись в базу, становится главной статьёй расхода CPU.
- Не игнорируйте системные таблицы. Самая полезная телеметрия базы обычно не в stdout.
- Версионируйте схему через отдельные таблицы +
Merge, если данные приходят из источников разных версий.
Дальше: Часть 13. LogHouse: квадриллион строк в трёх облаках.