MAATRIX / Блог / OpenSearch на сервере: частые ошибки и решения

OpenSearch на сервере: частые ошибки и решения

MAATRIX

После смены лицензии Elasticsearch многие команды переехали на OpenSearch — форк, который остался под Apache 2.0 и почти полностью совместим по API. На бумаге переезд выглядит безболезненно, но на практике первый же деплой на своём сервере упирается в одни и те же грабли: сервис не стартует из-за лимитов ядра, кластер уходит в жёлтый или красный статус, индекс внезапно становится read-only. Ниже — разбор самых частых ошибок с конкретными командами, которые реально помогают, без теории про архитектуру Lucene.

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

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

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

"max virtual memory areas vm.max_map_count is too low" — сервис не стартует вообще

Самая частая причина, по которой OpenSearch падает в первые секунды после systemctl start opensearch. Lucene активно использует mmap для работы с сегментами индекса, и ядру Linux по умолчанию не хватает лимита на количество memory-mapped областей.

Проверить текущее значение:

sysctl vm.max_map_count

Если меньше 262144 — поднимаем:

sudo sysctl -w vm.max_map_count=262144

Это разовое изменение, оно слетит после перезагрузки. Закрепляем постоянно:

echo "vm.max_map_count=262144" | sudo tee /etc/sysctl.d/99-opensearch.conf
sudo sysctl --system

Вторая частая связка — лимиты на файловые дескрипторы и заблокированную память. Если в логах видно max file descriptors too low или memory locking requested but is not supported, правим /etc/security/limits.d/opensearch.conf:

opensearch soft nofile 65536
opensearch hard nofile 65536
opensearch soft memlock unlimited
opensearch hard memlock unlimited

Важный нюанс: systemd не читает limits.conf для сервисов, запущенных через unit-файл. Нужно явно прописать лимиты в самом юните:

sudo systemctl edit opensearch

и добавить:

[Service]
LimitMEMLOCK=infinity
LimitNOFILE=65536

После этого systemctl daemon-reload && systemctl restart opensearch.

Процесс стартует и сразу падает: как читать причину

Когда сервис не просто "не стартует", а падает уже после запуска (иногда через минуту-две), самый быстрый способ понять причину — не лезть в конфиги наугад, а смотреть системный журнал:

journalctl -u opensearch -n 200 --no-pager

Если в выводе тишина по делу, но процесс умер — проверьте, не сработал ли OOM killer:

dmesg -T | grep -i "killed process"

Если строка нашлась — это почти всегда неправильно выставленный heap. По умолчанию OpenSearch пытается взять около половины оперативной памяти сервера, но на VPS с 2-4 ГБ этого может быть слишком много с учётом других процессов. Heap задаётся файлом в config/jvm.options.d/, например config/jvm.options.d/heap.options:

-Xms2g
-Xmx2g

Значения Xms и Xmx должны совпадать — это исключает паузы на изменение размера кучи "на лету". Общее правило: heap — не больше 50% от RAM сервера и не больше ~30 ГБ (выше упирается в потерю compressed oops в JVM, и прирост не оправдан). Оставшуюся половину памяти сознательно отдаём под файловый кэш ОС — Lucene активно на него полагается при чтении сегментов с диска.

Если сервер регулярно уходит в своп из-за того, что heap выставлен впритык к лимиту RAM, разберитесь сначала с правильным размером swap — для OpenSearch своп скорее враг: подкачка кучи JVM превращает любую операцию GC в многосекундный стопор кластера.

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

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

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

Кластер health = yellow или red

GET _cluster/health?pretty — первая команда, с которой стоит начинать любой разбор проблем с кластером:

curl -s -u admin:'ВашПароль' -k https://localhost:9200/_cluster/health?pretty

Красный статус означает, что часть данных недоступна вообще (unassigned primary shard), жёлтый — что primary-шарды на месте, но реплики не назначены. Чтобы увидеть, какие именно шарды в проблеме:

curl -s -u admin:'ВашПароль' -k "https://localhost:9200/_cat/shards?v&h=index,shard,prirep,state,unassigned.reason"

Для конкретного индекса причину неназначения объясняет отдельный API:

curl -s -u admin:'ВашПароль' -k -X GET "https://localhost:9200/_cluster/allocation/explain?pretty"

Самая частая причина жёлтого статуса на своём сервере — банальная: кластер состоит из одного узла, а number_of_replicas у индексов по умолчанию равен 1. Реплику ставить некуда — второго узла нет, и кластер повиснет в жёлтом навсегда, хотя данные целы. Решение для single-node установки — явно занулить реплики:

curl -s -u admin:'ВашПароль' -k -X PUT "https://localhost:9200/_all/_settings" \
  -H 'Content-Type: application/json' \
  -d '{"index": {"number_of_replicas": 0}}'

Если шард завис в состоянии ALLOCATION_FAILED после сбоя (например, ноду убило по OOM в момент записи), после исправления причины часто помогает принудительный ретрай:

curl -s -u admin:'ВашПароль' -k -X POST "https://localhost:9200/_cluster/reroute?retry_failed=true"

Диск заполнился — индексы ушли в read-only

Классический сценарий: логи льются в OpenSearch месяцами, диск подбирается к 90%, и внезапно запись начинает падать с ошибкой вида cluster_block_exception... FORBIDDEN/12/index read-only / allow delete. Это не баг, а защитный механизм — водяные знаки диска (disk watermarks).

По умолчанию:

  • low — 85% занятого диска: новые шарды перестают размещаться на этой ноде;
  • high — 90%: OpenSearch начинает переносить шарды с ноды;
  • flood_stage — 95%: все индексы на этом диске принудительно переводятся в read-only.

Проверить, что происходит с местом на нодах кластера:

curl -s -u admin:'ВашПароль' -k "https://localhost:9200/_cat/allocation?v"

Дальше — по порядку. Сначала освобождаем место (удаляем старые индексы, настраиваем ILM/ISM-политику на ротацию логов). Потом обязательно снимаем блок read-only вручную — сам по себе он не снимается, даже если места стало достаточно:

curl -s -u admin:'ВашПароль' -k -X PUT "https://localhost:9200/_all/_settings" \
  -H 'Content-Type: application/json' \
  -d '{"index.blocks.read_only_allow_delete": null}'

Если постоянно упираетесь в этот порог — стоит настроить мониторинг диска на сервере с алертом задолго до 85%, а не разбираться с этим постфактум в 3 часа ночи. Пороги при желании можно сдвинуть в opensearch.yml, но это лечит симптом, а не причину нехватки места:

cluster.routing.allocation.disk.watermark.low: 85%
cluster.routing.allocation.disk.watermark.high: 90%
cluster.routing.allocation.disk.watermark.flood_stage: 95%

Медленная индексация и поиск при большом потоке логов

Если OpenSearch используется под сбор логов (частый сценарий для тех, кто переезжает с ELK), при бурном потоке записи легко упереться в производительность. Несколько рабочих приёмов:

  • Во время массовой первичной загрузки временно отключите refresh и реплики — это резко ускоряет bulk-запись:
curl -s -u admin:'ВашПароль' -k -X PUT "https://localhost:9200/my-index/_settings" \
  -H 'Content-Type: application/json' \
  -d '{"index": {"refresh_interval": "-1", "number_of_replicas": 0}}'

После загрузки верните refresh_interval в разумное значение (обычно 5s-30s для потока логов, а не дефолтную 1s).

  • Пишите через _bulk пакетами, а не по одному документу. Ориентируйтесь на пакеты 5-15 МБ — точную оптимальную цифру лучше подбирать под свою нагрузку и диск (NVMe и обычный SSD дадут разный потолок).
  • Ошибка circuit_breaking_exception: [parent] Data too large — почти всегда следствие того, что запрос (обычно тяжёлая агрегация или глубокая пагинация) пытается вытащить в память больше, чем позволяет heap. Для листания больших выдач используйте search_after вместо from/size — глубокий offset в OpenSearch дорог по памяти на каждой ноде.
  • После окончания массовой загрузки старых данных, которые больше не пишутся, _forcemerge уменьшает число сегментов и ускоряет последующий поиск:
curl -s -u admin:'ВашПароль' -k -X POST "https://localhost:9200/my-index/_forcemerge?max_num_segments=1"

Учтите, что forcemerge — тяжёлая операция по I/O, запускать её на "живом" горячем индексе, который продолжают активно писать, не стоит.

Ошибки Security plugin и TLS при подключении

Свежая установка OpenSearch поднимается с демо-сертификатами и предупреждением в логах вида OpenSearch Security not fully configured. Это нормально для первого запуска, но означает, что сертификаты и пароли — тестовые и не годятся для боевого сервера.

Типичная ошибка при обращении к API без флага -k или сертификата — curl ругается на untrusted certificate, потому что демо-CA не знаком системе:

curl -s -u admin:'ВашПароль' --cacert /etc/opensearch/certs/root-ca.pem \
  "https://localhost:9200/_cluster/health?pretty"

Для боевого сервера сертификаты нужно сгенерировать свои (или получить от внутреннего CA) и применить конфигурацию security через securityadmin.sh:

cd /usr/share/opensearch/plugins/opensearch-security/tools
./securityadmin.sh -cd ../securityconfig/ -icl -nhnv \
  -cacert /etc/opensearch/certs/root-ca.pem \
  -cert /etc/opensearch/certs/admin.pem \
  -key /etc/opensearch/certs/admin-key.pem

Отключать security plugin (plugins.security.disabled: true) имеет смысл только в изолированном тестовом окружении, где порт 9200 никогда не смотрит наружу. Если нода слушает 0.0.0.0 без аутентификации — это открытая база с логами и, возможно, персональными данными в интернете; такие инстансы находят сканеры за считаные часы. Обязательно проверьте network.host в opensearch.yml и правила файрвола отдельно от настроек самого security plugin.

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

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

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

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

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

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

Чем OpenSearch принципиально отличается от Elasticsearch?

Исторически это форк Elasticsearch 7.10.2, сделанный после смены лицензии на SSPL. API и большая часть возможностей совместимы, лицензия — Apache 2.0. Дальше проекты развиваются раздельно, и по мере накопления версий различия в фичах и деталях поведения будут расти — при миграции старых конфигов и Kibana-дашбордов это стоит проверять руками, а не считать 1:1.

Сколько RAM нужно под OpenSearch на своём сервере?

Для тестового или небольшого single-node инстанса под логи хватает 4-8 ГБ, из которых половина уйдёт под heap, половина — под файловый кэш ОС. Под серьёзный поток логов или полнотекстовый поиск с индексами в десятки гигабайт стоит закладывать 16 ГБ и выше — точная цифра зависит от объёма и частоты индексации, универсальной формулы тут нет.

Можно ли развернуть OpenSearch на одной ноде без кластера?

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

Нужно ли ставить Java отдельно?

Нет, начиная с современных релизов OpenSearch поставляется с собственным бандлованным JDK, и в норме отдельная установка Java не требуется. Если в системе стоит своя Java и сервис почему-то использует её вместо бандла — проверьте переменную окружения OPENSEARCH_JAVA_HOME.

Как обновить OpenSearch на проде без риска потерять данные?

Перед любым апгрейдом снимите снапшот индексов через Snapshot API в отдельный репозиторий (S3-совместимое хранилище или примонтированный диск), затем обновляйте по одной ноде с проверкой _cluster/health между шагами. На одиночной ноде без резервной копии откатиться после неудачного обновления будет негде.

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

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

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