09 мар. 2026 г.·7 мин чтения

Выбор меток Loki, которые держат расходы на логи под контролем

Метки Loki могут незаметно увеличить расходы на хранение. Узнайте, какие значения должны быть метками, какие — полями логов, и как уменьшить шум в индексе.

Выбор меток Loki, которые держат расходы на логи под контролем

Почему метки повышают расходы Loki

Loki остаётся недорогим, когда метки небольшие и стабильные. По умолчанию он не индексирует весь текст лога. Он индексирует метки, и каждое новое значение метки добавляет работу для индекса.

На первый взгляд это звучит безобидно — пока приложение не начинает добавлять метки, которые меняются постоянно. Метка вроде service=api — нормальная, потому что она остаётся одинаковой на множестве строк логов. А вот request_id=9f3... уже дорого обходится, потому что почти каждый запрос создаёт новое значение.

Loki группирует логи в потоки по полному набору меток. Когда метки меняются на каждом запросе, Loki не может просто дописывать логи в несколько крупных потоков. Вместо этого он создаёт огромное количество маленьких потоков.

Это стоит денег по двум причинам. Loki пишет больше метаданных и записей индекса, а также хранит много маленьких чанков вместо меньшего числа крупных. Маленькие чанки менее эффективны для записи, хранения и поиска.

Даже простое приложение быстро упирается в этот предел. Если API обрабатывает 100 запросов в секунду, а одна метка меняется каждый раз, за час можно получить сотни тысяч уникальных потоков. Объём логов почти не изменится, но Loki внезапно станет делать гораздо больше служебной работы.

Чаще всего лишняя нагрузка заметна в тех же местах: больше записей индекса, больше маленьких чанков, больше объектов в хранилище и более тяжёлые запросы, потому что логи размазаны по слишком большому числу потоков.

Вот почему счета за логирование могут расти, даже когда трафик выглядит нормальным. Команда не выпускала ничего необычного. Объём запросов стабилен. Объём логов тоже почти не изменился. Потом кто-то добавляет несколько меток с высокой кардинальностью, меняется схема хранения — и счёт следует за этим.

Это ещё и мешает повседневной работе. Запросы замедляются, потому что Loki приходится обращаться к большему числу потоков. Хранение становится дороже. Фоновая компакция тоже растёт.

Схема простая: маленькие, скучные метки делают индекс узким. Метки с данными на уровень запроса превращают обычные детали логов в индексные данные, и индекс растёт гораздо быстрее, чем сами логи.

Чаще всего команды сталкиваются с этим после добавления меток для user ID, session ID, сырого URL-пути, IP клиента или значений feature flag. Эти поля всё ещё могут быть полезны, но обычно дешевле и удобнее держать их внутри структурированных полей логов, а не в метках.

Если вы используете Grafana и Loki в продакшене, это один из самых простых способов тихо выбрасывать деньги. Приложение выглядит нормально. Трафик стабильный. Индекс всё равно продолжает расти.

Что делает метку хорошей

Хорошая метка немного скучная. В Loki именно это и нужно.

Лучшие метки описывают поток логов, который долго принадлежит одному и тому же набору событий, а не один запрос, исчезающий за секунду. Начните с фактов, которые почти не меняются, например service, environment или, возможно, region, если по нему действительно фильтруют. Эти значения остаются одинаковыми на множестве строк логов, поэтому Loki может объединять их в небольшое число потоков, а не в беспорядок из крошечных.

Помогает простой тест: сужает ли эта метка поток в первую очередь? Если нет, скорее всего, она не должна быть меткой.

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

Теперь сравните это с данными запроса. Request ID, user ID, session ID, cart ID или полный URL-путь могут меняться почти в каждой строке. Эти поля по-прежнему полезны для отладки, но им место в структурированных полях логов, а не в метках.

Простой пример хорошо показывает разницу. Допустим, ваш checkout-сервис записывает ошибку в production. service="checkout" и environment="prod" — хорошие метки, потому что они быстро сужают набор логов. request_id="9f3..." — плохая метка, потому что она создаёт новый поток почти для каждого запроса. Лучше положить этот request ID в тело лога или JSON-поле и искать его там, когда это нужно.

Именно здесь команды чаще всего ошибаются. Они помечают все атрибуты подряд, а потом удивляются, почему растут расходы на хранение и нагрузка на запросы. Loki работает лучше, когда метки сначала отвечают на широкие вопросы маршрутизации, а подробности лежат в полях логов.

Если значение часто меняется, не стоит помещать его в индекс. Если оно остаётся стабильным на тысячах строк и помогает быстро делить логи на части, это, скорее всего, хорошая метка.

Переносите детали поиска в поля логов

Метки лучше всего работают для широких групп, таких как service, environment и region. Шумные детали каждого запроса должны оставаться в самом лог-записи, а не в индексе.

Это значит, что значения вроде request_id, user_id и path обычно должны находиться внутри сообщения как структурированные поля. Если превратить их в метки, Loki создаст больше потоков, сохранит больше индексных данных и сделает запросы тяжелее, чем нужно.

Структурированный JSON упрощает эту задачу. Лог остаётся читаемым, а инструменты по-прежнему могут аккуратно его разобрать. Одна строка может содержать имя события, код статуса, задержку, путь запроса и данные пользователя, не раздувая число меток.

{
  "level": "error",
  "service": "api",
  "env": "prod",
  "message": "request failed",
  "request_id": "9f2c1",
  "user_id": "18442",
  "path": "/billing/invoices",
  "status": 500,
  "duration_ms": 842
}

Так у вас получается понятный поиск в два шага. Сначала используйте небольшой набор меток, чтобы сузить данные до нужного сервиса и среды. Затем распарсьте или отфильтруйте поля внутри этих логов.

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

Хорошее правило простое: спросите себя, повторяется ли значение во множестве строк лога. Если оно меняется почти на каждом запросе, не добавляйте его в метки. Request ID — самый очевидный пример. User ID и сырой путь обычно тоже попадают в ту же категорию, особенно если пути содержат номера аккаунтов, slug или другие уникальные части.

Держите метки маленькими и стабильными, а структурированные поля — для деталей, которые нужны при отладке.

Простой пример для API

Возьмём загруженный API, который работает в production в трёх регионах. Если оставить в метках только service, env и region, Loki нужно будет поддерживать лишь небольшой набор потоков для этого сервиса. Сервис api в prod для us-east, eu-west и ap-south даёт три комбинации меток, а не тысячи.

Этого обычно хватает, чтобы быстро сузить поиск. Подробности по-прежнему можно сохранить, но они должны быть внутри строки лога как поля, а не внутри индекса.

{"ts":"2026-04-13T10:15:22Z","level":"info","message":"request finished","service":"api","env":"prod","region":"us-east","customer_id":"cust_4821","request_id":"req_9f12a7","path":"/v1/invoices","status":200,"duration_ms":83}

В этом примере customer_id и request_id остаются в JSON-теле. Они всё ещё доступны для поиска. Просто они не создают новый поток каждый раз, когда меняются.

Практический запрос выглядит так:

{service="api", env="prod", region="us-east"}
| json
| request_id="req_9f12a7"

В этом и есть суть. Сначала ищите по сервису api с небольшим набором меток. Затем распарсьте строку лога и отфильтруйте один запрос. Вы получаете тот же результат для отладки, но не платите индексной ценой за превращение каждого атрибута запроса в метку.

Разница в числе потоков быстро становится неприятной. Если оставить только service, env и region, один production API в трёх регионах создаёт три группы потоков для этого набора меток. Если добавить customer_id и request_id как метки, число может начать приближаться к одному потоку на запрос. Сервис, который обрабатывает 500 000 запросов в день, может в итоге создавать огромное количество короткоживущих потоков вместо того, чтобы переиспользовать небольшой набор.

Вот почему хорошие метки выглядят скучно. Скучно — это дёшево. Скучно — это удобно для запросов. А во время инцидента вы всё равно сможете найти один плохой запрос, отфильтровав поля логов после того, как Loki сузит поиск до нужного сервиса и региона.

Как постепенно сократить количество меток

Спланируйте более лёгкую схему логирования
Определите стабильные метки, перенесите шумные поля и сделайте Grafana и Loki проще в эксплуатации.

Большинству команд не нужен полный редизайн. Им нужен один честный аудит всех меток, которые выводят приложения.

Сначала соберите полный список меток из всех приложений, задач и лог-shipper'ов. Не полагайтесь на память. Проверьте, что реально попадает в Loki сейчас, потому что старые настройки по умолчанию и разовые изменения часто остаются надолго, даже когда команда уже забыла, зачем их добавляли.

Потом посчитайте, сколько уникальных значений получает каждая метка за обычный день. У метки вроде service может быть 8 значений. У метки вроде request_id — 2 миллиона. Их нельзя ставить в одну категорию, даже если обе кажутся полезными при поиске.

Практическая очистка

Разберите список по простому правилу: если метка меняется почти на каждом запросе, ей, вероятно, не место среди меток.

Оставляйте метки, которые описывают стабильные группы, такие как приложение, среда, регион или уровень логирования. Помечайте как проблемные метки с большим числом дневных значений, например user ID, request ID, session ID, URL-пути с ID или хеши контейнеров. Сначала уберите шумные метки только из одного сервиса, а не меняйте сразу весь парк. Перенесите эти изменяющиеся значения в структурированные поля логов, чтобы их по-прежнему можно было искать.

Затем сравните несколько реальных поисков до и после изменения. Этот шаг важнее, чем кажется большинству команд. Люди часто держатся за плохие метки из страха потерять видимость. На практике большинство запросов продолжают работать нормально, когда значение переезжает в JSON или другое структурированное поле. Вы фильтруете по небольшому набору стабильных меток, а затем ищете внутри содержимого лога.

Для проверки используйте реальные support- или incident-запросы. Найдите один падающий запрос клиента, один всплеск ошибок 500 и одну проблему, связанную с фоновой задачей. Посмотрите на скорость запроса, качество результата и то, по-прежнему ли поиск кажется удобным.

Если у вас уже работают Grafana и Loki рядом с Prometheus, делайте очистку небольшой и спокойной. Измените один сервис, понаблюдайте за ростом индекса и поведением запросов день-два, а потом переходите к следующему. Такой темп помогает избежать сюрпризов и даёт команде доказательство, что более маленькие метки обычно означают более чистое логирование, а не худшую отладку.

Ошибки, которые быстро раздувают индекс

Большинство проблем с затратами в Loki начинаются одинаково. Одна метка казалась полезной для быстрой диаграммы. Потом добавили ещё одну, потом пять, и индекс начал расти гораздо быстрее, чем объём логов.

Частые ошибки легко заметить, когда знаете, на что смотреть.

  • Помещать request_id в метку. У каждого запроса новое значение, поэтому Loki приходится отслеживать огромное число потоков.
  • Использовать полный URL-путь как метку, особенно если в пути есть ID вроде /users/1842/orders/991.
  • По умолчанию добавлять tenant, session или feature_flag в метки, хотя эти значения часто меняются слишком часто для индекса.
  • Оставлять метки надолго после того, как исходная причина уже исчезла, просто потому что их всё ещё использует один старый дашборд.

Проблему с полным путём легко пропустить. Команда может думать, что у неё всего одна метка path, хотя на самом деле она создаёт тысячи значений, потому что каждый customer ID, order ID или slug становится отдельной записью в метке. Если вам действительно нужна фильтрация по маршруту, поместите шаблон маршрута в метку, а точный путь оставьте в структурированных полях.

Данные о tenant и session могут создавать ту же проблему. В многопользовательском приложении метка по tenant может выглядеть разумно, если число tenant'ов небольшое и стабильное. Многие команды делают это слишком рано. Они ещё даже не назвали запрос, который им нужен, а уже платят за индексирование этого поля навсегда.

Старые метки тоже остаются по глупым причинам. Один дашборд всё ещё использует feature_flag, поэтому никто его не удаляет. Возможно, этот дашборд экономит пять минут в месяц, но лишняя метка создаёт нагрузку на хранилище и память каждый день.

Хорошее правило — сначала написать точный запрос, который кто-то будет выполнять каждую неделю, и только потом добавлять новую метку. Если никто не может назвать такой запрос, лучше оставить данные в структурированных полях.

Ранние признаки, что меток стало слишком много

Создайте более лёгкую платформу
Используйте практическую поддержку Fractional CTO, чтобы строить надёжные системы с меньшими затратами на облако и инструменты.

Плохой выбор меток обычно проявляется в метриках раньше, чем кто-то посмотрит на счёт. Неприятный момент в том, что система ещё какое-то время может выглядеть "здоровой", даже когда индекс растёт гораздо быстрее реального объёма логов.

Один из первых тревожных сигналов — число потоков растёт быстрее трафика. Если объём запросов вырос на 10%, а активных потоков стало в 2–3 раза больше, кто-то, скорее всего, добавил метку со слишком большим числом возможных значений, например user ID, путь запроса, session token или build hash.

Ещё один признак — скачок хранилища после релиза, который не менял нагрузку. В этом случае смотрите не только на приложение, но и на схему логов. Небольшое изменение кода, которое превращает один атрибут запроса в метку, может за день создать тысячи новых потоков.

Проблему можно почувствовать и в поиске. Простые вопросы начинают требовать слишком много условий по меткам, чтобы просто сузить набор результатов. Если инженерам приходится добавлять фильтр за фильтром, чтобы найти один класс ошибок, значит, метки делают слишком много работы, а сам лог не несёт достаточно структурированных деталей.

Обычно такие признаки идут вместе:

  • Число потоков растёт намного быстрее, чем число запросов.
  • Хранилище увеличивается сразу после деплоя, хотя нагрузка остаётся стабильной.
  • Запросы становятся капризными и требуют нескольких фильтров по меткам для простого поиска.
  • Loki пишет много маленьких чанков вместо меньшего числа более полных.

Эти маленькие чанки важнее, чем кажется многим командам. Loki работает лучше, когда логи из одного потока остаются вместе достаточно долго, чтобы заполнить разумный размер чанка. Когда метки разбивают трафик на тысячи узких потоков, чанки закрываются раньше, хранение становится менее эффективным, а производительность поиска обычно ухудшается.

Команды часто замечают это на дашбордах раньше, чем в счетах. Простой пример: сервис начинает помечать логи по полному API-маршруту плюс customer ID. Трафик остаётся стабильным, но число потоков и чанков резко подскакивает за ночь. Обычно это не проблема трафика. Это проблема индексирования.

Быстрая проверка перед добавлением новой метки

Получите поддержку Fractional CTO
Привлеките senior-специалиста для поддержки по observability, архитектуре и работе продакшена.

Большинство плохих меток появляется из одной привычки: считать, что каждое полезное поле должно попасть в индекс. Это не так. Метка должна заслужить своё место.

Перед тем как добавить её, спросите себя, как часто это значение повторяется. Если одно и то же значение встречается во множестве строк логов, метка может быть уместной. Environment, имя сервиса, регион и уровень логирования часто подходят. Request ID, user ID, session ID, cart ID и IP обычно — нет.

Помогает короткий чек-лист:

  • Остаётся ли это значение одинаковым на множестве событий?
  • Может ли оно разрастись до тысяч уникальных значений?
  • Нужно ли оно до чтения тела лога?
  • Решит ли ту же задачу структурированное поле?
  • Будет ли больше одного реального запроса использовать его?

Если на первый вопрос ответ «нет», остановитесь. Если на второй ответ «да», остановитесь тоже. Этому полю место в записи лога, а не в метке.

Третий вопрос важнее, чем многие ожидают. Метки помогают сузить область поиска до того, как Loki начнёт анализировать содержимое логов. Если никто не фильтрует по этому полю первым, индексировать его — напрасная трата денег. Оставьте его в структурированных полях, а затем ищите или парсьте его после того, как получите нужный поток.

Четвёртый и пятый вопросы защищают команды от меток "на всякий случай". Поле может быть полезным и при этом плохой меткой. Например, группа API-маршрутов вроде /billing может подойти в качестве метки, если по ней часто фильтруют. Полный URL с query-параметрами лучше оставить в строке лога. Люди смотрят на него при отладке, но немногие команды фильтруют по каждому точному URL.

Если сомневаетесь, начните со структурированного поля. Его всегда можно позже поднять до уровня метки, если увидите повторяющиеся шаблоны запросов. Делать наоборот, когда расходы уже выросли, гораздо неприятнее.

Следующие шаги для более лёгкой настройки Loki

Начните с одного сервиса на этой неделе, а не со всего стека. Выберите самый шумный — обычно это API gateway, auth-сервис или фоновой воркер, который пишет лог на каждый запрос. Одного сервиса достаточно, чтобы показать, что должно остаться меткой, а что лучше перенести в структурированные поля.

Запишите правило, которому команда действительно сможет следовать. Если поле имеет небольшой фиксированный набор значений, и люди используют его для ежедневного деления логов, оно может быть меткой. Если оно меняется на каждый запрос, для каждого пользователя, URL или session — оставьте его в теле лога.

Обычно достаточно простого внутреннего правила:

  • Оставляйте в метках service, environment, region и level логирования.
  • Держите request_id, user_id, session_id, сырой IP и полный путь вне меток.
  • Переносите детали поиска в структурированные поля логов.
  • Проверяйте любую новую метку в code review до релиза.

После каждого изменения следите за цифрами несколько дней. Сначала отслеживайте число потоков, потом рост хранилища и поведение запросов для тех поисков, которые ваша команда действительно выполняет. Если число потоков падает, а хранилище выравнивается, вы движетесь в правильном направлении. Если запросы становятся хуже, решение обычно не в том, чтобы вернуть метку обратно. Лучше сделать структурированные поля удобнее для поиска и сохранить единый формат логов.

Помогает и то, если за это правило отвечает один человек. Без этого команды постепенно снова превращают каждый атрибут запроса в индексные данные, и счёт растёт ещё до того, как кто-то это заметит.

Если нужен второй взгляд, Oleg Sotnikov на oleg.is в рамках Fractional CTO advisory work разбирает observability и инфраструктурные настройки. Он работал с компактными production-стеками на Grafana, Loki и остальном наборе инструментов, поэтому советы обычно остаются практичными.

Откройте один конфиг, уберите одну плохую метку и сравните число потоков и объём хранилища через 48 часов. Этот небольшой тест покажет больше, чем долгий спор.

Часто задаваемые вопросы

Почему `request_id` обычно плохая метка в Loki?

Потому что оно меняется почти при каждом запросе, который логирует приложение. Loki группирует логи по полному набору меток, поэтому меняющийся request_id создаёт огромное количество маленьких потоков и увеличивает нагрузку на индекс и хранение.

Какие метки большинству команд стоит использовать в первую очередь?

Начните с меток, которые остаются стабильными на множестве строк логов, например service, environment, а иногда region или level. Такие значения помогают быстро сузить логи, не создавая отдельный поток для каждого запроса.

Можно ли искать по request ID, если убрать его из меток?

Да. Оставьте его внутри структурированных полей логов, а затем фильтруйте по нему уже после того, как Loki сузит поиск по стабильным меткам. Так вы получите ту же пользу для отладки, не превращая каждый запрос в индексные данные.

Стоит ли помещать полные URL-пути в метки Loki?

Обычно нет, особенно если в путях есть ID, slug или query-параметры. Полный путь создаёт слишком много уникальных значений, поэтому лучше оставить точный путь в теле лога, а в метках использовать только стабильную группу маршрутов, если она действительно нужна.

Когда tenant или customer_id могут быть меткой?

Только если число tenant'ов остаётся небольшим и стабильным, а ваша команда часто фильтрует по tenant. Для большинства приложений tenant или customer_id меняется слишком часто, поэтому хранить его в структурированных полях дешевле, и при этом поиск всё равно работает.

Как провести аудит текущих меток Loki?

Соберите реальные метки из Loki или вашего лог-shipper'а и посчитайте, сколько уникальных значений получает каждая из них за обычный день. Если метка меняется почти на каждом запросе, перенесите её в структурированные поля и проверьте несколько реальных инцидентных поисков после изменения.

Какие признаки показывают, что мои метки раздувают расходы Loki?

Смотрите, растёт ли число потоков быстрее, чем трафик, прыгает ли объём хранилища после деплоя и не стали ли запросы медленнее или сложнее. Обычно это значит, что кто-то добавил метки с слишком большим числом возможных значений.

Не усложнит ли перенос полей из меток отладку?

Как правило, потерь немного. Вы всё равно сначала фильтруете по стабильным меткам, а затем ищете по распарсенным полям внутри подходящих логов. Если поиск стал хуже, лучше доработать структуру логов, чем возвращать шумные поля обратно в метки.

Стоит ли чистить метки сразу во всех сервисах?

Нет. Сначала измените один шумный сервис, понаблюдайте за числом потоков и объёмом хранилища день или два, а потом переходите к следующему. Такой поэтапный запуск показывает, что работает, и не удивляет всю команду.

Что лучше всего проверить перед добавлением новой метки?

Сначала спросите только одно: будет ли это значение повторяться во многих строках логов? Если ответ нет, не добавляйте его в метки. Начните со структурированного поля и повышайте его до метки только если команда действительно использует его в реальных поисках снова и снова.