ADG Оставить заявку
Блог Системное администрирование 5 мин чтения

Grafana Loki 2.8: structured metadata в production и миграция схемы хранения

Апгрейд Loki до 2.8 в production-кластере: structured metadata снижает нагрузку на индекс, миграция схемы и что изменилось в LogQL на практике.

Контекст момента

Grafana Loki 2.8 - structured metadata, улучшенный LogQL и снижение нагрузки на хранилище за счёт выноса метаданных из индекса

Loki 2.8 вышел на прошлой неделе, и мы довольно быстро взяли его в production - не потому что торопились, а потому что одна фича в release notes прямо закрывала задачу, которую мы держали в бэклоге уже месяца три: structured metadata. Рассказываем как прошло и что реально изменилось.

Проблема, которую решали

У нас несколько кластеров Kubernetes с централизованным сбором логов через Promtail -> Loki -> Grafana. Объём логов приличный - сотни гигабайт в день на крупных клиентах, хранение в S3-совместимом объектном хранилище. Индекс в Loki традиционно хранится отдельно (у нас BoltDB-shipper, постепенно мигрируем на TSDB), и именно индекс - главная статья расходов по IOPS и CPU.

Проблема классическая: хочется фильтровать логи по полям вроде trace_id, request_id, user_id - но если добавить эти поля в лейблы Loki, кардинальность индекса взлетает до небес. Мы это проходили: один из клиентов добавил user_id как лейбл, и через неделю Loki начал тормозить на ingestion, а размер индекса вырос в 4 раза. Пришлось откатывать.

Workaround был такой: парсить user_id прямо в LogQL через | json или | logfmt, но это работает только если формат лога позволяет, и это CPU на query-time, а не на write-time. При больших объёмах и сложных запросах это ощутимо.

Structured metadata: что это

В 2.8 появился третий уровень хранения данных о логе - помимо лейблов (индексируются) и тела лога (не индексируется). Structured metadata - это пары ключ-значение, которые прикрепляются к конкретной записи лога, хранятся рядом с чанком, но не попадают в индекс. Их можно фильтровать в LogQL через лейбл-фильтры напрямую, они видны в результатах запроса.

Идея простая: pod, namespace, job - в лейблы (фильтрация по ним в 99% запросов). trace_id, request_id, span_id - в structured metadata (нужны для drill-down, но не для первичного поиска). Тело лога - остаётся телом лога.

На уровне конфига Promtail это выглядит так:

pipeline_stages:
  - json:
      expressions:
        trace_id: trace_id
        request_id: request_id
  - structured_metadata:
      trace_id:
      request_id:

Поля убираются из лейблов, пишутся в metadata. LogQL для поиска по ним:

{namespace="production", app="api"} | trace_id="abc123"

Синтаксис тот же что для лейбл-фильтров, что удобно - не надо переучиваться.

Миграция схемы: schema_config и период перекрытия

Самое неудобное в апгрейде Loki - не сам бинарник, а схема хранения. Loki хранит периоды (periods) в конфиге, и при смене схемы нужно корректно закрыть старый период и открыть новый. Структурированные метаданные требуют минимум схемы v13 (в 2.8 это новый тип, схемы v11/v12 metadata не поддерживают).

Наш конфиг до апгрейда:

schema_config:
  configs:
    - from: 2022-01-01
      store: boltdb-shipper
      object_store: s3
      schema: v11
      index:
        prefix: index_
        period: 24h

После - добавляем новый период с v13:

schema_config:
  configs:
    - from: 2022-01-01
      store: boltdb-shipper
      object_store: s3
      schema: v11
      index:
        prefix: index_
        period: 24h
    - from: 2023-04-03
      store: tsdb
      object_store: s3
      schema: v13
      index:
        prefix: index_tsdb_
        period: 24h

Важный момент: дата начала нового периода не может быть в прошлом. Если поставить дату вчера - Loki откажется стартовать с ошибкой про перекрытие периодов. Мы поставили текущую дату, и новая схема начала применяться с сегодняшнего дня. Старые данные остаются читаемыми через старую схему - Loki умеет работать с несколькими периодами одновременно.

Заодно переехали с BoltDB-shipper на TSDB - это отдельная история, но в 2.8 TSDB стал дефолтным и рекомендованным. TSDB заметно быстрее на запросах с агрегацией по времени.

Что получили на практике

Прошло несколько дней после апгрейда, и можно сделать первые наблюдения - без громких цифр, просто по ощущениям и метрикам Grafana на самом Loki.

Размер индекса растёт медленнее. На одном из кластеров мы перевели в structured metadata около 8 полей, которые раньше были либо в лейблах (4 поля), либо дублировались в теле лога и парсились на query-time (4 поля). Индекс за первые трое суток на новой схеме вырос на треть меньше чем за аналогичный период до апгрейда. Выборка маленькая, но направление правильное.

Запросы по trace_id и request_id стали работать предсказуемее. Раньше фильтрация через | json | trace_id="..." иногда была медленной из-за необходимости читать все чанки за период и парсить JSON налету. Теперь metadata-фильтр применяется раньше, чтение чанков сокращается. Субъективно - заметно на периодах больше суток.

Новый LogQL: | keep и | drop. Это не связано с metadata напрямую, но появилось в 2.8. Операторы позволяют оставить или выбросить поля из результата запроса. Полезно когда парсишь жирный JSON-лог и хочешь в результатах видеть только 3-4 поля - не надо городить сложный label_format.

Что не понравилось

Structured metadata не работает с push-API если клиент не поддерживает новый формат. Promtail 2.8 поддерживает, Vector - добавили поддержку недавно, Fluentbit - пока нужно проверять. У нас один кластер с Fluentbit как shipper - там metadata пока не используем, ждём проверки совместимости.

Документация по metadata-фильтрации в момент релиза была откровенно куцей - пара примеров и всё. Пришлось читать тесты в исходниках чтобы понять граничные случаи с regexp-фильтрами.


В целом апгрейд прошёл рабочим образом - structured metadata закрывает реальную проблему с кардинальностью, которая у нас висела давно. Для клиентов на нашей managed-инфраструктуре будем переводить постепенно: сначала там где индекс растёт быстрее всего и есть высококардинальные поля. Посмотрим что покажут данные за полный месяц на новой схеме.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.