Сколько RAM нужно для Grafana Loki
Loki часто выбирают именно потому, что «Elasticsearch съедает всю память сервера», и это ожидание в целом оправдывается — но не безусловно. Если поставить single binary с настройками по умолчанию и залить в него поток логов с десятка сервисов, память всё равно кончится, просто по другим причинам: не из-за JVM-кучи, а из-за in-memory chunks в ingester, которые не успевают сбрасываться на диск. Разберём, из чего реально складывается расход RAM у Loki, сколько закладывать под разный объём логов и какие параметры конфига двигают потребление сильнее всего.
Содержание
- Почему Loki экономнее по памяти, чем Elasticsearch и Graylog
- Из чего складывается расход RAM: ingester, querier, кеш
- Single binary на VPS: сколько закладывать для старта
- Simple scalable deployment: когда single binary перестаёт хватать
- Настройки, которые сильнее всего двигают RAM
- Promtail/Alloy и Grafana: не забыть про соседей
- Как не упасть в OOM: практические ориентиры
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Почему Loki экономнее по памяти, чем Elasticsearch и Graylog
Ключевое архитектурное решение Loki — не индексировать содержимое логов. Elasticsearch и решения на его основе (включая Graylog) строят полнотекстовый индекс по каждому слову в каждой строке лога, и этот индекс живёт в памяти или активно её использует через файловый кеш — отсюда десятки гигабайт RAM даже на средних объёмах. Loki вместо этого индексирует только метки (labels): имя сервиса, под, хост, уровень логирования. Сама строка лога сжимается и складывается в chunk, а chunk уходит в объектное хранилище (S3, GCS, MinIO или локальный диск) или в filesystem-бэкенд.
Индекс Loki на порядок компактнее индекса Elasticsearch на том же объёме сырых логов. Именно поэтому single binary Loki спокойно работает на VPS с 2-4 ГБ RAM там, где Elasticsearch того же назначения потребовал бы 8-16 ГБ. Подробнее о том, откуда берётся аппетит Elasticsearch к памяти, — в статье сколько RAM нужно для Elasticsearch.
Но экономия не бесплатная: за неиндексированное содержимое приходится платить на этапе запроса. LogQL-запрос без узких меток вида {app="api"} вынужден сканировать сырые chunks, а не искать по индексу, и это может быть медленнее и памятеёмче, чем аналогичный запрос в Elasticsearch. Loki быстр и лёгок, когда запросы опираются на метки; он проседает, если превратить его в полнотекстовый поисковик по содержимому.
Из чего складывается расход RAM: ingester, querier, кеш
Даже в режиме single binary внутри Loki работает несколько логических компонентов, и у каждого свой профиль потребления памяти.
Distributor принимает входящий поток логов от Promtail/Alloy, валидирует метки и распределяет данные по ingester'ам. Сам по себе он лёгкий, держит немного буферов, и его вклад в RAM обычно второстепенный.
Ingester — главный потребитель памяти. Он держит свежие логи в памяти в виде chunks, пока chunk не заполнится до целевого размера или не истечёт время ожидания, и только потом сбрасывает (flush) его в постоянное хранилище. Пока данные не сброшены, они занимают RAM в несжатом или частично сжатом виде — это основная переменная: чем выше поток логов и чем реже flush, тем больше памяти висит в ingester в любой момент времени.
Querier потребляет память под выполнение запросов: чтение chunks (в том числе не сброшенных ещё в ingester), распаковку, фильтрацию по LogQL. Тяжёлые запросы без ограничения по времени и без узких меток — классическая причина скачков RAM именно на этом компоненте.
Кеш (chunks cache, index cache, results cache) — опциональный, но ускоряет повторные запросы через Grafana и попутно откусывает свою долю памяти, если развёрнут in-process, а не через отдельный memcached.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверSingle binary на VPS: сколько закладывать для старта
Для одного сервера или небольшой связки сервисов Loki обычно ставят в режиме -target=all (single binary) вместе с Promtail и Grafana на одной машине через docker-compose:
services:
loki:
image: grafana/loki:3.1.0
command: -config.file=/etc/loki/local-config.yaml
ports:
- "3100:3100"
volumes:
- ./loki-config.yaml:/etc/loki/local-config.yaml
- loki-data:/loki
deploy:
resources:
limits:
memory: 1g
promtail:
image: grafana/promtail:3.1.0
volumes:
- ./promtail-config.yaml:/etc/promtail/config.yaml
- /var/log:/var/log:ro
command: -config.file=/etc/promtail/config.yaml
grafana:
image: grafana/grafana:11.2.0
ports:
- "3000:3000"
volumes:
loki-data:
Ориентиры по RAM для single binary (это именно ориентиры для планирования, а не измеренные бенчмарки — у вас цифры будут отличаться в зависимости от кардинальности меток и частоты запросов):
| Сценарий | Поток логов | RAM для Loki | RAM всего сервера (с Grafana, Promtail, ОС) |
|---|---|---|---|
| Личный проект, 1-3 сервиса | до 1 ГБ логов/день | 512 МБ - 1 ГБ | 2 ГБ |
| Малый прод, 5-10 сервисов | 1-5 ГБ логов/день | 1-2 ГБ | 4 ГБ |
| Средний прод, десятки контейнеров | 5-20 ГБ логов/день | 2-4 ГБ | 6-8 ГБ |
Ставить лимит memory в docker-compose для Loki — хорошая практика: если ingester вдруг начнёт копить chunks быстрее, чем успевает их сбрасывать (например, из-за проблем с диском или бэкендом хранения), лучше получить контролируемый OOM-kill и перезапуск контейнера, чем положить своп и утащить за собой всю машину.
Simple scalable deployment: когда single binary перестаёт хватать
Когда логов становится действительно много (десятки-сотни ГБ в день) или нужна отказоустойчивость, Loki разворачивают в режиме simple scalable deployment: отдельно read-путь (querier, query-frontend) и write-путь (distributor, ingester), каждый со своим числом реплик и лимитами.
# фрагмент loki-config.yaml для scalable-режима
limits_config:
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
max_streams_per_user: 10000
retention_period: 336h # 14 дней
ingester:
chunk_idle_period: 30m
chunk_target_size: 1572864 # 1.5 МБ
chunk_retain_period: 1m
max_chunk_age: 2h
Ориентировочная раскладка по компонентам при таком объёме:
| Компонент | Роль | Типичный RAM на реплику |
|---|---|---|
| Ingester | приём и буферизация chunks | 2-4 ГБ |
| Querier | выполнение LogQL-запросов | 1-2 ГБ на реплику, растёт с числом параллельных запросов |
| Distributor | приём и валидация от Promtail | 512 МБ - 1 ГБ |
| Query-frontend | кеш результатов, разбивка запросов | 512 МБ - 1 ГБ |
| Memcached (chunks/index cache) | ускорение повторных запросов | по вашему выбору, обычно 1-4 ГБ |
Для такого масштаба уже разумно разносить компоненты по нескольким машинам или как минимум резервировать под них выделенный сервер, а не подселять к продовым сервисам — колебания в потоке логов (например, всплеск ошибок при инциденте) не должны конкурировать за память с приложением, которое эти логи как раз и генерирует.
Настройки, которые сильнее всего двигают RAM
Несколько параметров loki-config.yaml напрямую управляют тем, сколько данных Loki держит в памяти:
chunk_target_size— целевой размер chunk перед сбросом на диск. Больше значение — реже flush, но больше несжатых данных висит в RAM между сбросами. Уменьшение параметра снижает пиковое потребление ценой более частых операций записи в хранилище.chunk_idle_period— сколько ждать после последней записи в chunk, прежде чем закрыть его и сбросить, даже если целевой размер не достигнут. Для потоков с редкими логами (например, cron-задачи) слишком долгий idle-период держит в памяти много мелких недозаполненных chunks одновременно.max_chunk_age— максимальное время жизни chunk в памяти независимо от размера, ограничивает верхнюю границу накопления при долгоживущих потоках.ingestion_rate_mb/ingestion_burst_size_mb— лимиты на входящий поток. Без них один "болтливый" сервис, который вдруг начал писать логи в цикле из-за бага, способен раздуть ingester по памяти за минуты.max_streams_per_userи вообще кардинальность меток — самая частая скрытая причина утечек RAM. Каждая уникальная комбинация значений меток (label set) создаёт отдельный поток (stream) со своим набором chunks. Если добавить в метки что-то с высокой кардинальностью (например,user_idили полный путь запроса), число потоков может улететь в сотни тысяч, и память уйдёт не на логи, а на служебные структуры учёта потоков. Метки — для того, по чему вы реально фильтруете и группируете (app,env,pod,level), а не для произвольных значений из тела лога.retention_periodи настройка компактора на RAM впрямую не влияют, но при агрессивных запросах по всей истории querier поднимает больше chunks и, соответственно, больше памяти.
Promtail/Alloy и Grafana: не забыть про соседей
Расчёт RAM только под сам Loki — частая ошибка. На той же машине обычно живут ещё как минимум два компонента.
Promtail (или его преемник Alloy) — сборщик, который читает логи на каждом хосте и отправляет их в Loki. Сам по себе он лёгкий: для одного сервера с десятком log-файлов и контейнеров обычно достаточно 128-256 МБ RAM. Но если настроить агрессивный pipeline_stages с регулярными выражениями по каждой строке или включить сбор с большого числа контейнеров через Docker service discovery, потребление растёт — стоит проверять фактическое потребление через docker stats после недели работы под реальной нагрузкой.
Grafana сама по себе не требует много — 256-512 МБ хватает для дашбордов и explore-запросов на несколько пользователей. Но именно через Grafana чаще всего запускают тяжёлые LogQL-запросы без узких меток, и всплеск памяти в такой ситуации обычно происходит на querier, а не на Grafana — важно не путать источник проблемы при диагностике.
Если Loki работает в связке с Prometheus для метрик — а на практике это почти всегда так, — закладывайте память отдельно под каждый компонент: у Prometheus свой профиль потребления, завязанный на кардинальность метрик и период хранения, который с логами напрямую не связан. Про установку этой связки — в статье как установить Grafana и Prometheus на VPS.
Как не упасть в OOM: практические ориентиры
Несколько правил, которые снижают риск OOM-kill на проде:
- Ставьте явный
memory limitна контейнер Loki — управляемый рестарт с потерей нескольких минут несброшенных логов почти всегда лучше, чем зависший от нехватки памяти сервер целиком. - Мониторьте метрику
loki_ingester_memory_chunks(или общее потребление процесса через/metrics) в той же Grafana и повесьте алерт на приближение к лимиту заранее, а не постфактум разбирайте логи падения. - Не выключайте
ingestion_rate_mb"для простоты" на проде — без лимита один зациклившийся сервис может неожиданно стать причиной инцидента с самим Loki. - Проверяйте кардинальность меток регулярно: запрос через API
/loki/api/v1/seriesпокажет, сколько уникальных потоков реально накопилось, и часто это самая быстрая диагностика, если RAM растёт без видимой причины в объёме логов. - Для системных логов самой машины (не тех, что уходят в Loki) не забывайте про ротацию логов, чтобы не забивался диск — они по-прежнему живут по своим правилам через logrotate.
Для сравнения с альтернативным стеком на базе Elasticsearch — Graylog — у него другой баланс между удобством полнотекстового поиска и потреблением памяти; цифры разобраны в статье сколько RAM нужно для Graylog.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Хватит ли 1 ГБ RAM для Loki на маленьком VPS?
Для личного проекта с одним-двумя сервисами и небольшим потоком логов — как правило да, если Promtail и Grafana стоят рядом и тоже укладываются в скромные рамки. Заложите общий бюджет сервера от 2 ГБ, чтобы осталось место ОС и всплескам querier.
Почему Loki ест больше памяти, чем я ожидал, хотя логов немного?
Почти всегда причина — высокая кардинальность меток: в labels попало что-то уникальное для каждой записи (ID пользователя, полный URL). Проверьте через /loki/api/v1/series, сколько реально уникальных потоков, и уберите из меток лишнее.
Можно ли ограничить память Loki так, чтобы он не мог обрушить весь сервер?
Да, через memory limit в docker-compose или MemoryMax в systemd-юните, плюс ingestion_rate_mb/ingestion_burst_size_mb в конфиге — это ограничивает и потребление процесса, и скорость, с которой в него можно залить данные.
Нужен ли отдельный сервер под Loki, если он и так экономный?
Для небольших нагрузок нет. Но как только логов становится много или Loki начинает конкурировать за память с продовыми сервисами при всплесках, разумнее вынести его отдельно — колебания в логировании не должны ронять приложение.
Чем Loki принципиально отличается по памяти от Graylog?
Graylog построен поверх Elasticsearch/OpenSearch и наследует его модель памяти — полнотекстовый индекс требует heap. Loki индексирует только метки, поэтому базовый профиль потребления заметно ниже при сопоставимом объёме логов, но за это платят гибкостью полнотекстового поиска по содержимому.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →