Компоненты ClickHouse, имеющие отношение к OpenTelemetry
- OpenTelemetry Collector — это прокси-компонент, который принимает, обрабатывает и экспортирует данные телеметрии. В решениях на базе ClickHouse этот компонент используется как для сбора логов, так и для обработки событий перед батчингом и вставкой.
- SDK для языков программирования, реализующие спецификацию, API и экспорт данных телеметрии. Эти SDK обеспечивают корректную запись трассировок в коде приложения, создают входящие в них спаны и передают контекст между сервисами через метаданные, формируя тем самым распределённые трассировки и позволяя коррелировать спаны. Эти SDK дополняются экосистемой средств автоматической поддержки распространённых библиотек и фреймворков, поэтому пользователю не нужно изменять свой код, и он получает инструментацию из коробки.
Дистрибутивы
- Уменьшить размер коллектора, что сокращает время его развертывания
- Повысить безопасность коллектора за счёт сокращения доступной поверхности атаки
Ингестия данных с OTel
Роли развертывания коллектора
- Агент - Экземпляры агента собирают данные на периферии, например на серверах или узлах Kubernetes, либо получают события напрямую от приложений, в которые встроен OpenTelemetry SDK. Во втором случае экземпляр агента запускается вместе с приложением или на том же хосте, что и приложение (например, как sidecar или ДемонСет). Агенты могут отправлять свои данные либо напрямую в ClickHouse, либо в экземпляр шлюза. В первом случае это называется моделью развертывания агента.
- Шлюз - Экземпляры шлюза предоставляют отдельный сервис (например, в виде Развертывания в Kubernetes), обычно на кластер, центр обработки данных или регион. Они получают события от приложений (или других коллекторов в роли агентов) через единую конечную точку OTLP. Обычно развертывают набор экземпляров шлюза, а для распределения нагрузки между ними используют стандартный балансировщик нагрузки. Если все агенты и приложения отправляют свои сигналы в эту единую конечную точку, это часто называется моделью развертывания шлюза.
Сбор журналов
- Сбор через ресивер filelog - Этот приёмник читает файлы журналов на диске, формирует сообщения журналов и отправляет их в ClickHouse. Он также решает более сложные задачи: определяет многострочные сообщения, обрабатывает ротацию журналов, сохраняет контрольные точки для устойчивости к перезапуску и извлекает структуру. Кроме того, этот приёмник может читать журналы контейнеров Docker и Kubernetes, разворачиваться как Helm-чарт, извлекать из них структуру и обогащать их сведениями о поде.
Совет:
otelbin.iootelbin.io удобно использовать для проверки и визуализации конфигураций.Структурированные и неструктурированные
Пример
json_parser. Измените путь к файлу access-structured.log.
Рассмотрите использование ClickHouse для разбораВ примере ниже из журнала извлекается временная метка. Для этого требуется оператор
json_parser, который преобразует всю строку журнала в JSON-строку и помещает результат в LogAttributes. Это может быть ресурсоёмко, и в ClickHouse это можно сделать эффективнее — Извлечение структуры с помощью SQL. Эквивалентный пример для неструктурированных данных, в котором для этого используется regex_parser, можно найти здесь.filelog); например, вместо otelcol_0.102.1_darwin_arm64.tar.gz нужно скачать otelcol-contrib_0.102.1_darwin_arm64.tar.gz. Релизы доступны здесь.
После установки OTel collector можно запустить следующими командами:
Body, а JSON автоматически извлекается в поле Attributes благодаря json_parser. Этот же оператор используется для извлечения временной метки в соответствующий столбец Timestamp. Рекомендации по обработке журналов с помощью OTel см. в разделе Обработка.
ОператорыОператоры — это базовая единица обработки журналов. Каждый оператор выполняет одну конкретную задачу, например читает строки из файла или разбирает JSON из поля. Затем операторы объединяются в конвейер, чтобы получить нужный результат.
TraceID или SpanID. Если они присутствуют, например когда пользователи реализуют распределённую трассировку, их можно извлечь из JSON теми же способами, что показаны выше.
Пользователям, которым нужно собирать локальные файлы журналов или файлы журналов Kubernetes, мы рекомендуем ознакомиться с доступными параметрами конфигурации приёмника filelog, а также с тем, как обрабатываются смещения и разбор многострочных журналов.
Сбор журналов Kubernetes
ResourceAttributes. В настоящее время ClickHouse использует для этого столбца тип Map(String, String). Подробнее о работе с этим типом и его оптимизации см. в разделах Using Maps и Extracting from maps.
Сбор трассировок
Пример
telemetrygen. Инструкции по установке приведены здесь.
Следующая конфигурация принимает события трассировок через OTLP-приёмник, а затем отправляет их в stdout.
config-traces.xml
telemetrygen:
Обработка — фильтрация, преобразование и обогащение
-
Процессоры - Процессоры берут данные, собранные приёмниками, и изменяют или преобразуют их перед отправкой в экспортёры. Процессоры применяются в том порядке, в котором они указаны в разделе
processorsконфигурации collector. Они необязательны, но обычно рекомендуется использовать минимальный набор. При использовании OTel collector с ClickHouse мы рекомендуем ограничиться следующими процессорами:- memory_limiter используется для предотвращения нехватки памяти в collector. Рекомендации см. в разделе Оценка ресурсов.
- Любой процессор, выполняющий обогащение на основе контекста. Например, Kubernetes Attributes Processor позволяет автоматически задавать атрибуты ресурсов для spans, метрик и журналов на основе метаданных k8s, например обогащать события идентификатором исходного пода.
- Хвостовое или головное сэмплирование — если это требуется для traces.
- Базовая фильтрация - отбрасывание ненужных событий, если это нельзя сделать через оператор (см. ниже).
- Батчинг - крайне важен при работе с ClickHouse, чтобы данные отправлялись батчами. См. “Экспорт в ClickHouse”.
- Операторы - Операторы представляют собой самую базовую единицу обработки, доступную на уровне приёмника. Поддерживается базовый парсинг, позволяющий задавать такие поля, как Severity и Timestamp. Здесь поддерживаются парсинг JSON и regex, а также фильтрация событий и базовые преобразования. Мы рекомендуем выполнять фильтрацию событий именно здесь.
Пример
regex_parser) и фильтрации событий, а также процессор для объединения событий в батчи и ограничения использования памяти.
config-unstructured-logs-with-processor.yaml
Экспорт в ClickHouse
Используйте OpenTelemetry Collector ContribЭкспортер ClickHouse входит в состав OpenTelemetry Collector Contrib, а не основной дистрибуции. Вы можете либо использовать дистрибутив contrib, либо собрать собственный коллектор.
- pipelines - Приведённая выше конфигурация показывает использование конвейеров, состоящих из набора приёмников, процессоров и экспортеров, с отдельными конвейерами для журналов и трассировок.
- endpoint - Взаимодействие с ClickHouse настраивается через параметр
endpoint. Строка подключенияtcp://localhost:9000?dial_timeout=10s&compress=lz4&async_insert=1задаёт обмен данными по TCP. Если по соображениям переключения трафика вы предпочитаете HTTP, измените эту строку подключения, как описано здесь. Полные сведения о подключении, включая возможность указать имя пользователя и пароль в этой строке подключения, приведены здесь.
- ttl - это значение определяет, как долго хранятся данные. Дополнительные сведения приведены в разделе “Управление данными”. Его следует задавать в часах, например 72h. В примере ниже мы отключаем TTL, поскольку наши данные относятся к 2019 году и ClickHouse немедленно удалит их после вставки.
- traces_table_name and logs_table_name - определяют имена таблиц для журналов и трассировок.
- create_schema - определяет, будут ли при запуске создаваться таблицы со схемами по умолчанию. Для начальной настройки по умолчанию используется true. Следует установить false и определить собственную схему.
- database - целевая база данных.
- retry_on_failure - настройки, определяющие, следует ли повторять отправку неудачных батчей.
- batch - пакетный процессор гарантирует, что события отправляются батчами. Мы рекомендуем значение не менее 10 000 и тайм-аут 5s (если позволяет память, можно использовать значения до 100 000). Как только будет достигнут любой из этих порогов, батч будет отправлен в экспортер. Уменьшение этих значений снижает задержку конвейера, и данные становятся доступны для запросов быстрее, но ценой большего числа подключений и батчей, отправляемых в ClickHouse. Это не рекомендуется, если вы не используете асинхронные вставки, так как это может вызвать проблему too many parts в ClickHouse. И наоборот, если вы используете асинхронные вставки, доступность этих данных для запросов также будет зависеть от настроек асинхронной вставки, хотя данные всё равно будут раньше отправляться из коннектора. Подробнее см. в разделе Batching.
- sending_queue - управляет размером очереди отправки. Каждый элемент очереди содержит батч. Если очередь будет переполнена, например из-за недоступности ClickHouse при продолжающем поступлении событий, батчи будут отброшены.
telemetrygen:
Стандартная схема
create_schema. Кроме того, имена таблиц для журналов и трассировки можно изменить со значений по умолчанию otel_logs и otel_traces с помощью настроек, указанных выше.
В схемах ниже предполагается, что TTL включен и равен 72h.
otelcol-contrib v0.102.1):
- По умолчанию таблица разбита на партиции по дате с помощью
PARTITION BY toDate(Timestamp). Это позволяет эффективно удалять данные после истечения срока их хранения. - TTL задаётся через
TTL toDateTime(Timestamp) + toIntervalDay(3)и соответствует значению, заданному в конфигурации коллектора.ttl_only_drop_parts=1означает, что удаляются только целые части, когда срок хранения истёк для всех содержащихся в них строк. Это эффективнее, чем удалять строки внутри частей, так как это требует дорогостоящей операции delete. Мы рекомендуем всегда включать этот параметр. Подробнее см. в разделе Управление данными с помощью TTL. - В таблице используется классический движок
MergeTree. Он рекомендуется для журналов и трассировок, и менять его обычно не требуется. - Таблица упорядочена по
ORDER BY (ServiceName, SeverityText, toUnixTimestamp(Timestamp), TraceId). Это означает, что запросы будут оптимизированы для фильтров поServiceName,SeverityText,TimestampиTraceId— столбцы, расположенные раньше в списке, фильтруются быстрее, чем более поздние; например, фильтрация поServiceNameбудет значительно быстрее, чем поTraceId. Вам следует изменить этот порядок в соответствии с ожидаемыми шаблонами доступа — см. Выбор первичного ключа. - В приведённой выше схеме к столбцам применяется
ZSTD(1). Это обеспечивает наилучшее сжатие для журналов. Вы можете увеличить уровень сжатия ZSTD (выше значения по умолчанию, равного 1) для лучшего сжатия, хотя на практике это редко даёт заметную пользу. Увеличение этого значения приведёт к большей нагрузке на CPU во время вставки (при сжатии), хотя распаковка (а значит, и запросы) должна остаться примерно на том же уровне. Дополнительные сведения см. здесь. Дополнительное delta-кодирование также применяется к Timestamp, чтобы уменьшить его размер на диске. - Обратите внимание, что
ResourceAttributes,LogAttributesиScopeAttributesимеют тип Map. Важно понимать различия между ними. О том, как обращаться к этим Map и оптимизировать доступ к ключам внутри них, см. в разделе “Использование maps”. - Большинство остальных типов здесь, например
ServiceNameкак LowCardinality, уже оптимизированы. Обратите внимание, чтоBody, который в наших примерах логов представляет собой JSON, хранится как String. - К ключам и значениям Map, а также к столбцу
Bodyприменяются bloom-фильтры. Они помогают ускорить запросы, обращающиеся к этим столбцам, но обычно не являются обязательными. См. Вторичные индексы/индексы пропуска данных.
Оптимизация вставок
Батчинг
- (1) Если на узле, принимающем данные, возникают проблемы, запрос на вставку завершится по тайм-ауту (или вернёт более конкретную ошибку), и подтверждение не будет получено.
- (2) Если узел записал данные, но не может вернуть подтверждение отправителю запроса из-за проблем с сетью, отправитель либо получит тайм-аут, либо ошибку сети.
timeout пакетного процессора, что обеспечит низкую сквозную задержку конвейера и стабильный размер батчей.
Использование асинхронных вставок
timeout пакетного процессора. Это может приводить к проблемам — именно в таких ситуациях и нужны асинхронные вставки. Обычно это происходит, когда коллекторы в роли агента настроены на отправку данных напрямую в ClickHouse. Шлюзы, выступая в роли агрегаторов, могут смягчить эту проблему — см. Масштабирование со шлюзами.
Если нельзя гарантировать большие батчи, можно делегировать батчинг ClickHouse, используя асинхронные вставки. При асинхронных вставках данные сначала помещаются в буфер, а затем позже, то есть асинхронно, записываются в хранилище базы данных.
При включенных асинхронных вставках, когда ClickHouse ① получает запрос на вставку, данные запроса ② сразу записываются во внутренний буфер в памяти. Когда ③ происходит следующий сброс буфера, данные из буфера сортируются и записываются как часть в хранилище базы данных. Обратите внимание, что до сброса в хранилище базы данных эти данные недоступны для поиска запросами; сброс буфера настраивается.
Чтобы включить асинхронные вставки для коллектора, добавьте async_insert=1 в строку подключения. Мы рекомендуем использовать wait_for_async_insert=1 (значение по умолчанию), чтобы получить гарантии доставки — дополнительные сведения см. здесь.
Данные из async insert записываются после сброса буфера ClickHouse. Это происходит либо после превышения async_insert_max_data_size, либо через async_insert_busy_timeout_ms миллисекунд с момента первого запроса INSERT. Если для async_insert_stale_timeout_ms установлено ненулевое значение, данные записываются через async_insert_stale_timeout_ms milliseconds с момента последнего запроса. Эти параметры можно настроить, чтобы управлять сквозной задержкой конвейера. Дополнительные параметры для настройки сброса буфера описаны здесь. Обычно значений по умолчанию достаточно.
Рассмотрите адаптивные асинхронные вставкиВ случаях, когда используется небольшое количество агентов, при низкой пропускной способности, но строгих требованиях к сквозной задержке, могут быть полезны адаптивные асинхронные вставки. Однако обычно они не подходят для сценариев обсервабилити с высокой пропускной способностью, характерных для ClickHouse.
async_insert_deduplicate.
Полные сведения о настройке этой возможности можно найти здесь, а более подробный разбор — здесь.
Архитектуры развертывания
Только агенты
- Масштабирование соединений - Каждый агент будет устанавливать соединение с ClickHouse. Хотя ClickHouse способен поддерживать сотни, а то и тысячи одновременных соединений для вставки, со временем это станет ограничивающим фактором и сделает вставки менее эффективными — то есть ClickHouse будет тратить больше ресурсов на поддержание соединений. Использование шлюзов уменьшает количество соединений и повышает эффективность вставок.
- Обработка на периферии - В этой архитектуре любые преобразования или обработка событий должны выполняться либо на периферии, либо в ClickHouse. Это не только накладывает ограничения, но и может означать либо сложные materialized view в ClickHouse, либо перенос значительной вычислительной нагрузки на периферию, где ресурсы ограничены и могут пострадать критически важные сервисы.
- Маленькие батчи и задержки - Коллекторы-агенты могут по отдельности собирать очень мало событий. Обычно это означает, что их нужно настроить на сброс данных через заданный интервал, чтобы соблюдать SLA доставки. В результате collector может отправлять в ClickHouse маленькие батчи. Хотя это и является недостатком, его можно смягчить с помощью асинхронных вставок — см. Оптимизация вставок.