Диагностика проблем Smart Monitor Data Storage
В статье описана диагностика Smart Monitor Data Storage (далее - Data Storage). Значения порогов и лимитов по умолчанию взяты из профильных статей, ссылки на которые приведены в тексте и разделе «Полезные ссылки». Примеры ответов при исправной работе получены на тестовом стенде.
Условные обозначения
OS_LOGS- директория журналов Data Storage; не вложена в домашнюю директорию Data Storage, обычно/app/logs/opensearch/
Перед выполнением команд замените переменную фактическим путем в вашей инсталляции. Значение по умолчанию задается при установке (см. Установка Smart Monitor Data Storage).
Все запросы ниже выполняйте в консоли разработчика (Навигационное меню - Параметры системы - Консоль разработчика) или отправляйте эквивалентные запросы к Data Storage через curl.
Состояние кластера
Проверьте общее состояние кластера запросом:
GET _cluster/health
Основные поля ответа:
status-green(все шарды размещены),yellow(не размещены реплики) илиred(не размещены первичные шарды, часть данных недоступна)unassigned_shards- количество неразмещенных шардовnumber_of_nodesиnumber_of_data_nodes- фактическое количество узлов кластера; сравните с ожидаемым
Пример ответа при исправной работе:
{
"cluster_name": "smartmonitor",
"status": "green",
"number_of_nodes": 5,
"number_of_data_nodes": 2,
"active_primary_shards": 182,
"active_shards": 364,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"active_shards_percent_as_number": 100.0
}
Пример при сбое: часть первичных шардов не размещена, данные частично недоступны:
{
"cluster_name": "smartmonitor",
"status": "red",
"number_of_nodes": 4,
"number_of_data_nodes": 2,
"active_primary_shards": 178,
"active_shards": 350,
"relocating_shards": 0,
"initializing_shards": 2,
"unassigned_shards": 6,
"delayed_unassigned_shards": 6,
"number_of_pending_tasks": 0,
"active_shards_percent_as_number": 97.2
}
Если значение status отличается от green, перейдите к разделам Распределение шардов и дисковое пространство и Проблемные индексы.
Распределение шардов и дисковое пространство
Проверьте распределение шардов по узлам и использование дискового пространства:
GET _cat/allocation?v
Пример при исправной работе: дисковое пространство на узлах используется примерно равномерно:
shards disk.indices disk.used disk.avail disk.total disk.percent host node
182 45.2gb 52.1gb 147.9gb 200gb 26 192.0.2.10 smos-datawarm1
180 44.8gb 51.6gb 148.4gb 200gb 25 192.0.2.11 smos-datawarm2
Пример при сбое: один из узлов превысил высокий порог Disk Watermark и перестал принимать новые шарды (shards = 0, disk.percent близок к 100):
shards disk.indices disk.used disk.avail disk.total disk.percent host node
182 45.2gb 52.1gb 147.9gb 200gb 26 192.0.2.10 smos-datawarm1
0 178.9gb 189.3gb 9.1gb 200gb 95 192.0.2.11 smos-datawarm2
Получите список неразмещенных шардов с кратким указанием причин, не запрашивая каждый шард отдельно:
GET _cat/shards?v&h=index,shard,prirep,state,node,unassigned.reason
Чтобы получить подробное объяснение причины неразмещения первого найденного шарда, выполните запрос без указания конкретного шарда:
GET _cluster/allocation/explain
Если требуется объяснение для конкретного шарда, найденного через _cat/shards, укажите его параметры:
GET _cluster/allocation/explain
{
"index": "<INDEX_NAME>",
"shard": 0,
"primary": true
}
Пример ответа при достижении дискового порога: поле deciders содержит disk_threshold:
{
"index": "winlog-000123",
"shard": 0,
"primary": true,
"current_state": "unassigned",
"can_allocate": "no",
"allocate_explanation": "cannot allocate because allocation is not permitted to any of the nodes",
"node_allocation_decisions": [
{
"node_name": "smos-datawarm2",
"node_decision": "no",
"deciders": [
{
"decider": "disk_threshold",
"decision": "NO",
"explanation": "the node is above the high watermark cluster setting [cluster.routing.allocation.disk.watermark.high=90%], having less than the minimum required [10%] free disk on node, actual free: [4.5%]"
}
]
}
]
}
Одна из распространенных причин неразмещения шардов - достижение дискового порога на узлах data. Подробнее о механизме и уровнях защиты см. в статье Настройка Disk Watermark.
Что делать
-
Освободите место на диске проблемного узла: удалите старые индексы вручную или ускорьте работу политики ISM. Это устраняет причину, а не только ее проявление
-
Если место освобождено, но шарды не переразмещаются автоматически, повторно запустите расчет размещения
POST _cluster/reroute?retry_failed=true -
Повышайте пороги
cluster.routing.allocation.disk.watermark.*только временно, если свободного места нет и требуется время на расширение диска или добавление узла (см. Настройка Disk Watermark). После устранения причины восстановите прежние значения
Если _cluster/allocation/explain указывает на cluster.routing.allocation.enable, а не на нехватку места, размещение шардов было явно отключено ранее, например на время обслуживания кластера. Проверьте, в каком блоке задана настройка: transient или persistent:
GET _cluster/settings?include_defaults=true&filter_path=*.cluster.routing.allocation.enable
Изменяйте настройку в том же блоке, где она задана. Блок transient имеет приоритет над persistent, поэтому запрос PUT к блоку persistent не переопределит значение из transient. Если настройка задана в persistent:
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.enable": "all"
}
}
Если настройка задана в transient, измените ее в том же блоке. Значение null удаляет переопределение из transient, после чего применяется значение из persistent или значение по умолчанию:
PUT _cluster/settings
{
"transient": {
"cluster.routing.allocation.enable": null
}
}
Если первичный шард безвозвратно утрачен, например вместе с узлом, на котором находилась единственная копия данных, стандартные действия выше не помогут. Восстановление данных возможно только из снапшота (см. Снапшоты).
Если снапшота нет, а продолжать работу с индексом важнее сохранности недавних данных в утраченном шарде, можно принудительно выделить пустой первичный шард:
POST _cluster/reroute
{
"commands": [
{
"allocate_empty_primary": {
"index": "<INDEX_NAME>",
"shard": 0,
"node": "<NODE_NAME>",
"accept_data_loss": true
}
}
]
}
У индекса может быть несколько первичных шардов (0, 1, 2 и т. д.). В команде необходимо указать конкретные шард (shard) и узел (node), а не только индекс.
Если на одном из узлов сохранилась устаревшая (stale) копия шарда, например после временной недоступности узла, используйте вместо allocate_empty_primary команду allocate_stale_primary с теми же параметрами. Она назначает сохранившуюся копию первичной, поэтому потери данных меньше, чем при выделении пустого шарда.
allocate_empty_primary безвозвратно удаляет данные утраченного шарда. Используйте эту команду только при отсутствии устаревшей копии, если восстановление из снапшота невозможно или не требуется.
Нагрузка на узлы
Проверьте нагрузку на узлы: использование памяти кучи JVM, диска и процессора:
GET _cat/nodes?v&h=name,heap.percent,disk.used_percent,cpu,load_1m
Пример ответа при исправной работе:
name heap.percent disk.used_percent cpu load_1m
smos-datawarm1 45 52 8 1.20
smos-datawarm2 48 51 11 1.35
Пример при перегрузке: высокое использование памяти кучи JVM и диска, устойчивая нагрузка на процессор:
name heap.percent disk.used_percent cpu load_1m
smos-datawarm1 92 94 87 7.60
smos-datawarm2 49 51 12 1.40
CPU
Что делать
-
Определите потоки, нагружающие процессор, с помощью Hot Threads API
GET _nodes/smos-datawarm1/hot_threads?threads=5&interval=1sОтвет содержит наиболее нагруженные потоки и их стеки вызовов (поиск, индексация, слияние сегментов и т. д.)
-
Если нагрузку вызывают длительные поисковые запросы, найдите их через Tasks API
GET _tasks?actions=*search&detailedПри необходимости отмените зависший или ресурсоемкий запрос, не дожидаясь его завершения
POST _tasks/<task_id>/_cancel -
Чтобы ограничить подобные запросы в будущем, используйте настройки кластера
search.max_buckets(лимит числа бакетов в агрегации) иsearch.allow_expensive_queries: false, а также SME Circuit Breaker и лимиты поискаОбратите внимание!search.allow_expensive_queries: falseзапрещает wildcard-, regexp- и script-запросы, а также некоторые другие ресурсоемкие типы запросов. Перед применением на продуктивном кластере проверьте на тестовом стенде, какие SML-запросы и дашборды используют эти типы: после включения настройки они перестанут работать. -
Если нагрузку создает индексация, а не поиск, проверьте Data Collector (см. Throughput)
-
Если ресурсов узла постоянно не хватает, увеличьте число доступных процессорных ядер или добавьте в кластер узел
data
Heap
Что делать
См. раздел Circuit breaker: причины высокого использования памяти кучи JVM и срабатывания circuit breaker связаны.
Thread pool
Проверьте очереди и число отказов в пуле потоков. Рост этих показателей указывает на то, что узел не успевает обрабатывать запросы на запись или поиск:
GET _cat/thread_pool?v&h=node_name,name,active,queue,rejected
Пример ответа при исправной работе (rejected = 0):
node_name name active queue rejected
smos-datawarm1 write 2 0 0
smos-datawarm1 search 4 0 0
Пример при перегрузке: rejected растет, запросы на запись отклоняются. На стороне Data Collector это проявляется повторными попытками записи (см. Диагностика проблем Data Collector):
node_name name active queue rejected
smos-datawarm1 write 8 124 347
smos-datawarm1 search 13 89 52
Что делать при росте rejected
- Снизьте входящую нагрузку у источника. Для пула
writeэто поток от Data Collector (см. Throughput и Backpressure); возможно, его нужно замедлить. Для пулаsearchсократите число одновременных поисковых запросов или их ресурсоемкость - Не рассматривайте увеличение
queue_sizeсоответствующего пула потоков как постоянное решение: оно откладывает, но не устраняет исчерпание ресурсов - Если нагрузка ожидаема, например из-за роста объема данных, добавьте в кластер узлы
data
Circuit breaker
Проверьте срабатывания circuit breaker: при угрозе нехватки памяти узел принудительно прерывает запрос:
GET _nodes/stats/breaker
Пример ответа при исправной работе (tripped = 0):
{
"nodes": {
"a1b2c3": {
"name": "smos-datawarm1",
"breakers": {
"parent": {
"limit_size_in_bytes": 1037252096,
"estimated_size_in_bytes": 123456789,
"overhead": 1.0,
"tripped": 0
}
}
}
}
}
Пример при перегрузке: estimated_size_in_bytes близок к limit_size_in_bytes, tripped растет при отклонении запросов. В журнале и ответе появляется ошибка circuit_breaking_exception:
{
"nodes": {
"a1b2c3": {
"name": "smos-datawarm1",
"breakers": {
"parent": {
"limit_size_in_bytes": 1037252096,
"estimated_size_in_bytes": 1021345678,
"overhead": 1.0,
"tripped": 14
}
}
}
}
}
Если circuit breaker срабатывает регулярно, проверьте настройки sme.breaker.* (см. Использование Circuit Breaker в SME).
Для оценки нагрузки на память кучи JVM проверьте долю используемой памяти узла:
GET _nodes/stats/jvm?filter_path=nodes.*.jvm.mem.heap_used_percent
Если на узле используется сборщик мусора G1GC, дополнительно проверьте заполнение пула старого поколения: GET _nodes/stats?filter_path=nodes.*.jvm.mem.pools.old.
Если heap_used_percent длительное время близок к порогу родительского circuit breaker (по умолчанию 95 %), узлу регулярно не хватает памяти кучи JVM. Проверьте журнал узла: частые записи о сборке мусора (GC), занимающей значительную часть времени, подтверждают нехватку памяти.
Что делать
Circuit breaker - защитный механизм, а не причина проблемы. Единичные срабатывания при ресурсоемких разовых запросах допустимы.
Регулярный рост tripped при длительно высоком heap_used_percent указывает на нехватку памяти кучи JVM при текущей нагрузке. Примените те же меры, что и при высокой нагрузке на процессор: найдите и ограничьте ресурсоемкие запросы через Hot Threads API, Tasks API, search.max_buckets и search.allow_expensive_queries. Если нагрузка связана с объемом данных, увеличьте память кучи JVM или добавьте узлы.
Снижать sme.breaker.limit для решения проблемы нехватки памяти не рекомендуется: это лишь увеличит число прерванных запросов.
Проблемные индексы
Получите список индексов со статусом yellow или red:
GET _cat/indices?v&health=yellow
GET _cat/indices?v&health=red
При исправной работе оба запроса возвращают пустой список. Пример при сбое:
health status index uuid pri rep docs.count store.size
yellow open winlog-000123 k3F8s... 1 1 1245833 512.4mb
red open syslog-000045 p9A2x... 1 1 845213 301.1mb
Типичные причины и действия:
- недостаточно узлов для размещения заданного числа реплик (
yellow) - добавьте в кластер узелdataили уменьшитеnumber_of_replicasдля индекса, если избыточность реплик не требуется - достигнут дисковый порог (
redилиyellow) - см. раздел Распределение шардов и дисковое пространство - конфликт маппинга полей при записи данных из Data Collector - преобразуйте тип поля в пайплайне Data Collector до отправки (см. Dead Letter Queue) или скорректируйте шаблон маппинга индекса. Индекс с уже заданным неверным типом поля потребуется переиндексировать (см. Reindex)
- неконтролируемый рост числа полей в маппинге (mapping explosion при разборе разнородных журналов с динамическим маппингом) - ограничьте число полей настройкой
index.mapping.total_fields.limitв шаблоне индекса и измените парсинг в Data Collector, чтобы он не создавал отдельное поле для каждого уникального значения. Возможная причина - JSON с произвольными ключами, разобранный как набор отдельных полей вместо вложенного объекта
Если размер индексов растет без ротации, настройте политику управления жизненным циклом (см. Управление индексами).
Smart Monitor Master Node
Определите текущий master-узел и проверьте состояние кворума:
GET _cat/cluster_manager
GET _cluster/state/master_node
Пример при исправной работе: master-узел выбран, его идентификатор совпадает в ответах обоих запросов:
id host ip node
ebTq31e_RMi9lpmnsdBl0w 192.0.2.12 192.0.2.12 smos-master1
Если master-узел не выбран из-за отсутствия кворума, запрос GET _cat/cluster_manager возвращает пустой ответ. Запросы, изменяющие состояние кластера, например создание индекса или обновление настроек, могут зависать либо завершаться по таймауту.
Проверьте задачи кластера, ожидающие выполнения, например при отсутствии кворума или перегрузке master-узла:
GET _cluster/pending_tasks
Пример при исправной работе: список задач пуст:
{
"tasks": []
}
Пример при сбое: задача длительное время находится в очереди (time_in_queue_millis измеряется в миллисекундах):
{
"tasks": [
{
"insert_order": 101,
"priority": "URGENT",
"source": "shard-failed",
"time_in_queue_millis": 184320
}
]
}
Недоступность master-узла или отсутствие кворума блокирует изменение состояния кластера, в том числе создание индексов и перераспределение шардов.
Что делать
Дальнейшие действия зависят от наличия кворума. Проверьте его запросом GET _cat/cluster_manager из предыдущего раздела.
Кворум есть (master-узел выбран, один из узлов необходимо вывести):
-
Если узел временно недоступен из-за сетевой проблемы или перезагрузки, восстановите его работу. Кворум сохраняется, пока большинство узлов остается доступным
-
Если узел потерян безвозвратно или выводится планово, исключите его из конфигурации голосования. Команда изменяет состояние кластера и требует активного master-узла, поэтому выполняется только при наличии кворума
POST _cluster/voting_config_exclusions?node_names=<NODE_NAME>После остановки и вывода узла удалите исключение: автоматически оно не снимается
DELETE _cluster/voting_config_exclusions?wait_for_removal=false -
Для планового вывода узла с ролью
masterиспользуйте процедуру Исключение узла с ролью master, которая включает оба действия выше и дополнительные настройки
Кворума нет (GET _cat/cluster_manager возвращает пустой ответ, master-узел не выбран):
- Не выполняйте
POST _cluster/voting_config_exclusions: без активного master-узла команда зависнет. Восстановите работу достаточного числа узлов с рольюmaster, чтобы получить большинство от текущего состава голосующих узлов. Если они недоступны временно из-за сети или перезагрузки, дождитесь их возвращения: кворум восстановится автоматически - Не пытайтесь восстановить кворум добавлением нового узла с ролью
master. Изменение состава голосующих узлов само требует кворума и невозможно до его восстановления; принудительное изменение состава может усложнить восстановление
Если большинство master-узлов потеряно безвозвратно и снапшота нет, для восстановления кворума используют офлайн-утилиту opensearch-node.
Команды opensearch-node unsafe-bootstrap и detach-cluster изменяют метаданные кластера без согласования и могут привести к потере данных. Используйте их только при безвозвратной потере большинства master-узлов и отсутствии снапшота. По возможности сначала восстановите кластер из снапшота.
Выполняйте все команды на остановленных узлах. Утилита находится в каталоге установки Data Storage, обычно /app/opensearch/bin/opensearch-node:
-
Выберите сохранившийся узел с ролью
masterи наиболее актуальным состоянием. Утилита выводит паруCurrent node cluster state (term, version); если сохранилось несколько master-узлов, выберите узел с наибольшей парой(term, version) -
Остановите службу Data Storage на выбранном узле (
systemctl stop opensearch). Утилита работает только на остановленном узле: иначе каталог данных заблокирован (node.lock) -
Выполните начальную загрузку кластера на этом узле и подтвердите запрос
/app/opensearch/bin/opensearch-node unsafe-bootstrapПризнак успешного выполнения - сообщение
Cluster-manager node was successfully bootstrapped -
На каждом другом узле, возвращаемом в кластер (как
master-eligible, так иdata), остановите службу и отсоедините узел от старого кластера. Иначе он не присоединится из-за несовпадения UUID кластера/app/opensearch/bin/opensearch-node detach-cluster -
Запустите службу Data Storage на всех узлах (
systemctl start opensearch). Узел из шага 3 станет master-узлом, остальные присоединятся к нему -
Проверьте восстановление запросами
GET _cat/cluster_manager(master-узел выбран),GET _cluster/health(green/yellow) иGET _cat/nodes
Логи
Ошибки узлов Data Storage, например circuit_breaking_exception, OutOfMemoryError и CorruptIndexException, записываются в журнал кластера на каждом узле:
${OS_LOGS}/<cluster_name>.log