Высокая концентрация нагрузок
Возможна горячая точка в Elasticsearch, когда использование ресурсов распределено неравномерно между узлами. Временные пики обычно не считаются проблематичными, но постоянное существенно отличное использование может привести к узким местам кластера и должно быть проанализировано.
См. это видео для пошагового решения проблемы горячих точек.
Обнаружение горячих точек
Горячие точки чаще всего проявляются как существенно повышенное использование ресурсов (disk.percent, heap.percent или cpu) у подмножества узлов, как сообщается через cat nodes. Отдельные пики не обязательно являются проблематичными, но если использование неоднократно пикирует или постоянно остается высоким со временем (например, дольше 30 секунд), ресурс может испытывать проблематичные горячие точки.
Например, давайте рассмотрим два отдельных вероятных случая, используя cat nodes:
resp = client.cat.nodes(
v=True,
s="master,name",
h="name,master,node.role,heap.percent,disk.used_percent,cpu",
)
print(resp) response = client.cat.nodes( v: true, s: 'master,name', h: 'name,master,node.role,heap.percent,disk.used_percent,cpu' ) puts response
const response = await client.cat.nodes({
v: "true",
s: "master,name",
h: "name,master,node.role,heap.percent,disk.used_percent,cpu",
});
console.log(response); GET _cat/nodes?v&s=master,name&h=name,master,node.role,heap.percent,disk.used_percent,cpu
Предположим, этот же вывод был получен дважды в течение пяти минут:
name master node.role heap.percent disk.used_percent cpu node_1 * hirstm 24 20 95 node_2 - hirstm 23 18 18 node_3 - hirstmv 25 90 10
Здесь мы видим два существенно отличных использования: где мастер-узел находится на уровне cpu: 95, а узел с горячей точкой находится на уровне disk.used_percent: 90%. Это указывает на то, что горячие точки возникали на этих двух узлах, и не обязательно от одного и того же корневого причины.
Причины
Исторически кластеры испытывают горячие точки в основном в результате аппаратного обеспечения, распределения фрагментов и/или нагрузки задач. Мы рассмотрим их последовательно в порядке потенциального влияния на масштаб.
Аппаратное обеспечение
Вот некоторые распространенные неправильные конфигурации оборудования, которые могут способствовать возникновению горячих точек:
- Ресурсы распределяются неравномерно. Например, если одному узлу с горячей точкой предоставлена половина ЦП по сравнению со своими коллегами. Elasticsearch ожидает, что все узлы на уровне данных будут иметь одинаковые аппаратные профили или спецификации.
- Ресурсы потребляются другой службой на хосте, включая другие узлы Elasticsearch. Обратитесь к нашему рекомендованию по выделенным хостам.
- Ресурсы испытывают разную пропускную способность сети или диска. Например, если ввод/вывод одного узла ниже, чем у его коллег. Обратитесь к Использованию более быстрого оборудования для получения дополнительной информации.
- JVM, настроенный с кучей больше 31 ГБ. Обратитесь к установке размера кучи JVM для получения дополнительной информации.
- Проблемные ресурсы уникально сообщают о свопировании памяти.
Распределение фрагментов
Индексы Elasticsearch делятся на один или несколько фрагментов, которые иногда могут быть плохо распределены. Elasticsearch учитывает это, балансируя количество фрагментов между узлами данных. Как представлено в версии 8.6, Elasticsearch по умолчанию также включает желаемый баланс для учета нагрузки загрузки. Узел может все еще испытывать горячие точки, либо из-за индексов с интенсивными записями, либо из-за общего количества фрагментов, которые он содержит.
Уровень узла
Вы можете проверить баланс фрагментов с помощью cat allocation, хотя с версии 8.6 желаемый баланс больше не гарантирует полную балансировку фрагментов. Обратите внимание, что оба метода могут временно показывать проблематичный дисбаланс во время проблем стабильности кластера.
Например, давайте покажем два отдельных вероятных случая, используя cat allocation:
resp = client.cat.allocation(
v=True,
s="node",
h="node,shards,disk.percent,disk.indices,disk.used",
)
print(resp) response = client.cat.allocation( v: true, s: 'node', h: 'node,shards,disk.percent,disk.indices,disk.used' ) puts response
const response = await client.cat.allocation({
v: "true",
s: "node",
h: "node,shards,disk.percent,disk.indices,disk.used",
});
console.log(response); GET _cat/allocation?v&s=node&h=node,shards,disk.percent,disk.indices,disk.used
Что может вернуть:
node shards disk.percent disk.indices disk.used node_1 446 19 154.8gb 173.1gb node_2 31 52 44.6gb 372.7gb node_3 445 43 271.5gb 289.4gb
Здесь мы видим две существенно различные ситуации. node_2 недавно перезагрузился, поэтому у него гораздо меньше фрагментов, чем у всех остальных узлов. Это также связано с тем, что disk.indices намного меньше, чем disk.used, в то время как фрагменты восстанавливаются, как видно из cat recovery. Хотя количество фрагментов в node_2 низкое, он может стать узлом с интенсивными записями из-за текущих циклов ILM. Это распространенная причина интенсивных записей, о которой рассказывается в следующем разделе.
Вторая ситуация заключается в том, что у node_3 больше disk.percent, чем у node_1, даже если они содержат примерно одинаковое количество фрагментов. Это происходит, когда фрагменты не имеют одинакового размера (см. Настраивайте фрагменты от 200 млн документов или с размером от 10 ГБ до 50 ГБ) или когда имеется много пустых индексов.
Перебалансировка кластера на основе желаемого баланса в значительной степени решает проблему предотвращения горячих точек на узлах. Она может быть ограничена либо достижением узлами пороговых значений (см. исправление ошибок пороговых значений диска), либо низким количеством фрагментов индекса с интенсивными записями по сравнению с узлами, на которые записываются.
Вы можете подтвердить узлы с горячими точками с помощью API статистики узлов, возможно, выполнив опрос дважды через некоторое время, чтобы проверить только разницу в статистике между ними, а не выполнить опрос один раз, чтобы получить статистику за весь период работы узла работы узла. Например, чтобы проверить статистику индексирования всех узлов:
resp = client.nodes.stats(
human=True,
filter_path="nodes.*.name,nodes.*.indices.indexing",
)
print(resp) response = client.nodes.stats( human: true, filter_path: 'nodes.*.name,nodes.*.indices.indexing' ) puts response
const response = await client.nodes.stats({
human: "true",
filter_path: "nodes.*.name,nodes.*.indices.indexing",
});
console.log(response); GET _nodes/stats?human&filter_path=nodes.*.name,nodes.*.indices.indexing
Уровень индекса
Узлы с горячими точками часто обнаруживаются через cat thread pool за счет write и search очереди резервирования. Например:
resp = client.cat.thread_pool(
thread_pool_patterns="write,search",
v=True,
s="n,nn",
h="n,nn,q,a,r,c",
)
print(resp) response = client.cat.thread_pool( thread_pool_patterns: 'write,search', v: true, s: 'n,nn', h: 'n,nn,q,a,r,c' ) puts response
const response = await client.cat.threadPool({
thread_pool_patterns: "write,search",
v: "true",
s: "n,nn",
h: "n,nn,q,a,r,c",
});
console.log(response); GET _cat/thread_pool/write,search?v=true&s=n,nn&h=n,nn,q,a,r,c
Что может вернуть:
n nn q a r c search node_1 3 1 0 1287 search node_2 0 2 0 1159 search node_3 0 1 0 1302 write node_1 100 3 0 4259 write node_2 0 4 0 980 write node_3 1 5 0 8714
Здесь вы можете увидеть две существенно разные ситуации. Во-первых, у node_1 сильно заблокирована очередь записи по сравнению с другими узлами. Во-вторых, у node_3 наблюдаются исторически завершенные записи, которые вдвое превышают количество на других узлах. Вероятнее всего, это вызвано либо неравномерным распределением индексов с высокой скоростью записи, либо назначением нескольких индексов с высокой скоростью записи одному узлу. Поскольку операции записи первичных и реплицируемых фрагментов в значительной степени эквивалентны по объему работы кластера, мы обычно рекомендуем установить index.routing.allocation.total_shards_per_node, чтобы принудительно распределить индексы после выравнивания количества фрагментов индекса с общим количеством узлов.
Мы обычно рекомендуем, чтобы индексы с высокой интенсивностью записи имели достаточное количество первичных number_of_shards и реплицированных number_of_replicas для равномерного распределения между узлами индексирования. В качестве альтернативы, вы можете перенаправить фрагменты на более спокойные узлы, чтобы уменьшить нагрузку на узлы с горячими точками.
Если не очевидно, какие индексы являются проблематичными, вы можете провести более глубокий анализ с помощью API статистики индексов, выполнив:
resp = client.indices.stats(
level="shards",
human=True,
expand_wildcards="all",
filter_path="indices.*.total.indexing.index_total",
)
print(resp) response = client.indices.stats( level: 'shards', human: true, expand_wildcards: 'all', filter_path: 'indices.*.total.indexing.index_total' ) puts response
const response = await client.indices.stats({
level: "shards",
human: "true",
expand_wildcards: "all",
filter_path: "indices.*.total.indexing.index_total",
});
console.log(response); GET _stats?level=shards&human&expand_wildcards=all&filter_path=indices.*.total.indexing.index_total
Для более продвинутого анализа можно выполнять запросы статистики фрагментов, что позволяет сравнивать совокупные данные по индексам и узлам. Этот анализ не учитывает перезагрузку узлов и/или перенаправление фрагментов, но служит обзором:
resp = client.indices.stats(
metric="indexing,search",
level="shards",
human=True,
expand_wildcards="all",
)
print(resp) response = client.indices.stats( metric: 'indexing,search', level: 'shards', human: true, expand_wildcards: 'all' ) puts response
const response = await client.indices.stats({
metric: "indexing,search",
level: "shards",
human: "true",
expand_wildcards: "all",
});
console.log(response); GET _stats/indexing,search?level=shards&human&expand_wildcards=all
Например, вы можете использовать инструмент JQ стороннего разработчика для обработки выходных данных, сохраненных как indices_stats.json:
cat indices_stats.json | jq -rc ['.indices|to_entries[]|.key as $i|.value.shards|to_entries[]|.key as $s|.value[]|{node:.routing.node[:4], index:$i, shard:$s, primary:.routing.primary, size:.store.size, total_indexing:.indexing.index_total, time_indexing:.indexing.index_time_in_millis, total_query:.search.query_total, time_query:.search.query_time_in_millis } | .+{ avg_indexing: (if .total_indexing>0 then (.time_indexing/.total_indexing|round) else 0 end), avg_search: (if .total_search>0 then (.time_search/.total_search|round) else 0 end) }'] > shard_stats.json
# show top written-to shard simplified stats which contain their index and node references
cat shard_stats.json | jq -rc 'sort_by(-.avg_indexing)[]' | head Нагрузки задач
Проблемы с распределением фрагментов, скорее всего, проявятся как нагрузка на задачи, как показано выше в примере cat thread pool. Также возможно, что задачи будут концентрироваться на узле из-за индивидуальной качественной дороговизны или общей количественной нагрузки.
Например, если cat thread pool сообщил о большой очереди в warmer пуле потоков, вам нужно будет найти узлы, которые были затронуты, с помощью горячих потоков. Предположим, он сообщил о warmer потоках в 100% cpu, связанных с GlobalOrdinalsBuilder. Это позволит вам проверить глобальные порядковые номера данных поля .
В качестве альтернативы, предположим, что cat nodes показывает перегруженный мастер-узел, а cat thread pool показывает общую очередь на всех узлах. Это говорит о перегрузке мастер-узла. Для решения этой проблемы сначала необходимо убедиться, что настроен высокая доступность оборудования, а затем попытаться найти временные причины. В этом примере API горячих потоков узлов сообщает о нескольких потоках в other, что указывает на то, что они ожидают или заблокированы из-за сбора мусора или операций ввода-вывода.
В любой из этих ситуаций, хороший способ подтвердить проблемные задачи — просмотреть самые длительные не-непрерывные (определенные [c]) задачи с помощью управления задачами cat. Это можно дополнить, проверив самые длительные задачи синхронизации кластера с помощью cat pending tasks. Используя третий пример,
resp = client.cat.tasks(
v=True,
s="time:desc",
h="type,action,running_time,node,cancellable",
)
print(resp) response = client.cat.tasks( v: true, s: 'time:desc', h: 'type,action,running_time,node,cancellable' ) puts response
const response = await client.cat.tasks({
v: "true",
s: "time:desc",
h: "type,action,running_time,node,cancellable",
});
console.log(response); GET _cat/tasks?v&s=time:desc&h=type,action,running_time,node,cancellable
Это может вернуть:
type action running_time node cancellable direct indices:data/read/eql 10m node_1 true ...
Это выявляет проблемный запрос EQL. Мы можем получить дополнительную информацию об этом с помощью API управления задачами,
resp = client.tasks.list(
human=True,
detailed=True,
)
print(resp) response = client.tasks.list( human: true, detailed: true ) puts response
const response = await client.tasks.list({
human: "true",
detailed: "true",
});
console.log(response); GET _tasks?human&detailed
Его ответ содержит description, который сообщает об этом запросе:
indices[winlogbeat-*,logs-window*], sequence by winlog.computer_name with maxspan=1m\n\n[authentication where host.os.type == "windows" and event.action:"logged-in" and\n event.outcome == "success" and process.name == "svchost.exe" ] by winlog.event_data.TargetLogonId
Это позволяет узнать, какие индексы следует проверить (winlogbeat-*,logs-window*), а также тело запроса поиска EQL. Скорее всего, это связано с SIEM.
© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/hotspotting.html