MAATRIX / Блог / Сколько RAM нужно для Elasticsearch

Сколько RAM нужно для Elasticsearch

MAATRIX

Elasticsearch — тот случай, когда «просто добавить памяти» не работает так линейно, как хотелось бы: половину RAM он отдаёт под JVM-кучу, вторую половину принципиально требует оставить свободной для файлового кеша Lucene, и если нарушить этот баланс, кластер начинает тормозить или падать по OOM даже с виду на мощном сервере. Разберём, откуда берётся аппетит Elasticsearch к памяти, как посчитать нужный объём под свою нагрузку и какие настройки реально спасают от типичных провалов в проде.

Обсудить статью, задать вопрос или начать новую тему

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

Перейти в сообщество →

Почему Elasticsearch делит память на две неравные части

Под капотом Elasticsearch — это Java-процесс поверх библиотеки Lucene, и у памяти здесь два принципиально разных потребителя. Первый — JVM heap: куча, где живут структуры самого Elasticsearch (кеш запросов, буферы индексации, агрегации, метаданные шардов, служебные объекты кластера). Второй — файловый кеш операционной системы: сегменты Lucene на диске читаются через обычные файловые операции, и чем больше их помещается в кеш страниц ОС, тем реже поиск упирается в диск.

Отсюда классическое правило Elastic (его подтверждает и официальная документация, и практика эксплуатации): отдавайте под heap не больше 50% физической RAM сервера, а оставшуюся половину — операционной системе под файловый кеш. Это не рекомендация «на всякий случай» — если отдать под heap 80-90% памяти, Lucene останется без кеша, каждый запрос будет читать сегменты с диска, и производительность поиска просядет в разы даже при формально «мощном» heap.

Второй важный нюанс — потолок heap около 30-31 ГБ, независимо от того, сколько RAM физически стоит в сервере. Это связано с механизмом compressed oops в JVM: пока heap меньше порога (номинально 32 ГБ, но безопасная граница из-за выравнивания объектов ближе к 30-31 ГБ), JVM использует 32-битные сжатые указатели на объекты. Как только heap переваливает за эту границу, JVM переключается на полные 64-битные указатели, и эффективная плотность объектов в heap парадоксально падает, а не растёт вместе с размером кучи. Поэтому на серверах со 128 ГБ и больше RAM не имеет смысла давать Elasticsearch heap 60-64 ГБ — эффективнее держать heap на 30-31 ГБ и добавлять узлы, а не раздувать один процесс.

Сколько RAM нужно на heap для реальной работы

Формулы «RAM = N × размер индекса» не существует — heap Elasticsearch расходуется не столько на сами данные (они лежат в основном в off-heap структурах Lucene и файловом кеше), сколько на служебные операции:

  • Метаданные шардов и сегментов — каждый открытый шард держит в heap структуры для быстрого доступа к своим сегментам; чем больше шардов на узле, тем больше базовый оверхед, даже если сами шарды маленькие.
  • Кеш запросов и агрегаций — bucket-агрегации (terms, date_histogram, вложенные агрегации) строят промежуточные структуры прямо в heap, и на больших кардинальностях полей это может стать основным потребителем памяти в кластере.
  • Индексирующий буфер (indices.memory.index_buffer_size, по умолчанию 10% heap) — буферизует новые документы перед flush на диск; при высокой скорости записи это заметная доля heap.
  • Кеш полей для сортировки и скриптов — если поле не типизировано как doc_value (а по умолчанию для большинства типов doc_values и так off-heap), fielddata может съедать heap непредсказуемо; это одна из классических причин OOM на старых версиях ES.

Практический ориентир, которым реально пользуются при сайзинге: на каждый 1 ГБ heap — не больше 20 активных шардов (более старая рекомендация Elastic была строже, но общий принцип не изменился: чем больше heap, тем больше шардов можно держать открытыми без деградации). Если у вас 50 индексов по 5 шардов каждый на узле с 4 ГБ heap — это уже 250 шардов на 4 ГБ, то есть больше 60 шардов на гигабайт, и кластер будет постоянно давить на heap просто на служебных операциях, ещё до реальной нагрузки поиском.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Таблица: ориентиры по сценариям

Цифры ниже — отправная точка для оценки порядка величины, а не гарантированный результат для вашего конкретного датасета и схемы индексов:

СценарийRAM сервераHeap ESКомментарий
Разработка, тестовый стенд, single-node4 ГБ2 ГБТолько для знакомства с API и локальной отладки, не для реальных данных
Небольшой ELK для логов малого проекта8-16 ГБ4-8 ГБЛоги одного-двух сервисов, retention 7-14 дней
Продакшен-логирование среднего проекта32 ГБ16 ГБНесколько источников логов, ILM с hot/warm-фазами
Поисковый кластер интернет-магазина, сотни тысяч товаров32-64 ГБ16-30 ГБАктивные агрегации по фасетам, много запросов на чтение
Крупная аналитика/логирование, высокая скорость записи64-128 ГБ на узел, несколько узлов30-31 ГБ на узелГоризонтальное масштабирование выгоднее, чем один ram-монстр

Важно: колонка «RAM сервера» всегда примерно вдвое больше heap — это не round-число для красоты, а прямое следствие правила 50/50 из первого раздела. Если видите рекомендацию поставить heap в 24 ГБ на сервер с 32 ГБ RAM — это уже нарушение баланса, и на таком сервере Lucene будет голодать по файловому кешу. Если считаете сайзинг под задачу с нуля и нужен более широкий контекст по подбору конфигурации сервера под аналитическую нагрузку, у нас есть отдельный разбор выделенного сервера для аналитики больших данных.

Роли узлов: где RAM критична, а где можно экономить

В кластере Elasticsearch узлы редко равнозначны по требованиям к памяти — и раздача RAM «поровну на всех» часто просто неэффективна:

  • Data-узлы — самые прожорливые: тут крутится и индексация, и обслуживание поисковых запросов, и агрегации. Основная точка приложения RAM в кластере.
  • Master-узлы (выделенные, node.roles: [master]) — держат только состояние кластера (метаданные индексов, маппинги, распределение шардов), данных не индексируют и не ищут. Для кластера среднего размера достаточно 4-8 ГБ RAM с heap 2-4 ГБ — раздувать его смысла нет.
  • Ingest-узлы — pipeline-обработка документов перед индексацией (парсинг, grok, enrich). RAM нужна под буферы обработки, но заметно меньше, чем data-узлу с тем же трафиком.
  • Coordinating-узлы (без ролей data/master/ingest) — принимают запросы, разбивают по data-узлам, собирают и мёржат результат. При тяжёлых агрегациях по многим шардам именно coordinating-узел может упереться в heap при мёрже — это стоит учитывать на кластерах с десятками data-узлов.

На небольших инсталляциях (до нескольких десятков ГБ данных) все роли обычно совмещают на одних и тех же узлах — разделение ролей начинает окупаться, когда кластер растёт за пределы 3-5 узлов и нагрузка на master-состояние (частые изменения маппингов, много индексов с ILM) начинает мешать обслуживанию запросов.

Настройка: heap, ОС и типичные грабли конфигурации

Heap задаётся через jvm.options (или переменную ES_JAVA_OPTS в Docker) — и Xms/Xmx всегда должны быть равны, иначе JVM будет тратить циклы на изменение размера кучи во время работы:

# docker-compose.yml
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.15.0
    environment:
      - ES_JAVA_OPTS=-Xms16g -Xmx16g
      - bootstrap.memory_lock=true
    ulimits:
      memlock:
        soft: -1
        hard: -1
    deploy:
      resources:
        limits:
          memory: 32g

Обратите внимание на bootstrap.memory_lock: true — эта настройка запрещает ядру выгружать heap Elasticsearch в swap. Своп для JVM-кучи — почти всегда плохая идея: если страницы heap попадут в swap, garbage collector будет тормозить непредсказуемо долго, а задержки поиска станут скачкообразными без явной причины в логах приложения. На сервере с Elasticsearch правильнее вообще снизить vm.swappiness до минимума и держать своп только как аварийную подушку, а не как рабочий механизм — логика подбора размера свопа под такие сценарии разобрана в статье про правильный размер swap для VPS.

Ещё пара параметров ОС, без которых Elasticsearch либо не стартует, либо нестабилен под нагрузкой:

# /etc/sysctl.conf — лимит memory-mapped областей для Lucene + подкачка
vm.max_map_count=262144
vm.swappiness=1

# применить без перезагрузки
sysctl -w vm.max_map_count=262144
# /etc/security/limits.conf — снять ограничения на дескрипторы и память
elasticsearch soft nofile 65536
elasticsearch hard nofile 65536
elasticsearch soft memlock unlimited
elasticsearch hard memlock unlimited

Начиная с Elasticsearch 7.x по умолчанию используется G1GC вместо CMS — для heap от 8 ГБ и выше это, как правило, разумный выбор из коробки, и вручную менять сборщик мусора нужно редко, разве что у вас уже есть конкретные метрики долгих GC-пауз из мониторинга.

Как понять, что памяти не хватает

Три источника, по которым Elasticsearch честно сигнализирует о проблемах с heap, — это API кластера, логи и системные логи ядра:

# Текущее давление на heap по узлам
curl -s "http://localhost:9200/_cat/nodes?v&h=name,heap.percent,ram.percent,cpu"

# Детальная статистика по JVM конкретного узла
curl -s "http://localhost:9200/_nodes/stats/jvm?pretty"

# Сработавшие circuit breaker'ы — ES сам обрывает операции, чтобы не упасть в OOM
curl -s "http://localhost:9200/_nodes/stats/breaker?pretty"

# Был ли OOM killer на уровне ядра
dmesg -T | grep -i "killed process"

Если heap.percent в _cat/nodes стабильно держится выше 85% вне пиков (а не только после тяжёлых агрегаций) — это ранний сигнал: либо шардов на узле слишком много относительно heap, либо агрегации идут по полям с высокой кардинальностью без разумных лимитов (size, terms_enum), либо пора добавлять RAM или узлы. Circuit breaker с ошибкой [parent] Data too large — это ES защитился сам, не дав себе упасть в OOM; частое появление такой ошибки означает, что heap систематически мал для нагрузки, а не разовую случайность.

Полезно смотреть на эти метрики в динамике, а не разово — вынести их на дашборд рядом с остальными метриками сервера. Принципы те же, что и для мониторинга баз данных в целом: подробнее — в статье про мониторинг баз данных через Grafana, только источником метрик для ES выступает отдельный exporter.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

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

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Хватит ли 4 ГБ RAM для продакшена?

Только для очень маленькой нагрузки — единичный индекс, немного документов, невысокий поток записи. Для реального продакшен-логирования или поиска закладывайте от 8 ГБ (heap 4 ГБ), иначе первая же тяжёлая агрегация или всплеск индексации рискует упереться в circuit breaker или OOM.

Правда ли, что heap больше 32 ГБ вреден?

Не «вреден» в смысле поломки, но неэффективен: из-за перехода JVM на 64-битные указатели после отметки compressed oops падает эффективная плотность объектов в heap. Практический потолок — 30-31 ГБ; выше этого лучше добавлять узлы, а не раздувать один процесс.

Что делать, если данных на диске больше, чем есть RAM под файловый кеш?

Это нормальная ситуация — не весь индекс обязан помещаться в кеш целиком, «холодные» сегменты читаются с диска. Здесь важна скорость самого накопителя: на NVMe просадка от кеш-промахов минимальна, на медленных сетевых томах — заметна. Разница между типами дисков в таких сценариях разобрана в статье про NVMe против SATA SSD на сервере.

ELK-стек требует памяти сверх heap ES?

Да, закладывайте отдельно: Logstash с активными фильтрами (grok, mutate) может стабильно потреблять 1-2 ГБ heap своей JVM, Kibana — обычно 512 МБ-1 ГБ. На одном сервере с ES это суммарно добавляет несколько гигабайт сверх того, что заложено под сам Elasticsearch.

Elasticsearch или Kibana — что сложнее по требованиям к ресурсам?

Это разные роли в стеке, а не взаимозаменяемые альтернативы: Kibana — визуализация поверх данных ES. Если выбираете между Kibana и другими инструментами визуализации, у нас есть отдельное сравнение Grafana или Kibana для сервера.

Сколько шардов — уже слишком много для маленького кластера?

Ориентируйтесь на правило «не больше ~20 активных шардов на 1 ГБ heap» как на верхнюю границу, но лучше держаться заметно ниже. Частая ошибка новичков — создавать индекс по умолчанию с 5 шардами там, где хватило бы одного-двух, и за месяцы накопить сотни мелких шардов, каждый из которых съедает heap на метаданные вне зависимости от объёма данных внутри.

Обсудить статью, задать вопрос или начать новую тему

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

Перейти в сообщество →