Понимание и настройка размера кучи JVM Elasticsearch для производительности
Практическое руководство по определению размера кучи JVM Elasticsearch, чтению симптомов GC и избеганию настроек памяти, которые ухудшают производительность поиска.
Понимание и настройка размера кучи JVM Elasticsearch для производительности
Размер кучи JVM Elasticsearch — это одна из тех настроек, к которым люди часто обращаются слишком рано, а затем винят слишком поздно. Медленный кластер не всегда требует увеличения кучи. Иногда верно обратное: куча достаточно велика, но у операционной системы остается слишком мало памяти для кэша файловой системы, поэтому Lucene приходится чаще обращаться к диску. В других случаях куча действительно слишком мала, сборка мусора работает постоянно, и каждый поиск ощущается как шаг по мокрому цементу.
Практическая цель — не найти магическое число. Цель — предоставить Elasticsearch достаточно кучи для метаданных кластера, буферов индексации, агрегаций, запросов и кэшей, оставляя достаточно оперативной памяти вне кучи для файлов сегментов Lucene и операционной системы. Если вы запомните только одно, запомните, что производительность Elasticsearch зависит как от кучи, так и от памяти вне кучи.
Начните с разделения двух типов давления на память. Давление на кучу JVM проявляется как высокий heap.percent, длительные паузы сборки мусора, исключения родительского выключателя, давление fielddata или OutOfMemoryError. Давление вне кучи обычно выглядит как медленные поиски, даже если куча в порядке, высокое чтение с диска, активность подкачки или низкий процент попаданий в кэш после перезапуска. Увеличение кучи может помочь в первом случае. Это может ухудшить второй случай.
Для большинства самостоятельно управляемых кластеров старое эмпирическое правило все еще работает как отправная точка: установите кучу не более половины оперативной памяти машины и держите ее ниже порога сжатых обычных указателей объектов. Люди часто цитируют этот порог как «около 32 ГБ». На практике многие операторы остаются в диапазоне 26-31 ГБ, потому что точная граница зависит от JVM и компоновки времени выполнения. Elasticsearch регистрирует, включены ли сжатые обычные указатели объектов при запуске. Считайте журнал запуска источником истины для вашего узла.
В современных версиях Elasticsearch автоматическое определение размера кучи может уже установить разумное значение на основе ролей узла и доступной памяти. Это полезно, особенно для небольших кластеров и стандартных развертываний. Ручная настройка все еще имеет значение, когда у узла необычная рабочая нагрузка: тяжелые агрегации, большие маппинги, много шардов, конвейеры приема, задания преобразования, роли машинного обучения или сочетание горячего поиска и высокого объема индексации.
Вот простой пример. Предположим, у вас есть горячий узел данных на 64 ГБ, который обрабатывает как индексацию, так и поиск. Куча в 30 ГБ — обычная отправная точка. Это оставляет примерно половину оперативной памяти для кэша страниц ОС и собственной памяти. Если тот же узел является частью кластера журналирования с множеством маленьких шардов и агрегациями с высокой кардинальностью, вы все равно можете испытывать давление на кучу. Исправлением может быть лучший дизайн шардов или очистка маппинга, а не автоматическое увеличение кучи до 40 ГБ. Переход выше порога сжатых указателей может увеличить размер указателя объекта и снизить эффективность кучи.
Установите минимальный и максимальный размер кучи одинаковыми. Elasticsearch не должен тратить время на изменение размера кучи во время обслуживания трафика.
-Xms30g
-Xmx30g
Используйте файл в jvm.options.d/, а не редактируйте встроенный файл jvm.options напрямую, если ваша установка это поддерживает. Для установок из пакетов это обычно означает что-то вроде /etc/elasticsearch/jvm.options.d/heap.options. Для Docker передавайте настройки кучи через поддерживаемую переменную окружения или смонтированный конфиг. Сохраняйте настройку одинаковой для узлов с одинаковой ролью, но не предполагайте, что каждой роли нужна одинаковая куча. Выделенным узлам, подходящим для мастер-узлов, часто требуется гораздо меньше кучи, чем загруженным узлам данных, если только кластер не имеет очень больших метаданных из-за слишком большого количества индексов, полей или шардов.
Перед изменением кучи сделайте снимок текущего поведения. Посмотрите на статистику JVM:
GET _nodes/stats/jvm?filter_path=nodes.*.jvm.mem,nodes.*.jvm.gc
Затем проверьте выключатели и fielddata:
GET _nodes/stats/breaker,indices/fielddata?pretty
Также проверьте шарды и маппинги. Кластер с тысячами крошечных шардов может сжигать кучу на накладные расходы, даже если объем данных невелик.
GET _cat/shards?v&bytes=gb
GET _cluster/stats?filter_path=indices.count,indices.shards,indices.mappings
Симптомы важнее, чем итоговое число. Куча, находящаяся на уровне 70-85% во время всплесков, может быть нормальной, если сборка мусора быстро ее снижает. Куча, которая поднимается до высоких 90% и остается там, — это другое дело. Длительные паузы GC старого поколения хуже, чем высокий процент сам по себе. Если поиски истекают по тайм-ауту при каждом запуске GC, пользователям все равно, что средний график кучи выглядел приемлемо.
Распространенная ошибка в продакшене — использование кучи как заплатки для плохих маппингов. Сортировка или агрегация по анализируемым полям text с fielddata: true может потреблять много кучи. Лучшим исправлением обычно является подполе keyword, поле с более низкой кардинальностью или другой дизайн агрегации. Другая ошибка — разрешение динамическим маппингам создавать тысячи полей из произвольных ключей JSON. Тогда куча исчезает в маппингах, состоянии кластера и структурах запросов. Установите границы для динамических полей, прежде чем они станут операционной проблемой.
Агрегации заслуживают особого внимания. Агрегация terms по полю с высокой кардинальностью может создавать большие структуры в памяти. Если кто-то запускает дашборд, который группирует по user_id, session_id или полному URL за длительный период времени, давление на кучу может возрасти, даже если обычные поиски выглядят нормально. Используйте меньшие временные окна, фильтры, сужающие рабочее множество, агрегацию composite для пагинации или предварительно агрегированные свертки, где это уместно. Увеличение кучи может отсрочить сбой, но не сделает неограниченную агрегацию дешевой.
Индексация имеет свой собственный паттерн кучи. Массовые запросы создают временное давление. Очень большие полезные нагрузки массовых запросов могут заставить Elasticsearch удерживать слишком много работы одновременно. Если вы видите отказы индексации или скачки кучи во время приема, попробуйте меньшие пакеты массовых запросов и больше контроля параллелизма на стороне клиента. Полезный начальный диапазон часто составляет несколько мегабайт на массовый запрос, затем тестируйте вверх с вашими реальными документами. Правильное значение зависит от размера документа, конвейеров приема, реплик, интервала обновления и скорости хранения.
Не игнорируйте операционную систему. Отключите подкачку или настройте хост так, чтобы память Elasticsearch не выгружалась. Подкачка может превратить восстанавливаемую проблему с памятью в длительный сбой, потому что паузы JVM становятся огромными. Убедитесь, что процесс имеет разрешение на блокировку памяти, если вы используете bootstrap.memory_lock: true, и проверьте это при запуске, а не предполагайте, что настройка сработала.
После изменения кучи перезапускайте по одному узлу в производственном кластере и ждите восстановления шардов, прежде чем переходить к следующему узлу. Наблюдайте за задержкой поиска, паузами GC, чтением с диска и пропускной способностью индексации в течение как минимум одного нормального цикла трафика. Изменение, которое выглядит хорошо в тихий час, может провалиться во время утреннего пика дашбордов.
Если узел продолжает испытывать давление на кучу после разумной настройки, сделайте шаг назад и спросите, что удерживает куча. Слишком много шардов, слишком много полей, fielddata на text, чрезмерные агрегации, тяжелые скрипты и смешанные роли на одном узле — более распространенные причины, чем «Elasticsearch нужна вся оперативная память». Самая сильная работа по настройке кучи часто заканчивается меньшим маппингом, меньшим количеством шардов, лучшими лимитами запросов или выделенным уровнем приема.
Настройка кучи — это не разовая процедура. Это часть управления емкостью. Когда объем данных растет, дашборды меняются или новая команда начинает отправлять более широкие документы, профиль памяти также меняется. Держите настройку кучи скучной: измеряйте, меняйте одну вещь, безопасно перезапускайте и проверяйте с реальными данными рабочей нагрузки.