По использованию памяти Elasticsearch, 50% памяти на узле Elasticsearch обычно используется для кучи JVM (Java Virtual Machine), а другая половина памяти используется для других нужд, например, для кэша.
Для предотвращения ошибок "Out of Memory" (OOM) в Elasticsearch реализованы автоматические выключатели. Если определенный запрос может привести к ошибкам в узле из-за проблем с памятью, Elasticsearch выбросит исключение "CircuitBreakerException" и отклонит запрос, вместо того чтобы рисковать отказом всего узла.
Исключение автоматического выключателя - это обычно исключение, которое выбрасывается для того, чтобы предупредить нас о чем-то еще, что необходимо исправить для уменьшения использования памяти. Как правило, автоматические выключатели имеют разумные значения по умолчанию. Простое увеличение предела разрыва цепи, скорее всего, увеличит риск того, что ваш узел разрушится из-за OutOfMemoryError.
Если вы получили исключение, связанное с разрывом цепи, необходимо проверить, какого типа этот выключатель, а затем просмотреть данные мониторинга и журналы Elasticsearch, чтобы определить причину ошибки. Помните, что событие или запрос, появившийся в журнале, может быть просто "соломинкой, переломившей спину верблюда". Могут существовать и другие причины высокого потребления памяти, а событие в журнале - лишь последняя, которая вывела Elasticsearch за пределы допустимого. Возможные причины обсуждаются в каждом разделе ниже.
Выяснение текущего состояния автоматического выключателя
Получение текущих настроек
1 | GET /_cluster/settings?include_defaults=true |
Узнать текущее использование памяти и состояние выключателей
1 | GET _nodes/stats/breaker |
В результате будет получена полезная информация следующего вида
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | "breakers" : { "request" : { "limit_size_in_bytes" : 20574004838, "limit_size" : "19.1gb", "estimated_size_in_bytes" : 0, "estimated_size" : "0b", "overhead" : 1.0, "tripped" : 0 }, "fielddata" : { "limit_size_in_bytes" : 13716003225, "limit_size" : "12.7gb", "estimated_size_in_bytes" : 0, "estimated_size" : "0b", "overhead" : 1.03, "tripped" : 0 }, "in_flight_requests" : { "limit_size_in_bytes" : 34290008064, "limit_size" : "31.9gb", "estimated_size_in_bytes" : 6254164, "estimated_size" : "5.9mb", "overhead" : 2.0, "tripped" : 0 }, "accounting" : { "limit_size_in_bytes" : 34290008064, "limit_size" : "31.9gb", "estimated_size_in_bytes" : 282771278, "estimated_size" : "269.6mb", "overhead" : 1.0, "tripped" : 0 }, "parent" : { "limit_size_in_bytes" : 32575507660, "limit_size" : "30.3gb", "estimated_size_in_bytes" : 13431618584, "estimated_size" : "12.5gb", "overhead" : 1.0, "tripped" : 0 } } |
Прерыватель полевых данных
indices.breaker.fielddata.limit (по умолчанию=40% кучи JVM)
indices.breaker.fielddata.overhead (по умолчанию=1.03)
Лимит задается как доля от кучи JVM, заданной в jvm.options, а параметр "overhead" - это фиксированный коэффициент, который Elasticsearch использует для умножения теоретических вычислений для оценки потребности в памяти автоматического выключателя.
Fielddata circuit breaker - это ограничение на общий объем памяти, используемый fielddata в ваших индексах. По умолчанию для текстовых полей Fielddata имеет значение false, но может использоваться, если вы определили его в одном из ваших связующих элементов:
1 | "fielddata": true |
В общем случае рекомендуется избегать этой настройки из-за большого объема памяти, необходимого для размещения в памяти отдельных текстовых значений. Если есть возможность, то следует изменить в связках значение false, а для агрегации и сортировки использовать связки типа keyword, а не text.
Однако если это невозможно и требуется агрегирование по отдельным терминам в тексте, а не по ключевым словам, то для ограничения количества помещаемых в память полевых данных можно также установить фильтр частоты полевых данных в отображении.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | PUT my-index-000001 { "mappings": { "properties": { "need_to_aggregate_individual_terms_on_this_field": { "type": "text", "fielddata": true, "fielddata_frequency_filter": { "min": 0.001, "max": 0.1, "min_segment_size": 500 } } } } } |
Прерыватель запросов
indices.breaker.request.limit (по умолчанию=60% кучи JVM)
indices.breaker.request.overhead (по умолчанию=1)
Лимит задается как доля от кучи JVM, заданной в jvm.options, а параметр "overhead" - это фиксированный коэффициент, который Elasticsearch использует для умножения теоретических вычислений для оценки требуемой памяти автоматического выключателя.
Автоматический выключатель запроса учитывает объем памяти, необходимый для работы со структурами запроса, в частности, с агрегатами. Наиболее частой причиной превышения этого показателя является использование агрегатов с большим значением размера. Попробуйте уменьшить значение "size" в своих агрегатах.
Автоматический выключатель по запросу
network.breaker.inflight_requests.limit (по умолчанию=100% кучи JVM)
network.breaker.inflight_requests.overhead (по умолчанию=2)
Лимит задается как доля от кучи JVM, заданной в jvm.options, а параметр "overhead" - это фиксированный коэффициент, который Elasticsearch использует для умножения теоретических расчетов для оценки потребности в памяти автоматического выключателя.
Автоматический выключатель входящих запросов учитывает размер активных транспортных и http-запросов к узлу, основываясь на размере байтов этих запросов. Как правило, этот автоматический выключатель срабатывает при слишком больших размерах пакетов массовых запросов. Попробуйте уменьшить размер массовых запросов, особенно если они содержат большие документы.
Автоматический выключатель компиляции скриптов
script.context.$CONTEXT.max_compilations_rate (по умолчанию=75/5m)
Автоматический выключатель компиляции скриптов несколько отличается от остальных. Вместо ограничения по памяти он ограничивает количество раз, которое может быть скомпилировано скриптом за определенный период времени. Если вы получаете это предупреждение, то вам следует использовать хранимые скрипты с параметрами, а не встроенные, так как первые компилируются только один раз, а вторые - при каждом выполнении.
Родительские автоматические выключатели
indices.breaker.total.use_real_memory default=true
indices.breaker.total.limit default=95% кучи JVM
Исключения родительских выключателей вызываются суммой всей памяти, используемой различными типами выключателей. Если оставить значение use_real_memory по умолчанию, то родительский выключатель будет учитывать использование реальной памяти и основываться на 95% от размера кучи JVM. В общем случае лучше основывать эту схему на реальном использовании памяти, так как это дает более точное представление о том, что происходит в экземпляре. С другой стороны, если установить значение "use_real_memory" в false, то ограничение будет основано на сумме оценок других автоматических выключателей, и тогда ограничение по умолчанию будет уменьшено до 70% от размера кучи JVM, чтобы учесть погрешность при использовании суммы оценок.
Автоматические выключатели учета
indices.breaker.accounting.limit default = 100% кучи JVM
indices.breaker.accounting.overhead default=1
Этот автоматический выключатель предназначен для защиты узла от перерасхода памяти из-за вещей, которые остаются в памяти после завершения запроса, например, сегменты lucene до их стирания на диск. Однако по умолчанию ограничение установлено на уровне 100% кучи JVM, поэтому родительский автоматический выключатель сработает раньше, чем это ограничение вступит в силу. Настройка накладных расходов представляет собой коэффициент, на который умножаются все оценки перед применением ограничения.
Настройка автоматических выключателей
В целом, как уже было сказано выше, обычно не рекомендуется изменять автоматические выключатели по сравнению с их значениями по умолчанию, поскольку гораздо хуже потерять узел из-за ошибки OutOfMemoryError, чем пропустить несколько запросов. Вместо этого следует попытаться понять, почему происходит превышение, и предотвратить это. Также следует помнить, что расчеты по умолчанию основаны на размере кучи JVM, который обычно принимается равным 50% от общего доступного размера. Если это не так, то, возможно, стоит пересмотреть настройки JVM в jvm.options, прежде чем перестраивать все остальное. Однако если вы все же считаете, что вам необходимо изменить параметры выключателей (или восстановить значения по умолчанию), вы можете настроить параметры выключателей так же, как и любые другие параметры кластера
1 2 3 4 | PUT _cluster/settings { "transient": {"indices.breaker.total.limit":"5GB" } } |
Или восстановить настройки по умолчанию
1 2 3 4 | PUT _cluster/settings { "transient": {"indices.breaker.total.limit":null } } |