Настройки Elasticsearch для обеспечения скорости индексирования важны в продуктивной среде и могут отличаться в зависимости от архитектуры, типов документов, используемого железа. По этому могут отличаться в каждой установке.
Использование Bulk запросов
Массовые запросы (Bulk) дают гораздо более высокую производительность, чем запросы индекса одного документа. Для того чтобы узнать оптимальный размер массового запроса, вам следует провести сравнительный тест на одном узле с одним шардом. Сначала попробуйте проиндексировать сразу 100 документов, затем 200, затем 400 и т.д., удваивая количество документов в массовом запросе при каждом запуске теста. Когда скорость индексирования начнет начнет достигать предела, вы поймете, что достигли оптимального размера массового запроса для ваших данных. В случае "ничьей" лучше ошибиться в сторону слишком малого, а не слишком большого количества документов. Следует помнить, что слишком большие массовые запросы могут создать нагрузку на память кластера при одновременной отправке многих из них, поэтому рекомендуется не превышать пару десятков мегабайт на запрос, даже если кажется, что большие запросы работают лучше.
Использование нескольких потоков для отправки данных в Elasticsearch
Один поток, отправляющий массовые запросы, вряд ли сможет максимально использовать возможности индексирования кластера Elasticsearch. Чтобы использовать все ресурсы кластера, следует отправлять данные из нескольких потоков или процессов. Помимо более эффективного использования ресурсов кластера, это поможет снизить стоимость каждого fsync.
Обязательно следите за кодами ответов TOO_MANY_REQUESTS (429) (EsRejectedExecutionException в Java-клиенте) - это способ, которым Elasticsearch сообщает вам, что он не может поддерживать текущую скорость индексирования. Когда это происходит, вам следует немного приостановить индексирование, прежде чем повторить попытку, в идеале с рандомизированным экспоненциальным отступлением.
Аналогично определению размера массовых запросов, только тестирование может определить оптимальное количество рабочих. Это можно проверить, постепенно увеличивая число рабочих до тех пор, пока на кластере не произойдет насыщение ввода-вывода или процессора.
Снять или увеличить интервал обновления
Операция, которая заключается в том, чтобы сделать изменения видимыми для поиска - называемая обновлением - является дорогостоящей, и частое ее выполнение при продолжающейся активности индексирования может снизить скорость индексирования.
По умолчанию Elasticsearch периодически обновляет индексы каждую секунду, но только те индексы, которые получили один или более поисковых запросов за последние 30 секунд.
Это оптимальная конфигурация, если у вас нет или очень мало поискового трафика (например, менее одного поискового запроса каждые 5 минут) и вы хотите оптимизировать скорость индексирования. Это поведение направлено на автоматическую оптимизацию массового индексирования в случае по умолчанию, когда поиск не производится. Для того чтобы отказаться от этого поведения, задайте интервал обновления явным образом.
С другой стороны, если в ваш индекс регулярно поступают поисковые запросы, это поведение по умолчанию означает, что Elasticsearch будет обновлять ваш индекс каждые 1 секунду. Если вы можете позволить себе увеличить время между тем, как документ попадает в индекс, и тем, как он становится видимым, увеличение интервала index.refresh_interval до большего значения, например, 30 секунд, может помочь улучшить скорость индексирования.
Отключение реплик для начальной загрузки
Если у вас есть большой объем данных, которые вы хотите сразу загрузить в Elasticsearch, может быть полезно установить index.number_of_replicas на 0, чтобы ускорить индексирование. Отсутствие реплик означает, что потеря одного узла может привести к потере данных, поэтому важно, чтобы данные хранились в другом месте, чтобы в случае возникновения проблем можно было повторить первоначальную загрузку. После завершения начальной загрузки вы можете установить index.number_of_replicas обратно в исходное значение.
Если в настройках индекса задан интервал обновления index.refresh_interval, может оказаться полезным снять его значение во время начальной загрузки и вернуть его к исходному значению после завершения начальной загрузки.
Отключить свопинг
Вы должны убедиться, что операционная система не отправляет процесс java в файл подкачки.
Выделите память под кэш файловой системы
Кэш файловой системы будет использоваться для буферизации операций ввода-вывода. Вы должны убедиться, что для кэша файловой системы выделено не менее половины памяти машины, на которой запущен Elasticsearch.
Использовать автоматически генерируемые идентификаторы
При индексировании документа с явным идентификатором Elasticsearch должен проверить, существует ли уже документ с таким же идентификатором в том же шарде, что является дорогостоящей операцией и становится еще более дорогостоящей по мере роста индекса. Используя автоматически генерируемые идентификаторы, Elasticsearch может пропустить эту проверку, что ускоряет индексирование.
Используйте более быстрое оборудование
Если индексирование связано с вводом-выводом, подумайте об увеличении размера кэша файловой системы (см. выше) или об использовании более быстрого хранилища. Elasticsearch обычно создает отдельные файлы с последовательной записью. Однако индексирование предполагает одновременную запись нескольких файлов, а также сочетание случайных и последовательных чтений, поэтому SSD-накопители обычно работают лучше, чем вращающиеся диски.
Разбейте индекс на несколько SSD-дисков, сконфигурировав массив RAID 0. Помните, что это увеличит риск сбоя, поскольку отказ одного SSD уничтожит индекс. Однако это, как правило, правильный компромисс: оптимизируйте отдельные осколки для максимальной производительности, а затем добавьте реплики на разных узлах, чтобы обеспечить избыточность при любых сбоях узлов. Для дополнительной страховки можно также использовать моментальный снимок и восстановление для резервного копирования индекса.
Хранилище с прямым подключением (локальное) обычно работает лучше, чем удаленное хранилище, поскольку его проще настроить и избежать накладных расходов на обмен данными. При тщательной настройке иногда можно добиться приемлемой производительности и при использовании удаленного хранилища. Чтобы определить влияние любых параметров настройки, проведите тестирование системы с реалистичной рабочей нагрузкой. Если вы не можете достичь ожидаемой производительности, обратитесь к поставщику системы хранения данных для выявления проблемы.
Размер буфера индексирования
Если ваш узел выполняет только тяжелое индексирование, убедитесь, что indices.memory.index_buffer_size достаточно велик, чтобы обеспечить не более 512 МБ буфера индексирования на каждый шард, выполняющий тяжелое индексирование (после этого производительность индексирования обычно не улучшается). Elasticsearch принимает эту настройку (процент от кучи java или абсолютный размер байта) и использует ее как общий буфер для всех активных шардов. Очень активные шарды, естественно, будут использовать этот буфер больше, чем шарды, выполняющие легкое индексирование.
По умолчанию используется значение 10%, что часто бывает достаточно: например, если вы предоставите JVM 10 ГБ памяти, она выделит 1 ГБ под индексный буфер, что достаточно для размещения двух шардов с интенсивным индексированием.
Используйте кросс-кластерную репликацию, чтобы поиск не крал ресурсы у индексирования
В пределах одного кластера индексирование и поиск могут конкурировать за ресурсы.
Если создать два кластера, строить кросс-кластерную репликацию для репликации данных из одного кластера в другой и маршрутизации всех поисковых запросов в кластер с индексами-последователями, поисковая активность больше не будет красть ресурсы при индексации в кластере, в котором размещены индексы-лидеры.