массовое индексирование elasticsearch со временем становится медленнее с постоянным количеством индексов и документов

Я столкнулся с тем, что производительность массового индексирования с использованием клиента .NET NEST и ElasticSearch со временем ухудшается при постоянном количестве индексов и количестве документов.

Мы запускаем ElasticSearch Version: 0.19.11, JVM: 23.5-b02на экземпляре Amazon m1.large с 64-разрядной версией Ubuntu Server 12.04.1 LTS и Sun Java 7. На этом экземпляре больше ничего не работает, кроме того, что поставляется вместе с установкой Ubuntu.

Крупный экземпляр Amazon M1: с http://aws.amazon.com/ec2/instance-types/

7.5 GiB memory
4 EC2 Compute Units (2 virtual cores with 2 EC2 Compute Units each)
850 GB instance storage
64-bit platform
I/O Performance: High
EBS-Optimized Available: 500 Mbps
API name: m1.large

Для ES_MAX_MEM установлено значение 4g, а для ES_MIN_MEM установлено значение 2g.

Каждую ночь мы индексируем/переиндексируем ~15000 документов, используя NEST в нашем приложении .NET. В любой момент времени существует только один индекс с ‹= 15000 документов.

когда сервер был впервые установлен, индексация и поиск были быстрыми в течение первых нескольких дней, затем индексация начала становиться все медленнее и медленнее. массовое индексирование индексирует 100 документов за раз, и через некоторое время для завершения массовой операции потребуется до 15 секунд. после этого мы начали видеть множество следующих исключений и остановку индексации.

System.Net.WebException: The request was aborted: The request was canceled.
   at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization) : 

Реализация встроенной индексации выглядит так

private ElasticClient GetElasticClient()
{
    var setting = new ConnectionSettings(ConfigurationManager.AppSettings["elasticSearchHost"], 9200);
    setting.SetDefaultIndex("products");
    var elastic = new ElasticClient(setting);
    return elastic;
}

private void DisableRefreshInterval()
{
    var elasticClient = GetElasticClient();
    var s = elasticClient.GetIndexSettings("products");
    var settings = s != null && s.Settings != null ? s.Settings : new IndexSettings();
    settings["refresh_interval"] = "-1";
    var result = elasticClient.UpdateSettings(settings);
    if (!result.OK)
        _logger.Warn("unable to set refresh_interval to -1, {0}", result.ConnectionStatus == null || result.ConnectionStatus.Error == null ? "" : result.ConnectionStatus.Error.ExceptionMessage);
}

private void EnableRefreshInterval()
{
    var elasticClient = GetElasticClient();
    var s = elasticClient.GetIndexSettings("products");
    var settings = s != null && s.Settings != null ? s.Settings : new IndexSettings();
    settings["refresh_interval"] = "1s";
    var result = elasticClient.UpdateSettings(settings);
    if (!result.OK)
        _logger.Warn("unable to set refresh_interval to 1s, {0}", result.ConnectionStatus == null || result.ConnectionStatus.Error == null ? "" : result.ConnectionStatus.Error.ExceptionMessage);
}

public void Index(IEnumerable<Product> products)
{
    var enumerable = products as Product[] ?? products.ToArray();
    var elasticClient = GetElasticClient();
    try
    {
        DisableRefreshInterval();

        _logger.Info("Indexing {0} products", enumerable.Count());
        var status = elasticClient.IndexMany(enumerable as IEnumerable<Product>, "products");

        if (status.Items != null)
            _logger.Info("Done, Indexing {0} products, duration: {1}", status.Items.Count(), status.Took);

        if (status.ConnectionStatus.Error != null)
        {
            _logger.Error(status.ConnectionStatus.Error.OriginalException);
        }
    }
    catch(Exception ex)
    {
        _logger.Error(ex);
    }
    finally
    {
        EnableRefreshInterval();
    }
}

Перезапуск демона elasticsearch, похоже, не имеет никакого значения, но удаление индекса и повторная индексация всего имеют значение. Но через несколько дней у нас будет та же проблема медленного индексирования.

Я просто удалил индекс и добавил оптимизацию после повторного включения интервала обновления после каждой операции массового индексирования в надежде, что это может предотвратить деградацию индекса.

...
...
finally
{
    EnableRefreshInterval();
    elasticClient.Optimize("products");
}

Я делаю что-то ужасно неправильно здесь?


person Christian Westman    schedule 07.12.2012    source источник
comment
15000 должно быть легко как для NEST, так и для Elasticsearch, каково фактическое количество документов и размер индекса через пару дней?   -  person Martijn Laarman    schedule 20.12.2012
comment
Как у вас обстоят дела с конфигурацией ES после этого вопроса? Я заметил здесь одну вещь, на которую определенно нужно обратить внимание; вы установили максимальную и минимальную память кучи ES на разные значения. Они должны быть одинаковыми; где-то между 50 и 60% общей памяти, доступной системе. В настоящее время я каждую минуту массово индексирую пакеты из 100 000 документов в приложении обратной засыпки, используя NEST в качестве клиента, поэтому 15 000 должно быть тривиальным. Вы также используете очень старую версию ES — с 19.11 (в настоящее время 0.20.4) в нее были внесены значительные улучшения.   -  person james lewis    schedule 05.02.2013


Ответы (2)


Извините - только что начал писать еще один довольно длинный комментарий и подумал, что просто вставлю все это в ответ на случай, если это принесет пользу кому-то еще...

ES_HEAP_SIZE

Первое, что я заметил здесь, это то, что вы сказали, что устанавливаете максимальное и минимальное значения кучи для elasticsearch на разные значения. Они должны быть одинаковыми. В сценарии конфигурации/init.d должен быть EX_HEAP_SIZE, который вы можете установить. Обязательно установите только это (а не минимальное и максимальное значения), так как оно установит минимальное и максимальное значения на одно и то же значение, которое вы хотите. Если вы этого не сделаете, JVM заблокирует процессы Java, когда вам понадобится больше памяти - см. статья о недавнем сбое на github (вот цитата):

Установите переменную среды ES_HEAP_SIZE, чтобы JVM использовала одно и то же значение для минимального и максимального объема памяти. Настройка JVM на разные минимальные и максимальные значения означает, что каждый раз, когда JVM требуется дополнительная память (вплоть до максимума), она будет блокировать процесс Java для ее выделения. В сочетании со старой версией Java это объясняет паузы, которые демонстрировали наши узлы при более высокой нагрузке и непрерывном выделении памяти, когда они были открыты для общего поиска. Команда elasticsearch рекомендует установить 50 % оперативной памяти системы.

Также ознакомьтесь с этим замечательным постом, чтобы узнать больше о конфигурации elasticsearch из окопов.

Заблокировать память, чтобы остановить подкачку

Из моего исследования я обнаружил, что вы также должны заблокировать объем памяти, доступный для процесса java, чтобы избежать подкачки памяти. Я не эксперт в этой области, но мне сказали, что это также убьет производительность. Вы можете найти bootstrap.mlockall в файле конфигурации elasticsearch.yml.

Обновления

Elasticsearch все еще довольно новый. Планируйте обновление довольно часто, так как исправления ошибок, внесенные между версией, в которой вы работали (0.19.11), и текущей версией (0.20.4), очень значительны. Подробнее см. на сайте ES. Вы работаете с Java 7, и это определенно правильный путь. Я начал с Java 6 и быстро понял, что этого недостаточно, особенно для массовой вставки.

Плагины

Наконец, всем, кто сталкивается с подобными проблемами, установите достойный плагин для обзора ваших узлов и JVM. Я рекомендую bigdesk - запустите bigdesk, а затем нажмите elasticsearch с несколькими массовыми вставками и следите за странными шаблонами памяти кучи, очень большой количество потоков и т. д., все это есть!

Надеюсь, кто-то найдет это полезным!

Привет, Джеймс

person james lewis    schedule 05.02.2013
comment
На выделенном сервере помимо настройки bootstrap.mlockall = true следует также вызвать ulimit -l unlimited в скрипте демона .sh, который запускает elasticsearch. (Таким образом снимается искусственное ограничение способности elasticsearch выделять виртуальную память, необходимое для включения оптимизации mlock.) Настройка ulimits может быть очень неудобной, поэтому я также добавил строку ulimit -a для вывода значений в журнал. Если вы все сделали правильно, запуск top покажет, что elasticsearch использует примерно тот же размер VIRT и RSS сразу при запуске; если RSS мал, настройка mlockall не действует. - person mrflip; 24.03.2013

Просто рискну предположить:

Вы заметили, что по мере снижения производительности индекса он занимает больше места на диске?

Возможно, вместо того, чтобы заменять старый индекс или старые документы при переиндексации, вместо этого вы добавляете кучу новых документов, фактически удваивая количество документов, возможно, с в значительной степени дублированными данными. Возможно, стоит взять старый, медленный индекс и загрузить его в какую-нибудь программу просмотра для отладки (Luke, для пример). Если вы видите намного больше документов, чем вы ожидали, то вы можете подумать о том, чтобы вместо этого создать новый индекс для замены старого.

Поскольку перезапуск демона не устраняет проблему, я полагаю, что оставлять открытые дескрипторы файлов, запущенные процессы, соединения и т. д. можно исключить, хотя я хотел бы проверить эту статистику и определить, вижу ли я какое-либо подозрительное поведение на сервере. сервер.

Кроме того, что касается Оптимизации, вы, конечно, можете увидеть некоторые улучшения производительности, но это очень дорогая операция. Я бы рекомендовал запускать оптимизацию только после завершения полной перестройки, а не после каждой операции инкрементного массового индексирования.

person femtoRgon    schedule 07.12.2012
comment
спасибо за указатели! Мы действительно не заметили увеличения использования диска, памяти и процессора. Память обычно составляет ~ 70%, а ЦП находится в диапазоне от простоя до 60-80%. Прошло четыре дня с тех пор, как я удалил индекс и добавил Optimize в массовое индексирование. До сих пор мы не видели деградации индексации, надеюсь, она сохранится, но я чувствую себя неловко из-за того, что не могу точно определить проблему. Я загляну в Люка и покопаюсь в логах, если ситуация повторится. - person Christian Westman; 10.12.2012
comment
Конечно, вполне вероятно, что оптимизация может решить проблему. Накопление большого количества неоптимизированных удалений и вставок (а обновления — это просто удаление + вставка) определенно может снизить производительность поиска. Еще одна вещь, на которую следует обратить внимание, в этом случае может быть ваша политика слияния, elasticsearch.org/guide/reference/index-modules/merge.html - person femtoRgon; 10.12.2012