Автоматические выключатели — это механизм защиты для эластичного поиска, позволяющий предотвратить чрезмерное потребление ресурсов. Основная цель — предотвратить чрезмерное потребление ресурсов во время бизнес-эластичного поиска и вызвать OutOfMemoryError JVM. Не допускайте слишком высокой загрузки кучи памяти JVM службы elasticsearch, которая может привести к недоступности службы. Благодаря ограничению порогового значения параметра автоматического выключателя кластер elasticsearch перестанет принимать новые запросы и вернет сообщение об ошибке ответа, когда оно превысит заданный порог при ответе на клиентские запросы. Защитите стабильность кластера. Для этой цели Elasticsearch предоставляет различные автоматические выключатели.
Родительский предохранитель: В качестве предохранителя самого высокого уровня в автоматическом выключателе кластера эластичного поиска. Используется для мониторинга и управления использованием кучи памяти JVM всего кластера. При срабатывании родительского автоматического выключателя кластер перестает принимать запросы новых клиентов и возвращает исключение автоматического выключателя. Помогает предотвратить истощение ресурсов кластера, накопление запросов и снижение производительности. Улучшение стабильности кластера.
Поддерживаемые параметры:
#Максимальный предел памяти кучи, разрешенный родительским предохранителем. Значение по умолчанию — 70 % пространства кучи JVM. Его можно динамически регулировать в соответствии с фактической ситуацией в кластере.
indices.breaker.total.limit: "70%"
#Если родительскому предохранителю необходимо зарезервировать квоту для дочернего предохранителя, значение по умолчанию — true.
indices.breaker.total.use_real_memory: true
Предохранитель данных поля: предохранитель, используемый для оценки объема памяти кучи JVM, необходимой для загрузки данных поля в кэш памяти поля. Это разновидность дополнительного предохранителя. В основном отслеживает ресурсы кучи памяти, потребляемые кэшем полевых данных. При превышении заданного порога возвращается ошибка автоматического выключателя и операция кэша прекращается.
Кэширование данных полей — это механизм, используемый elasticsearch для ускорения таких операций, как агрегированная сортировка. Загрузка данных поля в память для быстрого доступа.
Поддерживаемые параметры:
#Верхний предел динамической памяти, которую может использовать автоматический выключатель полевых данных. Значение по умолчанию — 40 % от пространства кучи JVM. Его можно динамически регулировать в соответствии с фактической ситуацией в кластере.
indices.breaker.fielddata.limit:"40%"
#Определите коэффициент использования памяти для кэша полевых данных. Указывает долю дополнительной памяти вне кучи, выделенной для кэша данных поля. Просто используйте значение по умолчанию в популярных бизнес-сценариях.
#Избегайте накладных расходов на память мебели из-за несбалансированных пропорций. Влияет на стабильность и эффективность кэширования полевых данных.
indices.breaker.fielddata.overhead: 1.03
Прерыватель запросов: предохранитель, используемый для оценки объема памяти, который должен использовать каждый клиентский запрос при запросе эластичного поиска. Это тип дополнительного предохранителя. Основная функция — предотвратить потребление чрезмерных ресурсов памяти одним запросом. Обычно используется для мониторинга выделения памяти для таких запросов, как агрегирование мощности, и количества сегментов, используемых в запросах агрегации. При срабатывании заданных параметров автоматического выключателя запрос завершится и будет возвращена информация об исключении автоматического выключателя.
Поддерживаемые параметры:
#Запросите верхний предел динамической памяти, которую может использовать автоматический выключатель. Значение по умолчанию — 60 % пространства кучи JVM. Его можно динамически регулировать в соответствии с фактической ситуацией в кластере.
indices.breaker.request.limit: "60%"
#Определяет коэффициент использования памяти для запроса автоматического выключателя. Указывает долю дополнительной памяти вне кучи, выделенной сверх фактической памяти, выделенной для запроса автоматического выключателя. Значение по умолчанию — 1.
indices.breaker.request.overhead : 1
Автоматический выключатель запроса на обработку: автоматический выключатель, используемый для управления использованием памяти запросами, передаваемыми в данный момент на уровне HTTP. Это разновидность дополнительного предохранителя. Не допускайте превышения памяти, занимаемой передачей по сети, определенного предела квоты памяти узла.
Запросы на обработку — это запросы, которые передаются и обрабатываются на сетевом уровне. Эти запросы могут включать в себя операции поиска, индексирования, удаления и т. д. При передаче и обработке запросов будут заняты определенные ресурсы памяти.
Поддерживаемые параметры:
#Используется для управления объемом динамической памяти, которая может использоваться запросами, передаваемыми в данный момент на уровне HTTP. Значение по умолчанию — 100 % пространства кучи JVM. Ограничено пределом родительского предохранителя.
network.breaker.inflight_requests.limit: "100%"
#Определяет коэффициент накладных расходов памяти для обрабатываемого запроса, который представляет собой долю дополнительной выделенной памяти вне кучи в дополнение к фактической памяти, выделенной для обрабатываемого запроса.
Память #Off-heap используется для обработки метаданных запроса и других служебных данных. Значение по умолчанию — 2.
network.breaker.inflight_requests.overhead: 2
Автоматический выключатель счетчика запросов: автоматический выключатель, используемый для записи и контроля использования памяти, которая не освобождается после завершения запроса.
Поддерживаемые параметры:
#Используется для управления объемом динамической памяти, которую может использовать автоматический выключатель счетчика запросов. Значение по умолчанию — 100 % пространства кучи JVM. Ограничено пределом родительского предохранителя.
indices.breaker.accounting.limit: "100%"
#Определите коэффициент использования памяти для прерывателя счетчика запросов. Указывает долю дополнительной памяти вне кучи, выделенной сверх фактической памяти, выделенной для запроса автоматического выключателя. Значение по умолчанию — 1.
indices.breaker.accounting.overhead: 1
Автоматический выключатель компиляции скриптов: используется для управления объемом памяти, используемой во время компиляции скриптов.
Скрипт широко используется в различных операциях агрегирования запросов и обновления в elasticsearch. Компиляция скриптов — это процесс преобразования скриптов в исполняемый код. В процессе преобразования будут потребляться определенные ресурсы ЦП и памяти.
Поддерживаемые параметры:
#Используется для управления количеством скомпилированных скриптов, разрешенных для клиентских запросов в течение определенного периода времени. Вы можете контролировать скорость компиляции скриптов. Значение по умолчанию — 75/5 м;
# $CONTEXT является заполнителем для определенного имени контекста, например «поиск» или «обновление». В реальном использовании необходимо $CONTEXT Замените соответствующим именем контекста.
script.context.$CONTEXT.max_compilations_rate: "75/5m"
Предохранитель регулярного выражения: предохранитель, используемый для управления типом использования регулярных выражений в кластере.
Регулярные выражения обычно используются в elasticsearch для выполнения таких операций, как сопоставление с образцом или поиск. Регулярные выражения с низкой производительностью могут привести к чрезмерному потреблению ресурсов кластера. Влияет на стабильность кластера.
Поддерживаемые параметры:
#Используется для управления включением обычных сценариев в кластере. Значение по умолчанию ограничено;
script.painless.regex.enabled: "limited"
-true Включите регулярные выражения без ограничения сложности. Автоматический выключатель регулярного выражения отключен по умолчанию.
-false Регулярные выражения отключены, использование любого регулярного выражения приведет к ошибке.
-limited Используя регулярные выражения, задайте сложность регулярных выражений кластера с помощью параметра script.painless.regex.limit-factor.
#Используется для ограничения длины регулярных выражений в скриптах. Elasticsearch рассчитает этот предел на основе длины обычного сценария данных.
#Например: длина символов "foobarbaz" равна 9, если множитель "script.painless.regex.limit-factor" равен 6, то максимальная длина регулярного выражения на основе "foobarbaz" равна 54 (6*9 ), если регулярное выражение. Если выражение превышает этот предел длины, сработает обычный предохранитель и будет возвращено исключение плавкого предохранителя.
script.painless.regex.limit-factor
static class MemoryUsage {
final long baseUsage;
final long totalUsage;
final long transientChildUsage;
final long permanentChildUsage;
MemoryUsage(final long baseUsage, final long totalUsage, final long transientChildUsage, final long permanentChildUsage) {
this.baseUsage = baseUsage;
this.totalUsage = totalUsage;
this.transientChildUsage = transientChildUsage;
this.permanentChildUsage = permanentChildUsage;
}
}
В этом коде класс MemoryUsage используется для представления использования памяти. Он содержит несколько полей, представляющих базовое использование (baseUsage), общее использование (totalUsage), временное дочернее использование (transientChildUsage) и постоянное дочернее использование (permanentChildUsage). Этот статический класс будет вызываться, когда прерыватель подсчитывает использование памяти, чтобы облегчить управление и мониторинг памяти.
HierarchyCircuitBreakerService(
Settings settings,
List<BreakerSettings> customBreakers,
ClusterSettings clusterSettings,
Function<Boolean, OverLimitStrategy> overLimitStrategyFactory
) {
super();
HashMap<String, CircuitBreaker> childCircuitBreakers = new HashMap<>();
childCircuitBreakers.put(
CircuitBreaker.FIELDDATA,
validateAndCreateBreaker(
new BreakerSettings(
CircuitBreaker.FIELDDATA,
FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING.get(settings).getBytes(),
FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING.get(settings),
FIELDDATA_CIRCUIT_BREAKER_TYPE_SETTING.get(settings),
CircuitBreaker.Durability.PERMANENT
)
)
);
childCircuitBreakers.put(
CircuitBreaker.IN_FLIGHT_REQUESTS,
validateAndCreateBreaker(
new BreakerSettings(
CircuitBreaker.IN_FLIGHT_REQUESTS,
IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_LIMIT_SETTING.get(settings).getBytes(),
IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_OVERHEAD_SETTING.get(settings),
IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_TYPE_SETTING.get(settings),
CircuitBreaker.Durability.TRANSIENT
)
)
);
childCircuitBreakers.put(
CircuitBreaker.REQUEST,
validateAndCreateBreaker(
new BreakerSettings(
CircuitBreaker.REQUEST,
REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING.get(settings).getBytes(),
REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING.get(settings),
REQUEST_CIRCUIT_BREAKER_TYPE_SETTING.get(settings),
CircuitBreaker.Durability.TRANSIENT
)
)
);
for (BreakerSettings breakerSettings : customBreakers) {
if (childCircuitBreakers.containsKey(breakerSettings.getName())) {
throw new IllegalArgumentException(
"More than one circuit breaker with the name ["
+ breakerSettings.getName()
+ "] exists. Circuit breaker names must be unique"
);
}
childCircuitBreakers.put(breakerSettings.getName(), validateAndCreateBreaker(breakerSettings));
}
this.breakers = Map.copyOf(childCircuitBreakers);
this.parentSettings = new BreakerSettings(
CircuitBreaker.PARENT,
TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING.get(settings).getBytes(),
1.0,
CircuitBreaker.Type.PARENT,
null
);
logger.trace(() -> format("parent circuit breaker with settings %s", this.parentSettings));
this.trackRealMemoryUsage = USE_REAL_MEMORY_USAGE_SETTING.get(settings);
clusterSettings.addSettingsUpdateConsumer(
TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING,
this::setTotalCircuitBreakerLimit,
HierarchyCircuitBreakerService::validateTotalCircuitBreakerLimit
);
clusterSettings.addSettingsUpdateConsumer(
FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING,
FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING,
(limit, overhead) -> updateCircuitBreakerSettings(CircuitBreaker.FIELDDATA, limit, overhead)
);
clusterSettings.addSettingsUpdateConsumer(
IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_LIMIT_SETTING,
IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_OVERHEAD_SETTING,
(limit, overhead) -> updateCircuitBreakerSettings(CircuitBreaker.IN_FLIGHT_REQUESTS, limit, overhead)
);
clusterSettings.addSettingsUpdateConsumer(
REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING,
REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING,
(limit, overhead) -> updateCircuitBreakerSettings(CircuitBreaker.REQUEST, limit, overhead)
);
clusterSettings.addAffixUpdateConsumer(
CIRCUIT_BREAKER_LIMIT_SETTING,
CIRCUIT_BREAKER_OVERHEAD_SETTING,
(name, updatedValues) -> updateCircuitBreakerSettings(name, updatedValues.v1(), updatedValues.v2()),
(s, t) -> {}
);
clusterSettings.addSettingsUpdateConsumer(USE_REAL_MEMORY_USAGE_SETTING, this::updateUseRealMemorySetting);
this.overLimitStrategyFactory = overLimitStrategyFactory;
this.overLimitStrategy = overLimitStrategyFactory.apply(this.trackRealMemoryUsage);
}
Класс HierarchyCircuitBreakerService наследует класс CircuitBreakerService и используется для управления и контроля предохранителей. В этом классе родительский предохранитель и каждый дочерний предохранитель определяются в конструкторе. Используется для инициализации объекта автоматического выключателя.
После того, как кластер активирует автоматический выключатель, мы обычно видим следующую информацию журнала в журнале кластера elasticsearch или информацию об исключении, возвращаемую клиентским API:
error:elastic: Error 503 (Service Unavailable):
[parent] Data too large, data for [<http_request>] would be [34212596438/31.8gb],
which is larger than the limit of [30804738048/28.6gb],
real usage: [34211774560/31.8gb],
new bytes reserved: [821878/802.6kb] [type=circuit_breaking_exception]
Идеи анализа:
Мы передаем следующееGET _cluster/settings
Получить параметры автоматического выключателя кластера,Сначала проверим параметры. Проанализируйте, правильно ли настроены параметры.
В текущем сценарии мы анализируем информацию мониторинга через контекст журнала автоматического выключателя. Было обнаружено, что запрос пользователя агрегировал большое количество полей типа данных поля, что приводило к частому срабатыванию прерывателя данных поля, и в конечном итоге сработал родительский прерыватель. В зависимости от использования памяти кучи кластера пороговое значение слияния полевых данных было окончательно скорректировано. Обычный ответ на запрос бизнес-запроса восстановлен.
Идеи анализа: Сначала проверьте индексы с большим объемом записи посредством мониторинга. После нахождения соответствующего индекса,Проанализируйте, являются ли параметры индекса разумными. Стандартизирован ли дизайн шардинга. Сначала вы можете распределить давление записи, временно переместив сегменты. Когда давление на бизнес не может быть уменьшено,,Путем расширения узлов кластера,И ускорить миграцию осколков,обеспечить скорейшее восстановление бизнеса.