Часто встречающиеся проблемы и пути их устранения#

Примечание

Для анализа проблем используются логи и метрики, полученные через JMX.

Анализ производительности в DataGrid#

Возможные причины проблем с производительностью:

  1. Настройки операционной системы.

  2. Настройки DataGrid или работа с данными.

  3. Настройки JVM.

  4. Иные причины во время эксплуатации (оборудование и прочее).

  5. Аппаратные настройки.

При поиске проблем с производительностью стоит начать с первых трех пунктов.

Внимание

Настройки DataGrid для кластеров in-memory и persistence могут отличаться.

Шаг 1. Проверьте настройки ОС#

Цель: достичь максимальной производительности ОС.

  • Скорректируйте количество открытых файлов.

    Это важно, так как если используется native persistence, каждая партиция является отдельным файлом на диске, и из-за установленного back-up фактора для кеша количество файлов партиций кратно увеличивается в DataGrid, поэтому на каком-то из узлов возникнет ошибка «Too many files».

    Узнать количество открытых файлов на данный момент можно следующим образом:

    cat /proc/sys/fs/file-nr
    

    Внимание

    Не используйте команду lsof | ws I, так как это завысит количество открытых файлов в данный момент и включит другие файлы, используемые другими процессами. Команду можно использовать только при постановке фильтрации по дубликатам.

  • Ограничьте время использования сервера одним пользователем.

    Для этого измените ограничение open files (-n) в файле /etc/security/limits.conf;

  • Запретите использование swap (подкачки) на узлах кластера, так как это приведет к ухудшению общей производительности системы.

    В файле etc/sysctl.conf установите параметр vm.swappiness=0.

    Примеры проверки использования swap:

    • free -h — наличие ненулевых значений говорит об использовании подкачки.

    • swapon –show — наличие подкачки и ее характеристики.

    Примечание

    При отключении swap (подкачки) использование swapping для in-memory кластера DataGrid станет невозможным.

    Примечание

    Отключение swapping не используется по следующим причинам:

    1. Нет сохранности данных между рестартами узла.

    2. Низкая производительность.

  • Отключите transparent huge pages, SELinux, zeroconf, увеличьте до максимума значения буферов rx и tx сетевых адаптеров, укажите в файле /etc/hosts IP-адреса и имена всех узлов кластера, чтобы исключить проблемы с DNS.

Для выдачи действующих параметров sysctl используйте команду:

sudo sysctl -a

Шаг 2. Проверьте работу DataGrid и работу с данными#

  1. Проверьте выбранные таймауты, так как даже при небольших задержках они могут привести к проблемам, например, неправильная настройка failureDetectionTimeout может привести к определению узла кластера как FAILED.

  2. Проверьте, используется ли Affinity Colocation там, где он может.

  3. При активной работе с кешами Native Persistence (этот режим создавался для ситуаций, когда размер данных на узлах больше доступного объема ОЗУ) может возникать Page Replacement (вытеснение неиспользуемых страниц из ОЗУ и погрузка страниц с нужными данными с диска), что приводим к дополнительным накладным расходам.

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

  5. Текущие настройки DataGrid видны в файле ignite.log при запуске узла: IgniteConfiguration, Data Regions после Topology Snapshot.

Шаг 3. Проверьте настройки JVM#

Текущие настройки JVM видны в файле ignite.log при запуске узла: VM arguments на момент запуска. Можно искать JVM-опции в CommandLine flags в файле gc_server_memory.log, но вывод может быть неполным.

Шаг 4. Воспользуйтесь инструментами мониторинга#

Подробное описание метрик вы можете найти в разделе «События мониторинга» документа «Руководство по системному администрированию».

Zabbix

Система мониторинга статусов разнообразных сервисов компьютерной сети, серверов и сетевого оборудования. Осуществляет проверку доступности, производительности и сбор желаемых данных с использованием пользовательских интервалов. Поддерживает мониторинг с использованием SNMP, IPMI, JMX, VMware и пользовательских настроек.

Grafana

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

JMX

Метрики Java management extensions (JMX) — это технология мониторинга и управления Java-приложениями. Работает через объекты MBeans (Managed Beans). Использование JMX для больших экземпляров JIRA Server и JIRA Data Center позволит легко контролировать потребление ресурсов приложений. Мониторинг JMX-метрик может вестись через JConsole, Hyperic, Zabbix (с версии 2.0), GridGain Web Console, тд.

Подробнее о JMX метриках в Apache Ignite и о метриках через Zabbix. C версии Zabbix 2.0 был выпущен Java Zabbix demon. Когда сервер Zabbix захочет узнать значение конкретного счетчика JMX на узле, он спросит Zabbix Java gateway, который использует API управление JMX, запросить интересующее приложение удаленно.

jconsole

Инструмент с графическим интерфейсом для управления и мониторинга JVM (локальными и удаленными) и приложениями. Для получения подробной информации о графическом интерфейсе jconsole обратитесь к документации Oracle.

Context Switches per Second

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

Единица измерения — количество переключений контекста в секунду.

В процедуру переключения контекста входит планирование задачи (какой задаче передать управление) и следующие аппаратные действия:

  • очистка конвейера команд и данных процессора;

  • очищается TLB, отвечающий за страничное отображение адресов на физические.

На состояние системы влияет содержимое кеша, особенно первого уровня, так как заточено под один поток и часто неприменимо к новому потоку, на который происходит переключение. При использовании swap (подкачки) при переключении контекста неиспользуемый процесс многих страниц может не находится в ОЗУ, что приводит к подкачке вытесненных страниц с диска.

Таким образом, переключение контекста очень ресурсоемко. При изучении метрик Context switches per second на графике обратите внимание на рост или резкое падение метрики:

  • рост — начало ресурсоемких операций на кластере (исполняющаяся задача на гриде, процедура ребалансировки, снятия снепшота, возросшая нагрузка в другом приложении в этом узле и прочее);

  • резкое падение — завершение тех или иных процессов.

Context switches говорит о росте нагрузки или увеличении числа активных потоков, но не говорит о корневых причинах, например, о процессах внутри приложения DataGrid или любого другого приложения на узле.

CheckPoint-операция, CheckPoint Time, CheckPoint Pages

CheckPoint-операция — сброс измененных страниц из памяти на диск.

CheckPoint Time — время выполнения операций CheckPoint для Native Persistence-кешей. Причины роста метрики:

  • рост количества записанных страниц при создании контрольной точки (CheckPoint);

  • повышенная нагрузка на диск;

  • проблемы с диском.

CheckPoint Pages — количество измененных страниц, требующих сохранения на диск. Перекос на графике показывает неравномерность распределения данных по серверным узлам, что означает наличие ошибок проектирования структуры данных, либо неправильное их распределение, например, проблема с пользовательской Affinity Function. Рост показателя или заметный перекос означает:

  • рост нагрузки на кластер по модификации данных;

  • ошибки проектирования структуры данных;

  • неправильное распределение структуры данных.

Чаще всего между CheckPoint Time и CheckPoint Pages есть связь, так как нужно больше времени для записи на диск большего числа страниц.

LRT (Long Running Transactions)

LRT — долго выполняющиеся в кластере транзакции. Они часто являются следствием проблем, вызванных следующими причинами:

  • повышенная загруженность узлов;

  • наличие сетевых проблем, приводящих к деградации вычислений;

  • прочие причины:

    • длительные GC-паузы на узлах;

    • неоптимальный код;

    • падение узлов.

JVM-опция IGNITE_LONG_OPERATIONS_DUMP_TIMEOUT отвечает за порог срабатывания для отпечатывания сообщения о наличии LRT в лог. Значение по умолчанию — 1 секунда.

Stop-the-World (STW)

Stop-the-World (STW) — период времени, в течение которого простаивают все процессы в JVM, кроме GC (очистки мусора). Это позволяет безопасно провести очистку мусора. STW используется для дефрагментации памяти и иных процессов. STW представляет собой GC-паузу, и приложение в эти моменты простаивает.

В HotSpot JVM механизмы паузы STW называются безопасной точкой, или Safepoint. Во время Safepoint все потоки, выполняющие код Java, приостановлены. Потоки, выполняющие собственный код, могут продолжать работать, пока они не взаимодействуют с JVM, так как попытка получить доступ к Java-объектам через JNI, вызвать java-метод или вернуться из собственного в java, приостановит поток до конца безопасной точки.

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

При проблемах с производительностью в JVM стоит найти ту фазу GC, которая занимает большее время, и сопоставить эту информацию с целями анализа и конкретной ситуацией.

Внимание

Проблемы с длительностью GC-пауз часто встречаются при наличии большого heap.

Striped Executor Pool

Пул потоков executor, помогающий ускорить основные операции кеширования и транзакции, распределяя выполнение операций по не конкурирующим за ресурсы потокам. Размер пула равен max(8, общее количество ядер). Его можно изменять через IgniteConfiguration.setQueryThreadPoolSize(..).

Скачки на графике Striped Executor говорят об успешном обслуживании резко накопившейся очереди. Линейные графики с резким ростом, долгим линейным падением, линейным долгим ростом означают проблемы, так как очередь накапливается быстро, но не успевает быть быстро обслужена.

PME

PME (Partition Map Exchange) — процесс обмена информацией между узлами об актуальном состоянии партиций. Цель — установить актуальное состояние партиций для всех узлов кластера.

Exchange-процесс:

  1. Узлы кластера отправляют свою локальную информацию узлу-координатору - GridDhtPartitionsSingleMessage.

  2. Узел-координатор объединяет информацию о локальном разделе.

  3. Узел-координатор строит карту партиций и отправляет ее остальным узлам, чтобы они знали, где искать ключи.

PME требуется при распределении партиций для любых изменений кеша, например:

  • создание индекса;

  • добавление новых узлов в топологию;

  • покидание топологии старыми узлами (запроса пользователя или сбой).

События топологии:

  • Обнаружение нового узла в топологии.

    Внимание

    Событие не запускает PME, если толстый клиент подключает кластер в версиях от 2.8 и выше;

  • Узел выбыл из топологии.

    Внимание

    Событие не запускает PME с версии 2.8 и позже, если узел покидает текущую топологию.

  • Node.FAILED — обнаружен не реагирующий узел.

Пользовательские события:

  • GlobalStateMessage — активация или деактивация базовой топологии;

  • DynamicCacheChangeBatch — запуск или остановка динамического кеширования;

  • SnapshotDiscoveryMessage — создание или восстановление снепшотов;

  • WalStateAbstractMessage — включение или отключение global WAL;

  • CacheAffinityChangeMessage — Late affinity assignment.

При запуске процесса PME кластер ожидает завершения выполнения всех транзакций и только потом начинает PME. Новые транзакции откладываются и ждут завершения PME.

Процесс PME работает следующим образом:

  1. Узел-координатор запрашивает со всех узлов информацию о партициях, которыми они владеют.

  2. Каждый узел отправляет эту информацию координатору.

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

  4. Когда узел-координатор получил подтверждающие сообщения от всех узлов, PME считается завершенным.

Длительность PME можно найти через Zabbix, записи о PME содержаться в классе GridMetricManager.

Query Execution

Если время фиксации проблемы слишком большое, то это может быть причиной или следствием проблем с производительностью. Часто такими проблемами являются FULL SCAN-запросы без использования индекса. Можно посмотреть в плане запроса.

TCPCommunicationSPI

SPI — Service Provider Interface — OutboundMessagesQueueSize — размер очереди исходящих сообщений с коммуникационными сообщениями, ожидающими отправки на другие узлы. Рост размера очереди TCPCommunicationSPI может говорить о проблеме. Одиночные пики проблемой не являются.

Bash (Bourne again shell) — прямой заход на узлы кластеров и выполнение нужных команд невозможно, поэтому информация по логам доступна по запросу с открытого тикета. Если логов много, хранить их в виде текстовых файлов неудобно, для их обработки и удобного вывода лучше использовать стек программ.

dmesg -T

dmesg — команда UNIX-подобных ОС для вывода буфера сообщений ядра в стандартный поток вывода, начиная с сообщения о загрузке ядра ОС в память компьютера, загрузке драйверов и так далее. Уровень детализации сообщений регулируется через параметры загрузчика. После полной загрузки сообщений в логи могут записываться дополнительные сообщения по диагностике, например, об ошибках I/O или при подключении устройств.

dmesg -T — выводит время в человекочитаемом формате;

dmesg –decode — выводит категорию и уровень журналирования в удобном для чтения формате, преобразуя числовое значение уровней загрузки и параметры операции в понятные текстовые примечания.

Изучая логи, смотрите на ошибки во время работы системы. При блокировке процесса выясните тип паузы, JVM или GC. Проверьте, есть ли аварийное завершение процесса по обрыву логов без видимой причины. Если да, найдите записи об OOM Error: kill process. Логи dmesg могут подсказать, где произведен запуск: на физическом сервере или на VM. Для этого найдите DMI, например, VMware Inc.

Java Flight Recorder (JFR)

Java Flight Recorder — файл с информацией по потокам, GC-паузам для дальнейшего анализа через JMC (Java Mission Control — подробно описано ниже). Подробнее о JFR читайте в документации Oracle.

JFR обязателен при принятии стенда на поддержку. Если со стороны DataGrid не снимается JFR, при повторных ситуациях снимите jstack последовательно со всех серверных узлов около 3 раз и включите эту информацию в тикет.

Чтобы использовать JFR для записи событий о работе Java в непрерывном режиме нужно указать в VM options XX:+UnlockCommercialFeatures и XX:+FlightRecorder.

Приложение pGraph позволяет представлять статистику nmon на графике по разрезам.

JFR управляется через jcmd. Он дублирует функционал других команд JDK и применим для запуска, остановки или сброса записей на диск. Он распечатывает текущие метрики, публикуемые в .jstat.

Дополнительную информацию вы можете найти в разделе TroubleShooting and Debugging официальной документации Apache Ignite.

  1. Начните с General секции в JMC. Если есть данные о конкурирующих процессах или I/O предупреждениях, смотрите их позже, так как там содержится общая информация.

  2. Получите сведения о системе через команды dstat или vmstat:

  3. dstat -ta --top-cpu --top-mem -m -s.

  4. vmstat -t 1.

  5. Проверьте загрузку процессора. Для этого воспользуйтесь командами sysctl. Команда sysctl vm выведет информацию только по VM.

  6. Проверьте swap настройки. Сверьте их с конфигурационными и рекомендуемыми настройками.

JCMD

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

Java Mission Control (JMC)

Открывает .jfr-файлы, имеет шкалу времени для выбора периода визуализации и секции General, Memory, Code, Threads, I/O, System, Events.

General – overview: Heap Usage, CPU Usage, GC Pause Time – avg и max.

General – JVM: JVM start, JVM version, cmd lines аргументы JVM, JVM flags. До .jfr информация видна в ignite.log.

Memory – overview: Memory Usage с разбивкой по Memory (Physical, Used) и Heap (Commited, Reserved), GC configs, GC stats, Memory Allocation Summary.

Memory – GC: наличие и длительность GC-пауз, Heap (Commited, Used). Тип, GC Reason, GC ID, время начала и окончания, фазы GC, размер Heap до и после GC.

Memory – GC Times: длительность GC-пауз (время возникновения, длина). Pause Stats Info (avg, max, total), generation stats – young и old collection time.

Code – overview: общая информация по коду, сортировка по частоте использования в коде пакетов и классов – Hot Packages, Hot Classes.

Code – Hot Methods: дерево с указанием частоты использования методов. Полезно для поиска аномалии, зацикливаний в коде через время выполнения методов либо частоту использования.

Threads – overview: общая информация по потокам: CPU Usage, Thread Count, полезно для оценки загрузки процессора с Active Threads, Daemon Threads.

Threads – Hot Threads: часто используемая информация, показывает Java Thread ID, OS Thread Id – количество и процент использования, связь с Hot Methods.

Threads – Thread Dumps: полезно, если нет информации по TD.logs, можно получить расширенную информацию по Thread Dump, но нельзя копировать Thread, так как текстовый поиск отсутствует.

Threads – Lock Instances: полезна при поиске аномальной длительности блокировок (более часа), чтобы выяснить источники аномалий.

I/O: редко используется, так как редко где настроена, содержит статическую информацию по Input/Output.

System: редко используется, dmesg вывод, nmon — в логах, данные о системе, CPU, количестве ядер, о потоках, сокетах, размере физической памяти, ОС.

Events: почти не используется в анализе.

Sysstat

Пакет инструментов мониторинга производительности для Unix-подобных операционных систем. Логи хранятся в каталоге /var/log/sysstat/.

sar — сбор информации об активности системы, читает данные в формате saXX, получаемое от sa1.

iostat — отчеты об использовании CPU и статистика по I/O.

mpstat — глобальная статистика и отчеты по каждому процессу.

pidstat — отчеты по процессам в Linux.

sadf — генерирует отчеты от sar в различных форматах и визуализирует log.

nfsiostat — статистика I/O для сетевых файловых систем.

sadc — утилита сбора данных об активности системы, сохраняет их в файле в двоичном формате, по одному файлу каждые 24 часа, но можно настроить более частую периодичность, является надстройкой над sar.

sa1 — утилита по сбору, обработке и сохранению статистики в двоичном формате данных, использует sadc для этой цели, запускается через cron. На выходе имеем бинарный файл saXX, где XX — номер дня в месяце, что делает удобным поиск лога по нужной дате. Sar читает данные в формате saXX.

sa2 — утилита по сбору, обработке и сохранению статистики в текстовом формате, использует sadc для этой цели, запускается через cron. На выходе имеет текстовый файл в формате sarXX, который сохранен по тому же пути, что и saXX.

cifsiostat — отображает статистику операций чтения и записи в файловых системах CIFS.

Базовые проверки, нужные для выполнения#

Первые шаги#

  1. Соберите подробную информацию о среде развертывания.

  2. Проанализируйте возможную конкуренцию с другими VM за CPU и память, так как она может привести к падению производительности.

  3. Уточните:

    1. Размер кластера. Он должен быть больше одного узла и система должна быть распределенной.

    2. Конкуренция за ресурсы отсутствует.

    3. Количество узлов на физическую машину. В идеале DataGrid должен владеть всеми ресурсами, иначе нужно настроить высокую доступность и убедиться в тос, что нет копий (первичных и резервных) разделов на одних и тех же физических машинах. Производительность заранее проверяется при тестировании.

    4. Количество процессоров.

    5. Размер ОЗУ компьютера.

    6. Диски. При включенном Native Persistence следует предпочесть SSD накопители вместо жестких дисков. Подробнее в разделе Настройка памяти и JVM официальной документации Apache Ignite.

  4. Измерьте производительность, пропускную способность и выясните:

    1. Операции, используемые потоками.

    2. Информацию по типу кеша.

    3. Информацию по JDBC, тонким и толстым клиентам.

    4. Количество потоков, выполняющих операции.

    5. Показатели, используемые для измерения производительности.

  5. Выясните конфигурацию DataGrid, сравните все настройки использования. Обратитесь к архитектору решения, если нужно.

  6. Запросите логи.

  7. Изучите настройки JVM и запросите журналы GC для серверных и клиентских узлов.

  8. Изучите план запросов при использовании SQL (Explain Analyze).

Если не получается найти узкое место при анализе информации выше, нужно переходить к поиску через другие диагностические инструменты, например, Java Flight Recorder (JFR). Подробное описание JFR содержится в соответствующем подразделе выше.

Анализ через диагностические инструменты#

Возможные источники проблем с производительностью делятся на три категории:

  1. Проблемы с системой:

    • центральный процессор;

    • сеть;

    • диск;

    • системные ошибки;

    • ошибки с ОС.

  2. Проблемы с JVM (GC и JVM паузы).

  3. Проблемы продукта DataGrid:

    • ошибки в логах;

    • deadlock;

    • LRT;

    • checkpoints;

    • долго исполняющиеся scan-запросы;

    • исчерпание пулов.

Проблемы с системой

В первую очередь локализуйте проблему — удостоверьтесь, что проблема именно на стороне DataGrid, а не на стороне ОС или аппаратной части.

Например: узел выпал из топологии, появились LRT — причиной этого может быть проблема на аппаратном уровне, а не в DataGrid.

Внимание

Следует обращать внимание на Heap Utilization, Memory Utilization и CPU Utilization метрики. Максимальные значения представлены в Grafana в дашборде All Stands. При их завышении найдите выбивающийся узел через дашборд. Остальные метрики вы можете найти в Zabbix.

Heap Utilization — это процент использования heap, который, при прочих равных, составляет 35%. Процент использования heap выше 35% говорит о создании большого числа объектов, что может привести к росту GC-пауз, длительность которых напрямую зависит от процента использования heap (чем больше heap используется, тем дольше GC-паузы). Ситуация постепенно может привести к ошибке OOM (Out-Of-Memory Error) из-за нехватки Heap с одновременной невозможностью очистки через GC. Возможным выходом будет только перезапуск узла кластера. Heap Utilization можно найти через Zabbix, JFR, JMX (jconsole).

Внимание

Утилизация heap, которая не приводит к ошибке OutOfMemoryError, и проблемой, по сути, не является. Утилизация выше 80% — нормальная ситуация, на некоторые стенды триггеры отключаются администраторами на 80%. Стоит пересмотреть конфигурацию мониторинга в 80%**.

Memory Utilization — процент использования памяти вне heap, или Off-Heap. GC не работает в Off-Heap, поэтому длительность GC-пауз на эту область не влияет. При работе в native persistence размер кеша может превысить выделенный размер ОЗУ и память уже заполнена LFS (large file storage). Тогда при запросе данных, которых нет в Off-Heap, они будут прочитаны с диска, что приведет к дополнительным накладным расходам, так как дисковая система работает сильно медленнее, чем ОЗУ, поэтому при Page Replacement дополнительные накладные расходы будут выше, если запрос на Page Replacement будет идти чаще.

CPU Utilization — процент использования ЦП. При прочих равных, он равен 6-7%. Если ЦП используется более, чем на 20%, то это говорит о большой нагрузке на сеть данных, возможно из-за снятия снепшотов, либо других операций в сети данных, либо из-за работы каких-либо процессов, не связанных с сетью, но происходящих в ОС узла. В этом случае, необходимо понимать, какое приложение приводит к увеличению процента использования ЦП.

  • ps aux — текущее состояние процессов выполнения их системы;

  • ps aux --sort -pcpu — текущее состояние с sort по использованию ЦП;

  • ps aux --sort -rss — текущее состояние с sort по резидентной памяти;

  • ps aux --sort -vsz — текущее состояние с sort по виртуальной памяти;

  • ps aux --sort -pmem — текущее состояние с sort по использованию ОЗУ.

Будет полезно воспользоваться командой top. Эта команда в реальном времени выводит информацию об использовании ЦП. Если просуммировать все значения, то итоговое значение будет равно 100%. Информация из top сортируема. Для сортировке используйте команды:

  • M — по потреблению памяти;

  • P — по потреблению ресурсов процессора;

  • T — по времени активности;

  • O — для фильтрации данных.

Если работа узла нестабильна:

  • система начинает неожиданно зависать;

  • при запуске нескольких программ, некоторые из них падают с Error;

  • файл или архив то успешно открывается, то указывается, что он поврежден;

  • при виртуализации проблема происходит с одним из контейнеров.

Проблемы могут быть вызваны планкой памяти, что сложно узнать из анализа логов. Проверен запуск memtest86+ для подробной проверки ячеек памяти. Проверка идет оффлайн и долго, планка памяти должна быть заменена при наличии хотя бы одной ошибки.

Свободное место на диске, или free disk space, можно увидеть в Zabbix, Grafana, в выводе df -h (свободное место на диске) и df -ih (количество оставшихся inode). Если inode нет, то это как нехватка места на диске, то есть система не может записать на диск. Возможно, что места под файлы достаточно, что покажет df -h, как свободное место на диске, но для записи новых файлов свободных дескрипторов файловой системы нет.

Примечание

Чаще всего это может происходить из-за разрастающихся логов, поэтому нужно удалять устаревшие.

inode – структура данных, хранящая данные о файле или каталоге в файловой системе.

Падение производительности может быть связано с Disk utilization. Напрямую через Grafana и Zabbix это не увидеть, но можно предположить по косвенным признакам: рост CheckPoint Time при тех же CheckPoint Pages. Альтернативой Zabbix будет запрос sar-файлов и, при возможности, запустить iostat -xz для отображения статистики по дисковой подсистеме.

Кроме этого, падение производительности может быть вызвано и ошибками дисковой подсистемы. Внесение обновлений в ядро может привести к ошибкам с XFS (высокопроизводительной журналируемой файловой системой). Тогда узлы кластера могут покидать топологию, так как на уровне ОС произошла потеря диски с XFS. Чтобы убедиться, что проблема с оборудованием, нужно искать ошибки в выводе команды dmesg -T.

Проверка фактов разрыва соединения сетевых интерфейсов может производиться через dmesg -T. Факт разрыва соединения проявится в выводе.

Ошибки на интерфейсах можно найти через команду ip -s addr или ip -a -d -s link.

Для проверки наличия сетевых проблем обратитесь к сетевым инженерам, которые проверят ошибки и разрывы соединения на портах коммутатора. Они могут быть вызваны проблемами с DNS серверами, если в hosts не прописаны узлы кластера.

Проблемы с JVM (GC и JVM паузы)

Рост показателя Heap Utilization % приводит к учащению GC и увеличению GC-пауз. JVM-паузы происходят, когда JVM ожидает от ОС завершения процессов, например, при работе с файлами JVM в случае высокой нагрузки на диск, происходят сбои диска. Они приводят к задержке I/O операций, возникновению проблем с сетью и так далее. Для мониторинга этого показателя используйте Zabbix, Grafana, а также файл ignite.log.

Для выявления типа паузы (GC- или JVM-пауза) используйте файл gc.log. В этом файле необходимо смотреть записи real= в реальном времени, отвечающие за длительность паузы соответствующего узла. Если поиск не выдаст результатов или если время записи в лог не совпадает с Possible too long JVM pause из файла ignite.log, то это JVM-пауза. Чтобы в этом убедиться, стоит запросить и изучить JFR c узла. Если в них за период возникновения записей по логу ignite.log не будет сведений и все графики — прямая от точки начала паузы до ее конца, то это подтвердит наличие JVM паузы.

Если же и в gc.log, и в ignite.log есть записи о паузе, то это GC-пауза. Для поиска причин следует изучить JFR с узла и смотрим на threads, memory usage, stacktrace.

Внимание

Часто выявляется проблема больших GC при большом Disk Utilization, например, при запуске снятия снепшота. Причина: неоптимальная конфигурация дисковой подсистемы. Разделы в массиве дисков используются одновременно для операций random write при запуске снепшота и для работы тома с ОС, там же происходят и множество I/O операций, кроме этого туда записывает свое состояние JVM (GC, Safepoint и прочие).

Рекомендуется разделять том ОС и том для снепшотов на разные массивы дисков и использовать tmpfs для информации с JVM.

Проблемы с продуктом DataGrid

Возможны следующие проблемы, связанные с продуктом:

  • ошибки в логах;

  • deadlock;

  • LRT;

  • checkpoints;

  • долго исполняющиеся scan-запросы;

  • исчерпание пулов.

Описание и методы устранения приводятся ниже.

Используемая фактура#

Для анализа проблемы используются логи и метрики, отдаваемые через JMX (описание метрик приводится в разделе «События мониторинга» настоящего документа).

Сбор фактуры#

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

Корректный сбор log-файлов#

Время, потраченное на анализ проблемы, и результат этого анализа напрямую зависят от полноты log-файлов. Проверьте, что log-файлы собраны:

  • со всех узлов кластера — серверных и клиентских. Это требование связано с особенностями распределенной системы DataGrid, в которой для анализа проблемы недостаточно собрать log-файлы только с проблемного узла;

  • с момента старта узла и до момента воспроизведения проблемы. Это позволит включить в выборку предупреждения, предшествовавшие возникновению проблемы, а также дополнительную информацию о конфигурации узла.

Местоположение основных log-файлов DataGrid настраивается через переменную окружения IGNITE_LOG_DIR. По умолчанию log-файлы располагаются в $IGNITE_HOME/work/log.

В DataGrid по умолчанию включен режим IGNITE_QUIET, который сообщает о минимуме событий. Для расширенного логирования используйте JVM-опцию IGNITE_QUIET=false.

Основные log-файлы

log-файл

Как настроить

Где находится

console.out и console.err

Не требуют настройки

$IGNITE_HOME/work/log

ignite.log

Используйте переменную окружения IGNITE_LOG_DIR

В $IGNITE_HOME/work/log (по умолчанию)

gc.log

Используйте JVM-опции:

Oracle/OpenJDK Java 8 (см. ниже таблицу «Параметры Oracle/OpenJDK Java 8»);

OpenJDK Java 11 (см. ниже таблицу «Параметры OpenJDK Java 11»)

Путь к JVM-опциям:

Oracle/OpenJDK Java 8: по пути, указанному в опции -Xloggc:{{ ignite_se_jvm_gc_log }};
OpenJDK Java 11: по пути, указанному в опции -Xlog:gc*=debug:file={{ ignite_se_jvm_gc_log }}:time,uptime,tags:filecount=50,filesize=50M

safepoint.log

Используйте JVM-опции:

Oracle/OpenJDK Java 8: -XX:+LogVMOutput -XX:LogFile={{ ignite_se_jvm_safepoint_log }} OpenJDK Java 11: -Xlog:safepoint=debug:file={{ ignite_se_jvm_safepoint_log }}:time,uptime,tags

Путь указан в JVM-опциях

JFR

Используйте JVM-опции:

Oracle (см. ниже таблицу «Настройка JFR с помощью параметров Oracle»);

OpenJDK (см. ниже таблицу «Параметры OpenJDK»)

Путь указан в JVM-опциях

/var/log/messages

Дефолтный log-файл на linux-системах; не требует настройки

/var/log/messages

/var/log/dmesg

Не требует настройки

/var/log/dmesg

nmon

Для настройки частоты сбора статистики используйте утилиту /usr/bin/nmon -ft -s 60 -c 1440 -m /var/log/nmon/. В этом примере log-файлы будут сохраняться в /var/log/nmon/

/var/log/nmon/

heap dump

Используйте утилиту jmap: jmap -dump:format=b,file=filename <pid>
Важно! Не рекомендуется для промышленной эксплуатации

Укажите путь для сохранения log-файла внутри атрибута file=filename <pid>

thread dump

Вручную с помощью утилиты jstack -l <pid> > thread_dump.txt

sar

Не требует настройки

/var/log/

jvm crush dump

Создается автоматически, если указана JVM-опция -XX:ErrorFile=/opt/ignite/logs/diag/crash-dump-%p.err

Log-файлы console.out и console.err#

Текстовые файлы, обычно небольшого объема. В файлы console.out и console.err перенаправляются потоки stdout и stderr до того момента, пока DataGrid не запустит logger, настроенный в конфигурации продукта. Сюда попадает отладочная информация до запуска DataGrid, например, информация о причине падения JVM и о неполадках в момент запуска DataGrid, например, ошибки чтения конфигурации продукта.

Файлы console.out и console.err генерируются автоматически, дополнительная настройка не требуется.

Log-файл ignite.log#

Основной log-файл приложения DataGrid для первичного анализа проблем и поиска причин их возникновения. Формат файла — текстовый, часто довольно объемный. Содержит отладочную информацию о работе DataGrid с момента запуска logger и до момента остановки/прерывания работы узла. Анализ любых проблем стоит начинать именно с файла ignite.log.

Где находятся

По умолчанию log-файлы ignite.log располагаются в $IGNITE_HOME/work/log.

Как настроить ignite.log

За настройку отвечает отдельный logger, который записывает данные в ignite.log.

Как настроить logger

В конфигурации DataGrid можно настроить logger, который будет использоваться для записи и ротации log-файлов. Рекомендуется использовать файл log4j2 (см. пример файла). Для его включения в конфигурацию DataGrid нужно добавить bean:

<bean class="org.apache.ignite.configuration.IgniteConfiguration" id="ignite.cfg">
    <property name="gridLogger">
        <bean class="org.apache.ignite.logger.log4j2.Log4J2Logger">
            <!-- log4j2 configuration file -->
            <constructor-arg type="java.lang.String" value="log4j2-config.xml"/>
        </bean>
    </property>

    <!-- other properties -->

</bean>

В примере выше log4j2-config.xml — файл конфигурации logger log4j2. Пример конфигурации log4j2 можно найти в каталоге $IGNITE_HOME/config/, который поставляется с продуктом.

Как настроить debug level

По умолчанию в log-файл попадают сообщения уровня WARN и ERROR, но иногда требуется включить сообщения DEBUG на том или ином пакете. Если используется log4j2, в секцию Loggers конфигурации log4j2 можно добавить следующую строку:

<Logger name="org.apache.ignite.internal.processors.odbc" level="DEBUG"/>

В примере выше в переменную name передается имя пакета, для которого требуется включить расширенное логирование.

Как настроить debug SSL

Включение отладочной информации для SSL полезно для установления причины сбоя. Для этого при запуске узла нужно добавить jvm-опцию:

-Djavax.net.debug=ssl,handshake
Log-файл gc.log#

Файл gc.log содержит информацию о работе Garbage Collector. Информация полезна при анализе проблем, связанных с утечками памяти, долгими GC-паузами и проблемами производительности.

В частности, файл gc.log позволяет определять долгие GC-паузы и время их возникновения. Пример команды для определения пауз длиной от 1 секунды:

`grep -P 'real=[1-9]+' имя_gc-лога'

Формат файла — текстовый, часто довольно объемный. Для анализа gc.log существуют специализированные утилиты и сервисы.

Как настроить

GC-логирование настраивается через JVM-опции. Для разных версий Java набор опций будет разным.

Параметры Oracle/Openjdk Java 8

Параметр

Описание

-XX:+PrintClassHistogramBeforeFullGC

Вывод гистограммы классов перед Full GC

-XX:+PrintClassHistogramAfterFullGC

Вывод гистограммы классов после Full GC

-XX:+PrintGC

Вывод log-файла GC

-XX:+PrintGCDetails

Вывод подробной информации о GC-log

-XX:+PrintGCDateStamps

Вывод даты в GC-log

-XX:+PrintGCTimeStamps

Вывод времени в GC-log

-XX:+PrintGCApplicationStoppedTime

Количество времени, в течение которого приложение было остановлено в safepoint

-XX:+UseGCLogFileRotation

Включение ротации GC-logs

-XX:+PrintTenuringDistribution

Вывод распределения объектов по возрасту

-Xloggc:{{ ignite_se_jvm_gc_log }}

Путь до GC-logs

-XX:NumberOfGCLogFiles=50

Количество GC-logs в ротации

-XX:GCLogFileSize=50M

Размер GC-log, после достижения которого будет происходить ротация

-XX:G1LogLevel=finest

Установка уровня логирования G1

-XX:+TraceMetadataHumongousAllocation

Логирование выделения памяти под Humongous-объекты

-XX:+G1TraceEagerReclaimHumongousObjects

Вывод подробностей о Humongous-объектах во время GC

-XX:+PrintSafepointStatistics

Вывод статистики по safepoint

-XX:PrintSafepointStatisticsCount=1

Количество записей в последнем отчете safepoint

Параметры Openjdk Java 11

Параметр

Описание

-Xlog:gc*=debug:file={{ ignite_se_jvm_gc_log }}:time,uptime,tags:filecount=50,filesize=50M

Настройка GC-log, детализация, ротация

-Xlog:safepoint=debug:file={{ ignite_se_jvm_safepoint_log }}:time,uptime,tags

Настройка safepoint-log, детализация

Log-файл safepoint.log#

Формат файла — текстовый, часто довольно объемный. Содержит информацию об аргументах JVM safepoint, глобальных флагах и потоках, которая может быть полезна при анализе проблем, связанных с долгими GC-паузами.

Как настроить

Настройки для safepoint.log (Oracle/Openjdk Java 8 и Openjdk Java 11) перечислены в таблице «Основные log-файлы».

Log-файл JFR#

Log-файл генерируется при помощи Java Flight Recorder — механизма легковесного профилирования Java-приложения. Имеет собственный формат. Для просмотра и анализа используется Java Mission Control.

Механизм JFR позволяет записывать и впоследствии анализировать огромное количество метрик и событий, происходящих внутри JVM, что значительно облегчает анализ различных проблем. Что именно окажется в файле, зависит от настроек JFR в каждом конкретном случае.

Как настроить

Запись JFR настраивается через jvm-опции. Для разных версий Java набор опций будет разным.

Настройка JFR с помощью параметров Oracle

Параметр

Описание

-XX:+UnlockCommercialFeatures

Включение коммерческой функциональности

-XX:+FlightRecorder

Разрешение на использование JFR

-XX:FlightRecorderOptions=defaultrecording={{ ignite_se_jfr_enabled; bool; string &#124; lower }},disk={{ ignite_se_jfr_disk }},settings={{ ignite_se_jfr_settings }},repository={{ ignite_se_diag_dir }},maxage={{ ignite_se_jfr_maxage }},maxsize={{ ignite_se_jfr_maxsize }},maxchunksize={{ ignite_se_jfr_maxchunksize }},dumponexit={{ ignite_se_jfr_dumponexit }},dumponexitpath={{ ignite_se_diag_dir }}

JFR при запуске JVM будут записываться на диск. Параметрами можно регулировать глубину хранения и детализацию JFR

Настройка JFR с помощью параметров Openjdk

Параметр

Описание

-XX:StartFlightRecording=disk={{ ignite_se_jfr_disk }},settings={{ ignite_se_jfr_settings }},maxage={{ ignite_se_jfr_maxage }},maxsize={{ ignite_se_jfr_maxsize }},dumponexit={{ ignite_se_jfr_dumponexit }},{% if ignite_se_jfr_dumponexit == 'True' %}filename={{ ignite_se_diag_dir }}/dumpjfr.jfr{% endif %}

Активирует JFR и определяет основные параметры его работы

-XX:FlightRecorderOptions=repository={{ ignite_se_diag_dir }},maxchunksize={{ ignite_se_jfr_maxchunksize }}

Задает дополнительные параметры работы

Log-файл /var/log/dmesg#

Дефолтный log-файл на linux-системах. Для корректного просмотра /var/log/dmesg используйте утилиту dmesg -T. Флаг -T включает удобочитаемый формат времени при выводе log-файла.

Log-файл nmon#

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

Для просмотра nmon-файлов используйте утилиту NMONVisualizer.

Log-файл heap dump#

Бинарный файл, размер которого примерно соответствует размеру heap на момент снятия heap dump. Файл содержит моментальный снимок java heap. Такой снимок содержит низкоуровневую информацию о Java-объектах и классах, размещенных в java heap. Для анализа heap dump используйте утилиты jhat или mat.

Log-файл heap dump необходимо снимать вручную. Самый распространенный способ — при помощи утилиты jmap:

jmap -dump:format=b,file=filename <pid>

В атрибуте file=filename <pid> укажите нужный путь для сохранения log-файла.

Примечание

Эта команда ресурсозатратна и может приводить к негативным эффектам при выполнении на работающем под нагрузкой кластере.

Log-файл thread dump#

Формат файла — текстовый. Содержит информацию о потоках внутри jvm.

Как настроить

Собирается вручную:

jstack -l <pid> > thread_dump.txt
Log-файл sar#

Входит в sysstat — пакет инструментов мониторинга производительности для unix-систем. Log-файл sar отвечает за сбор информации об активности системы и читает данные в формате saXX, получаемые от sa1.

WAL и WAL-архив#

Дополнительно для анализа проблем в случае сбоев могут пригодиться следующие каталоги: WAL и WAL-архив. По умолчанию эти каталоги создаются автоматически.

Проблемы и их решения#

Лишние узлы в топологии#

При использовании поискового механизма Multicast в топологии могут быть обнаружены лишние узлы. Проблема возникает:

  • при запуске нового кластера, в котором версия топологии отличается от «1»;

  • при добавлении в топологию новых узлов; для решения этой проблемы сконфигурируйте Security Plugin (рекомендованный способ) или воспользуйтесь SSL-протоколом (в случае, если невозможна настройка через Security Plugin).

Проверить количество узлов в топологии можно двумя способами:

  • через heartbeat-сообщение в log-файле ignite.log, в котором записывается количество узлов (hosts).

    Пример heartbeat-сообщения: Cluster [hosts=6, CPUs=9, servers=1, clients=5, topVer=10, minorTopVer=0];

  • через консоль control.sh с помощью команды --baseline; выполнение команды вернет consistency id узлов в топологии, по которым можно обнаружить лишний узел.

Для решения проблемы сконфигурируйте класс TcpDiscoveryVmIpFinder в конфигурационном файле DataGrid:

```xml
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
    <property name="addresses">
        <list>
            <value>127.0.0.1:47500..47509</value>
        </list>
    </property>
</bean>
```

Долгий запуск первого узла в топологии#

При данной проблеме:

  • время запуска первого узла критически увеличено;

  • после запуска узла дальнейших проблем не наблюдается.

  1. Проблема возникает при большом количестве адресов, так как DataGrid сканирует все заданные порты. При включенной защите от port scanning может не приходить сообщение Connection refused.

    Время открытия одного порта по умолчанию составляет 10 секунд. Если у вас 3 адреса и по 10 портов на один адрес, как в примере ниже, время запуска составит 5 минут:

    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
        <property name="addresses">
            <list>
                <value>ignite1.local.net:47500..47509</value>
                <value>ignite2.local.net:47500..47509</value>
                <value>ignite3.local.net:47500..47509</value>
            </list>
        </property>
    </bean>
    

    DataGrid сканирует все заданные порты:

    • connection refused может не прийти (защита от port scanning);

    • ожидание открытия порта по умолчанию - 10 секунд;

    • 3 адреса * 10 портов * 10 секунд = 5 минут.

  2. Высокое значение IgniteConfiguration.failureDetectionTimeout.

    Для решения этой проблемы не прописывайте лишние порты, укажите только те порты и адреса, которые вы используете. Дополнительно можно отключить защиту от port scanning во внутренней сети.

    Стоит снизить значение failureDetectionTimeout, чтобы сканирование через IP Finder происходило быстрее.

Проблемы при использовании IPv6#

По умолчанию, решения DataGrid тестируются с использованием четвертой версии интернет-протокола IPv4. При передаче данных с использованием шестой версии интернет-протокола IPv6 (Internet Protocol version 6) могут возникать сетевые ошибки, о которых свидетельствуют сообщения в log-файлах:

  • Failed to connect to address;

  • Node SEGMENTED;

  • Failed to send message to remote node.

Помимо указанных выше ошибок, могут возникать другие симптомы проблемы, связанной с невозможностью передачи данных. Эта проблема может быть вызвана смешанным окружением IPv4 и IPv6, когда начинает использоваться шестая версия интернет-протокола вместо четвертой.

Для решения конфликта между версиями установите значение true для параметра -Djava.net.preferIPv4Stack в конфигурационном файле Ignite-SE-15.0.0/config/jvm.opts .

Проблемы с маршалингом или сериализацией#

При взаимодействии продуктового кода с кодом DataGrid происходит сериализация. Это процесс, при котором продуктовый код преобразуется в формат, пригодный для хранения или передачи. Подробнее о сериализации см. в разделе «Термины и определения»

При записи данных в память для их дальнейшего использования DataGrid производит сериализацию объектов с помощью трех механизмов:

  • JDK Marshaller — обычная Java-сериализация;

  • Optimized Marshaller — оптимизированная Java-сериализация, при которой используются те же механизмы, что и в случае JDK Marshaller; этот механизм обеспечивает обратную совместимость с Ignite 1.9;

  • Binary Marshaller — сериализация, созданная специально для Apache Ignite, используемая в DataGrid по умолчанию; это — наиболее быстрый вариант, который позволяет избегать дополнительной сериализации или десериализации, а также работать с объектом напрямую в binary-формате.

При взаимодействии с кодом DataGrid и последующей сериализации могут возникать проблемы (WARN), о которых свидетельствуют сообщения вида Some classes in query configuration cannot be written in binary format... или Class FooBar cannot be serialized using BinaryMarshaller.

Проблемы с сериализацией классов также могут возникать при использовании кастомной реализации методов readObject() и writeObject() с помощью интерфейса Externalizable. В этом случае невозможна сериализация по механизму BinaryMarshaller, реализованном в продукте по умолчанию, так как BinaryMarshaller сериализует объекты с помощью обычной записи полей и простых методов. В случае кастомной сериализации DataGrid переключится на механизм OptimizedMarshaller, что может привести к падению производительности.

В случае возникновения проблем с сериализацией кастомных методов readObject() и writeObject(), которые по умолчанию реализуются с помощью механизма Binary Marshaller, для классов, в которых возникли проблемы, реализуйте интерфейс Binarylizable.

Рассмотрим процесс реализации Binarylizable на примере стандартного TreeMap:

private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException {
    // Write out the Comparator and any hidden stuff
    s.defaultWriteObject();
    // Write out size (number of Mappings)
    s.writeInt(size);
    // Write out keys and values (alternating)
    for (Iterator<Map.Entry<K,V>> i = entrySet().iterator(); i.hasNext(); ) {
        Map.Entry<K,V> e = i.next();
        s.writeObject(e.getKey());
        s.writeObject(e.getValue());
    }
}

Классы writeBinary() и readBinary() в интерфейсе Binarylizable работают аналогично: BinaryTreeMap «оборачивается» в обычный TreeMap и записывается в OutputStream.

Пример реализации BinaryTreeMap.writeBinary():

public void writeBinary(BinaryWriter writer) throws BinaryObjectException {
    BinaryRawWriter rewriter = writer. rewrite ();
    rawWriter.writeObject(map.comparator());
    int size = map.size();
    rawWriter.writeInt(size);
    for (Map.Entry<Object, Object> entry : ((TreeMap<Object, Object>)map).entrySet()) {
        rawWriter.writeObject(entry.getKey());
        rawWriter.writeObject(entry.getValue());
    }
}

Узел не включается в топологию#

Причина 1. Maintenance Mode режим узла

Серверный узел может не войти в топологию, если находится в Maintenance Mode режиме.

В следующих двух примерах следует обратить внимание на разницу в CPU, Heap, Local node address.

Серверный узел из топологии:

>>> Ignite ver. 2.12.0-p7#20220526-sha1:543651d5886a61d93d7f3381d3bacc10dcee3c17
>>> OS name: Linux 3.10.0-1160.59.1.el7.x86_64 amd64
>>> CPU(s): 16
>>> Heap: 15.0GB
>>> VM name: 1532437@tvldd-pprb00615
>>> Local node[ID=1A60DC51-1655-4527-96B6-2D1D27E033F8, order=2, clientMode=false]
>>> Local node addresses:[hostname, /127.0.0.1]
>>> Local ports: TCP:8080 TCP:10800 TCP:11211 TCP:47100 TCP:4750

Серверный узел, не вошедший в топологию:

>>> Ignite ver. 2.12.0-p7#20220526-sha1:543651d5886a61d93d7f3381d3bacc10dcee3c17
>>> --------------------------------------------------------------------------
>>> OS name: Linux 3.10.0-1160.59.1.el7.x86_64 amd64
>>> CPU(s): -1
>>> Heap: 0.1GB
>>> VM name: 1963884@tvldd-pprb00614
>>> Local node [ID=6D7810F8-C65A-42A8-AA78-35D4FDA29BD6, order=1, clientMode=false]
>>> Local node addresses: [localhost/127.0.0.1]
>>> Local ports: TCP:8080 TCP:10800 TCP:11211 TCP:47100

Сообщение в логах о нахождении узла в состоянии maintenance mode:

[INFO ][main][org.apache.ignite.internal.IgniteKernal] Node is being started in maintenance mode. Starting IsolatedDiscoverySpi instead of configured discovery SPI.

В отдельных случаях необходимо особое состояние узла кластера, при котором узел принимает поступающие команды через скрипты или JMX API, но не присоединяется к кластеру.

Другими словами, нужно, чтобы узел кластера мог войти в maintenance режим, например, когда выполняются действия по техническому обслуживанию.

Возможные причины перехода в режим maintenance:

  • очистка поврежденных PDS файлов;

  • Native persistence дефрагментация;

  • Corrupted cash data files.

Причина перехода в maintenance mode указана в логе:

[INFO ][main][org.apache.ignite.internal.maintenance.MaintenanceProcessor] Node requires maintenance, non-empty set of maintenance tasks is found: [*corrupted-cache-data-files-task*]

Пример 1. Очистка потенциально поврежденных PDS файлов:

Случай включает автоматическое создание Maintenance Task - специальный маркер технического обслуживания, при котором узел решает переключиться на maintenance mode при запуске.

Maintenance Task состоит из уникального ID, user-readable описания и, при необходимости, аргументов для завершения действий по техническому обслуживанию.

  • Узел падает в середине checkpoint, когда WAL архив отключен для одного или нескольких кешей.

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

  • На следующем перезапуске узел входит в maintenance mode и ожидает, что пользователь решит проблему вместо ожидания нового сбоя.

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

  • Когда файлы удаляются через ручное действие, пользователь удаляет Maintenance Task из регистра и перезапускает узел.

  • Узел запускается в нормальном режиме и присоединяется к кластеру.

Пример 2. Native persistence дефрагментация:

  • Пользователь через скрипт control.sh или через другие API запросы создает Maintenance Task для дефрагментации native persistence на узле или определенных кешах.

Maintenance Task создан и сохранен на диске;

  • Пользователь перезапускает узел, узел входит в maintenance режим, находит Maintenance Task о дефрагментации и начинает работать над задачей.

  • Когда дефрагментация выполнена, Maintenance Task автоматически удаляется. При следующем перезапуске узел с дефрагментированными PDS присоединяется к обычным операциям.

Maintenance режим применим только тогда, когда включена persistence дата регионов и хранение доступно.

В maintenance режиме узел не присоединяется к кластеру, но принимает команды пользователя и/или выполняет другие действия, необходимые для обслуживания.

Узел остается изолированным пока maintenance работы не закончены или отменены по запросу пользователя.

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

Устранение причины попадания в данный режим возможно через ручное вмешательство пользователя либо через выполнение автоматических действий запрошенного компонента Maintenance Mode.

Подробнее указано в разделе Persistence Defragmentation.

Потеря данных в persistence-кластерах#

Происходит потеря данных в кластерах, использующих режим Native Persistence.

Проблема появляется, если:

  1. Запустить один узел.

  2. Активировать кластер.

  3. Запустить еще несколько узлов.

  4. Остановить первый узел.

Причиной данной проблемы является запуск узлов после активации кластера. В данном случае эти узлы находятся вне базовой топологии (baseline) и не хранят persistent-данные.

Baseline topology — множество узлов, которые хранят на себе persistent-данные. Во всех остальных узлах persistent данных содержаться не будет (все остальные данные будут, но не persistent). Baseline topology в первый раз определяется в момент первой активации. После того, как вы добавили несколько узлов, во множество baseline они не попали, и в baseline у вас находится один первый узел.

Базовое правило — сначала запустите все узлы, а потом активируйте кластер.

Если добавляете или убираете узлы на длительное время, с помощью скрипта control.sh вы можете проверить, что у вас находится в baseline. Этот же скрипт поможет вам обновить baseline до текущего состояния.

Узлы, стартовавшие после активации, находятся вне baseline и не хранят persistent данные.

Для решения проблемы:

  • обязательно обновляйте baseline при смене топологии;

  • активируйте кластер только после запуска всех серверных узлов.

Потеря primary-партиций после перезапуска кластера#

При данной проблеме в логах появляется сообщение следующего вида:

[2022-03-09 15:30:43,662][WARN ]sys-#60%gridCommandHandlerTest0%[GridDhtPartitionTopologyImpl] Detected lost partitions [grp=default, parts=[3, 7, 13], topVer=AffinityTopologyVersion [topVer=6, minorTopVer=0]]

Данная проблема приводит к потере primary-партиций после перезапуска кластера, но данные все еще можно загрузить с диска.

Для решения проблемы выполните следующие действия:

  • запустите команду control.sh --cache reset_lost_partitions cacheName1,cacheName2,...;

  • запустите команду control.sh --cache idle_verify.

Выполнение JOIN#

Выполнение JOIN по умолчанию приводит к объединению данных, лежащих на одном узле. Такое поведение было выбрано потому, что объединение данных на одном узле выполняется быстрее, чем объединение данных на разных узлах. Сбор данных со всего кластера тормозит работу всей системы.

Чтобы минимизировать потери, связанные с объединением данных на разных узлах, можно на этапе проектирования модели данных коллоцировать те данные, которые наиболее часто будут использоваться совместно. Для этого воcпользуйтесь одним из возможных вариантов решения:

  1. Задайте affinity-ключ с помощью AffinityKeyMapped, чтобы связать данные. Подробнее читайте в разделе «Настройка с помощью affinity-ключа».

  2. Используйте реплицированные таблицы.

  3. Установите setDistributedJoins(true) или distributedJoins=true без коллокации данных. Данное решение подходит в том случае, когда коллокацию невозможно реализовать или когда уже используется модель без реализованной коллокации данных. При выборе такого решения объединение данных будет проходить с накладными расходами.

Настройка с помощью affinity-ключа#

Affinity-ключ определяет, в какой партиции будет находиться значение по заданному ключу. Если объявить конкретный атрибут (например, столбец с ID организации) affinity-ключом, то все записи для этого атрибута (например, сотрудники с таким же значением ID организации) будут находиться в одной партиции, а партиция будет находиться на одном узле. Важно знать характер данных и подбирать affinity-ключ в соответствии с ними. Например, при создании чата сохраните диалог между двумя пользователями на одном узле кластера, а пользовательские данные — на другом узле; нужные данные извлекайте с помощью команды JOIN.

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

По умолчанию DataGrid не выравнивает данные и не распределяет их равнозначно их содержимому. В нашем примере все данные будут распределены на две группы с неравномерным соотношением организаций и числом сотрудников, например, «5—5», «7—3», «6—4». Если вам важно распределить данные равномерно — например, в соотношении «1—9», чтобы первой партиции соответствовали данные для самой большой организации с наибольшим количеством сотрудников, а второй партиции — все остальные небольшие организации, создайте гораздо большее количество affinity-ключей, чем партиций в выборке. Для выравнивания распределения также можно использовать алгоритм RendezvousAffinityFunction, который, однако не обеспечивает полностью равномерного распределения: погрешность составляет ±5–10% между узлами.

Таймауты записи на клиентских узлах#

При данной проблеме при подключениях клиентских узлов и попытках записи на них TcpCommunicationSpi перестает работать по таймаутам:

021-11-17 17:23:40:275 [WARN ] [org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi] [grid-timeout-worker-#118%DPL_GRID%DplGridNodeName%] - Handshake timed out (will stop attempts to perform the handshake) [node=5b89fd66-11e5-4775-900a-64a1f2fb32f6, connTimeoutStrategy=ExponentialBackoffTimeoutStrategy [maxTimeout=600000, totalTimeout=30000, startNanos=1625306659621898, currTimeout=600000], err=Operation timed out [timeoutStrategy= ExponentialBackoffTimeoutStrategy [maxTimeout=600000, totalTimeout=30000, startNanos=1625306659621898, currTimeout=600000]], addr=/192.168.122.1:47100, failureDetectionTimeoutEnabled=true, timeout=0]

В логах сервера при данной проблеме присутствует множество попыток входящих соединений:

2021-11-17 17:24:29.141 [INFO ][grid-nio-worker-tcp-comm-10-#129%TcpCommunicationSpi%][org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi] Accepted incoming communication connection [locAddr=/192.168.122.1:47100, rmtAddr=/192.168.122.1:42776]

В целях диагностики обратите внимание:

  • на IP-адрес, по которому происходит time out handshake;

  • на IP-адрес, с которым запущен кластер.

Проблема появляется, когда при наличии нескольких интерфейсов TcpCommunicationSpi запускается на интерфейсе, отличном от того, на котором работает кластер:

2021-11-17 00:00:10.362 [INFO ][grid-timeout-worker-#118][org.apache.ignite.internal.IgniteKernal]
Metrics for local node (to disable set 'metricsLogFrequency' to 0)
    ^-- Node [id=7eace3d5, uptime=1 day, 05:29:46.136]
    ^-- Cluster [hosts=32, CPUs=1792, servers=32, clients=9, topVer=53, minorTopVer=0]
    ^-- Network [addrs=[10.127.119.237, 127.0.0.1, 192.168.122.1], discoPort=47500, commPort=47100]
    ^-- CPU [CPUs=56, curLoad=0.03%, avgLoad=0.05%, GC=0%]
    ^-- Heap [used=10953MB, free=65.49%, comm=31744MB]
    ^-- Off-heap memory [used=132MB, free=99.98%, allocated=592071MB]
    ^-- Page memory [pages=33435]
    ^--   sysMemPlc region [type=internal, persistence=true, lazyAlloc=false,
      ...  initCfg=40MB, maxCfg=100MB, usedRam=0MB, freeRam=99.99%, allocRam=99MB, allocTotal=0MB]
    ^--   default region [type=default, persistence=true, lazyAlloc=true,
      ...  initCfg=256MB, maxCfg=591872MB, usedRam=130MB, freeRam=99.98%, allocRam=591871MB, allocTotal=129MB]
    ^--   metastoreMemPlc region [type=internal, persistence=true, lazyAlloc=false,
      ...  initCfg=40MB, maxCfg=100MB, usedRam=2MB, freeRam=97.99%, allocRam=0MB, allocTotal=2MB]
    ^--   TxLog region [type=internal, persistence=true, lazyAlloc=false,
      ...  initCfg=40MB, maxCfg=100MB, usedRam=0MB, freeRam=100%, allocRam=99MB, allocTotal=0MB]
    ^--   volatileDsMemPlc region [type=user, persistence=false, lazyAlloc=true,
      ...  initCfg=40MB, maxCfg=100MB, usedRam=0MB, freeRam=100%, allocRam=0MB]
    ^-- Ignite persistence [used=131MB]
    ^-- Outbound messages queue [size=0]
    ^-- Public thread pool [active=0, idle=0, qSize=0]
    ^-- System thread pool [active=0, idle=7, qSize=0]

Для решения проблемы необходимо указать в bean TcpCommunicationSpi следующее свойство с локальным IP-адресом, на котором запущен кластер (TcpDiscoveryVmIpFinder):

<property name="localAddress" value="1.2.3.4"/>

Внимание

Данная опция включается автоматически в развертываниях через роль с версии v4.2110.1.

Проблемы с таймаутами подключения узлов#

Существуют два параметра (property), определяющих таймауты подключения, в течение которых происходит ожидание ответа от удаленного узла:

  • IgniteConfiguration.failureDetectionTimeout — таймаут для ожидания ответа от серверных узлов в процессе выполнения сетевых операций; значение таймаута по умолчанию составляет 10 000 мс;

  • IgniteConfiguration.clientFailureDetectionTimeout — таймаут для ожидания ответа от клиентских узлов в процессе выполнения сетевых операций; значение таймаута по умолчанию составляет 30 000 мс.

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

Значения таймаутов по умолчанию позволяют discovery SPI надежно работать в большинстве развертываний (on-premise and containerized deployments). Однако можно самостоятельно установить значение таймаута в конфигурации узла. Например, увеличение времени ожидания имеет смысл в кластере, где присутствуют длинные GC-паузы или медленная нестабильная сеть — это поможет справляться с более долгими паузами между ответами в рамках сессии, что, в свою очередь, позволит не исключать медленно отвечающий узел из топологии.

Пример XML-конфигурации:

    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="         http://www.springframework.org/schema/beans         http://www.springframework.org/schema/beans/spring-beans.xsd         http://www.springframework.org/schema/util         http://www.springframework.org/schema/util/spring-util.xsd">
        <bean class="org.apache.ignite.configuration.IgniteConfiguration">

            <property name="failureDetectionTimeout" value="5000"/>

            <property name="clientFailureDetectionTimeout" value="10000"/>

        </bean>
    </beans>

Увеличение времени проведения транзакций и LRT#

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

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

Диагностировать проблему можно по следующим признакам:

  • сработала метрика LRT Found long running transaction NEW в Grafana;

  • log-файл ignite.log содержит сообщения следующего вида:

    [2021-10-06 11:41:53,530][WARN ][sys-#206%client%][root] First 10 long running transactions [total=10]
    [2021-10-06 11:41:53,530][WARN ][sys-#206%client%][root] >>> Transaction [startTime=11:41:52.961, curTime=11:41:53.518, systemTime=0, userTime=557, tx=GridNearTxLocal [mappings=IgniteTxMappingsImpl [], nearLocallyMapped=false, colocatedLocallyMapped=false, needCheckBackup=null, hasRemoteLocks=false, trackTimeout=false, systemTime=0, systemStartTime=0, prepareStartTime=0, prepareTime=0, commitOrRollbackStartTime=0, commitOrRollbackTime=0, lb=null, mvccOp=null, qryId=-1, crdVer=0, thread=async-tx-with-delay-#240%testscope%, mappings=IgniteTxMappingsImpl [], super=GridDhtTxLocalAdapter [nearOnOriginatingNode=false, span=o.a.i.i.processors.tracing.NoopSpan@60d3a365, nearNodes=KeySetView [], dhtNodes=KeySetView [], explicitLock=false, super=IgniteTxLocalAdapter [completedBase=null, sndTransformedVals=false, depEnabled=false, txState=IgniteTxStateImpl [activeCacheIds=[], recovery=null, mvccEnabled=null, mvccCachingCacheIds=[], txMap=EmptySet []], super=IgniteTxAdapter [xidVer=GridCacheVersion [topVer=244989714, order=1633509712519, nodeOrder=3], writeVer=null, implicit=false, loc=true, threadId=264, startTime=1633509712961, nodeId=390487f0-99c2-4890-992c-c9c3ac93d505, isolation=REPEATABLE_READ, concurrency=PESSIMISTIC, timeout=0, sysInvalidate=false, sys=false, plc=2, commitVer=null, finalizing=NONE, invalidParts=null, state=ACTIVE, timedOut=false, topVer=AffinityTopologyVersion [topVer=-1, minorTopVer=0], mvccSnapshot=null, skipCompletedVers=false, parentTx=null, duration=557ms, onePhaseCommit=false], size=0]]]]
    ...
    

Для решения проблемы проанализируйте содержимое log-файла DataGrid, в котором присутствуют сообщения вида Found long running transaction NEW. Возможные причины увеличения длительности транзакции:

  • длительная работа прикладного кода. Об этой проблеме свидетельствует наличие транзакции в активном статусе: status=active;

  • неисправное состояние кластера, при котором транзакции перестали выполняться — например, при отказе дисков.

Обратите внимание: при первом сообщении о появлении LRT будет получен дамп потока, запустившего LRT на узле-координаторе транзакции. Часто такой узел является клиентским узлом, а следовательно, дамп потока тразакции также будет получен с клиентского узла. Дамп показывает тип выполняемой операции (бизнес-операция или взаимодействие с DataGrid). Следующие признаки, присутствующие в дампах транзакций, свидетельствуют о наличии задержек:

  • атрибуты TransactionProxyImpl.commit, TransactionProxyImpl.rollback, TransactionProxyImpl.prepare свидетельствуют о задержках работы сети или GC-задержках (очистка мусора);

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

Пример записи в log-файле:

2022-07-06 05:31:08.093 [WARN ][sys-#112111][org.apache.ignite.internal.diagnostic] Dumping the near node thread that started transaction [xidVer=GridCacheVersion [topVer=267985566, order=1658822904791, nodeOrder=29, dataCenterId=0], nodeId=b1076c6d-e26d-44ff-bd30-af41845a42ed]
Stack trace of the transaction owner thread:
Thread [name="se-53", id=1353, state=WAITING, blockCnt=1, waitCnt=1788]
Lock [object=java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@a19d495, ownerName=null, ownerId=-1]
at sun.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:403)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

LRT-транзакции часто возникают в результате следующих причин:

  • повышенной загрузки узлов кластера;

  • наличия сетевых проблем, приводящих к деградации вычислений;

  • системных проблем: длительные GC-паузы на узлах, неоптимальный код, падение узлов кластера.

Чтобы настроить время срабатывания для вывода сообщений о наличии LTR-транзакций, воспользуйтесь JVM-опцией IGNITE_LONG_OPERATIONS_DUMP_TIMEOUT. По умолчанию время вывода сообщений — 1 секунда.

Чтобы установить максимальное время, разрешенное для длительных транзакций, используйте метод TransactionConfiguration.setTxTimeoutOnPartitionMapExchange(...). После срабатывания таймаута происходит откат всех незавершенных транзакций, после чего продолжается процесс обмена данными в кластере.

Пример xml-файла для конфигурации времени таймаута:

<bean class="org.apache.ignite.configuration.IgniteConfiguration">

    <property name="transactionConfiguration">
        <bean class="org.apache.ignite.configuration.TransactionConfiguration">
            <!--Установите таймаут на 20 секунд.-->
            <property name="TxTimeoutOnPartitionMapExchange" value="20000"/>
        </bean>
    </property>

</bean>

Чек-лист вопросов для анализа LRT-транзакций:

  • в чем причина возникновения LRT;

  • какой способ возможен для восстановления LRT — автоматически или вручную;

  • что необходимо сделать, чтобы снизить вероятность повторения сбоя в дальнейшем;

  • как повлияла LRT-транзакция на grid-данные и дальнейшую работу.

Долгий PME#

PME (partition map exchange) — процесс обмена информацией о партициях между узлами кластера. Цель - установить актуальное состояние партиций для всех узлов кластера.

От чего зависит: длительность PME зависит от количества партиций, от длины транзакций.

Пороговые значения: комфортная длительность PME для клиентов составляет меньше 1 секунды. Для PME нужно дождаться окончания всех транзакций и не запускать новые, поэтому при общей комфортной длительности нагрузки при запуске PME в 60 сек сама длительность PME должна составлять меньше 1 секунды. Чем меньше длительность PME, тем лучше.

Начиная с версии 2.8 функция IGNITE_PME_FREE_SWITCH_DISABLED стала деактивируемой.

К симптомам относится срабатывание метрик по LRT, например, Found Long Running Transactions NEW.

Симптомы вызваны следующими проблемами:

  • создание транзакций без таймаутов или с большими таймаутами;

  • наличие дефектов.

Есть вероятность, что транзакция никогда не будет завершена. Например, если пользователь запустил pessimistic транзакции и выполнил cache put, вызывающий блокировку и настройку версии топологии транзакций. Для этого случая вводится timeout транзакции на PME. Если транзакция не может быть завершена в рамках timeout, указанного транзакцией, она будет принудительно выполнена во время выпуска партиций.

Установите время в setTxTimeoutOnPartitionMapExchange(long txTimeoutOnPartitionMapExchange) — устанавливает временное ограничение на PME в партициях при выполнении транзакции. Если оно будет превышено, выполнение транзакции будет прервано.

Реакция на долгие PME: чаще всего причина в зависшей транзакции либо в результате дефектов. Если дело в транзакции, то возможно, что разработка не поставила таймаут на длительность выполнения транзакции. Следовательно, нужно найти транзакцию и прервать ее.

Поломка h2-индексов#

При данной проблеме узлы завершают работу с ошибками вида Critical system error detected. Will be handled accordingly to configured handler. Поломка индексов выявляется в результате выполнения команды control.sh --cache validate_indexes <optional arguments>. Подробнее об индексах читайте в разделе «Управление индексами» документа «Руководство по системному администрированию».

Пример сообщения об ошибке:

2021-11-22 17:33:43.466 [ERROR][sys-stripe-9-#10][] Critical system error detected. Will be handled accordingly to configured handler [hnd=StopNodeOrHaltFailureHandler [tryStop=false, timeout=0, super=AbstractFailureHandler [ignoredFailureTy
pes=UnmodifiableSet [SYSTEM_WORKER_BLOCKED, SYSTEM_CRITICAL_OPERATION_TIMEOUT]]], failureCtx=FailureContext [type=CRITICAL_ERROR, err=class o.a.i.i.processors.cache.persistence.tree.CorruptedTreeException: B+Tree is corrupted [pages(groupId,
pageId)=[IgniteBiTuple [val1=544320549, val2=844420635174666]], cacheId=-227153373, cacheName=APPLY_ERROR_V1, indexName=_key_PK, msg=Runtime failure on row: Row@4118366a[ key: BinaryObject [idHash=974233043, hash=1604362618], val: Data hidd
en due to IGNITE_TO_STRING_INCLUDE_SENSITIVE flag. ][ data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden ]]]]
org.apache.ignite.internal.processors.cache.persistence.tree.CorruptedTreeException: B+Tree is corrupted [pages(groupId, pageId)=[IgniteBiTuple [val1=544320549, val2=844420635174666]], cacheId=-227153373, cacheName=APPLY_ERROR_V1, indexName=
_key_PK, msg=Runtime failure on row: Row@4118366a[ key: BinaryObject [idHash=974233043, hash=1604362618], val: Data hidden due to IGNITE_TO_STRING_INCLUDE_SENSITIVE flag. ][ data hidden, data hidden, data hidden, data hidden, data hidden, da
ta hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden, data hidden ]]

Поломка h2-индексов — дефект, о котором необходимо сообщить в службу поддержки DataGrid и передать фактуру для анализа: log-файлы DataGrid, хронологию событий, PDS (достаточно index.bin).

В качестве временного решения проблемы перестройте индексы:

  1. Остановите проблемные узлы.

  2. Удалите проблемный файл index.bin.

  3. Запустите узлы.

  4. Выполните процесс перестройки всех индексов с помощью команды control.sh --cache indexes_force_rebuild --node-ids nodeId1,...nodeIdN|--all-nodes --cache-names cacheName1,...cacheNameN|--group-names groupName1,...groupNameN.

  5. Дождитесь завершения процесса перестроения индексов.

Переполнение региона данных (data region)#

Регион данных (data region) — логическая расширяемая область в RAM, где находятся кешированные данные. Пользователи могут настраивать начальный и максимальный размер автоматически создаваемого региона данных, создавать дополнительные регионы данных, а также контролировать persistence-параметры для кеша.

По умолчанию при старте DataGrid создается один регион данных с автоматически заданными начальным и максимальным размерами. Начальный размер составляет 256 Mб, максимальный — 20% от доступной узлу RAM. Все создаваемые пользователем кеши хранятся в этом регионе данных. Пользователи могут настраивать начальный и максимальный размеры автоматически создаваемого региона данных по своему усмотрению.

Помимо автоматически создаваемого, пользователи могут добавлять дополнительные регионы данных. Размеры регионов данных либо задаются пользователем в конфигурации, либо устанавливаются автоматически. При автоматической установке максимальный размер региона данных также будет выставлен в пределах от 256 Mб до 20% от доступной оперативной памяти. При ручной установке настройки региона данных необходимо задать до старта узла; эти настройки нельзя будет изменить динамически, без остановки узла. Заполнение памяти для регионов данных отображается в log-файлах каждого узла.

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

Количество дополнительных регионов данных не ограничено; главное — не превышать размер доступной оперативной памяти. Расчет размера регионов данных должен определяться исходя из размера доступной памяти на серверном узле. В случае переполнения доступной памяти узел будет аварийно остановлен.

Ситуации, в которых оправданно добавление дополнительных регионов данных:

  • для настройки объема памяти, доступной для одного кеша, или для группы кешей, использующих один регион данных;

  • для конфигурирования способа хранения данных — только в памяти (in-memory), или и в памяти, и на диске (persistence). Способ хранения конфигурируется на уровне настроек региона данных, следовательно, этот способ является единым для всех кешей, использующих один регион данных; в этом случае настройте два или более региона данных с разными persistence-параметрами: один для кешей в памяти, другой — для persistence-кешей. По умолчанию данные кешей не записываются на диск и хранятся только в оперативной памяти;

  • для настройки политики хранения данных, например, политики вытеснения данных (eviction policy). Политики хранения памяти настраиваются отдельно для каждого региона данных.

В случае переполнения и/или недостаточного размера региона данных появляется сообщение в Zabbix и Grafana: IgniteOutOfMemoryException: Out of memory in data region.

Для решения проблемы:

  • увеличьте DataRegionConfiguration.maxSize;

  • включите режим Native Persistence (подробнее см. в разделе «Включение Persistence-хранилища данных» документа «Руководство по системному администрированию»). При включении Native Persistence данные, которые больше не помещаются в регион данных, вытесняются из оперативной памяти на диск. В этом случае операции чтения и записи занимают больше времени, однако объем памяти больше не ограничивается размером региона данных. Также включенный режим Native Persistence позволяет восстановить данные из кеша после перезапуска кластера;

  • установите значение атрибута DataRegionConfiguration.pageEvictionMode=RANDOM_2_LRU. Важно: включение eviction policy — аварийный механизм сохранения данных. При работе eviction policy данные могут вытесняться из оперативной памяти неконсистентно, что потенциально приводит к расхождениям по узлам. В случае систематического переполнения региона данных и запуска eviction policy рекомендуется увеличить объем региона данных или включить режим Native Persistence;

  • используйте политику истечения срока действия.

Подключение другой версии клиента#

Симптом проблемы – сообщение в log-файлах о том, что клиент не подключается.

При возникновении проблемы с толстым клиентом обратитесь к группе разработки.

При использовании тонкого клиента проблемы с подключением возникают только при наличии дефектов. Чтобы передать фактуру для анализа в группу разработки, соберите следующие метрики:

  • название affinity-функции, при использовании которой возникают ошибки, и параметры функции;

  • распределение партиций (primary, backup) по узлам;

  • распределение ключей по партициям.

Неравномерная загрузка узлов#

Некорректное распределение данных и ошибки кода могут приводить к скоплению запросов на одном узле. Из-за этого возникает неравномерная загрузка остальных узлов:

  • на уровне аппаратных и/или физических ресурсов, к которым относятся CPU, SSD, RAM, LAN, аппаратные ресурсы узлов кластера;

  • на уровне неаппаратных ресурсов, к которым относятся системные потоки кластера (thread pools), все виды памяти в ОС, партиции и т.д.

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

Мониторинг симптомов возможен с помощью сбора фактуры ignite.log, метрик DataGrid, метрик ОС.

Возможные причины проблемы:

  • некорректная конфигурация, например, указан только один IP-адрес;

  • ошибки в коде, из-за чего данные и запросы направляются на один узел.

Для решения проблемы установите причину концентрации данных. Если причина в некорректной конфигурации, настройте ее. Если проблема в коде, найдите ошибки, чтобы решить проблему с ключами, разнесением данных по узлам и по партициям.

Неравномерное распределение данных#

DataGrid: равномерное распределение данных по партициями и по узлам, минимизация трафика при балансировке (изменениях в топологии).

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

Одним из симптомов является снижение показателей производительности CheckPoint Pages & Time.

Чтобы определить причину неравномерного распределения данных, необходимо ответить на следующие вопросы:

  • какая affinity функция используется, какие у нее параметры?

  • как распределились партиции (primary, backup) по узлам?

  • как распределяется ключи по партициям?

Сколько партиций держать на одном узле кластера?

Если мы используем persistence, то стоит ориентироваться на примерный объем кластера (Гб)/количество партиций, чтобы, примерно, в одной партиции был 1 Гб, дальше affinity функция это примерно равномерно распределит. Если говорим о Partition per node, 2-4 партиции на узел кластера, так как если одна партиция на узел, то есть риск неравномерного распределения данных. Несколько партиций на узел должно быть на случай ребалансировки в случае большого кластера.

Как количество партиций влияет на ребаланс?

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

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

Внимание

Никакие два узла не должны иметь одинаковые токены.

Два популярных способа решения проблемы распределения данных:

  • консистентное хеширование (consistent hashing);

  • алгоритм наибольшего случайного веса (HRW), также известный как Rendezvous hashing.

Замедление бизнес-операций#

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

Источник проблемы может разниться от неверно настроенного уровня логирования до проблем на аппаратном уровне.

Полный анализ всей фактуры подскажет конкретные проблемы, по которым стоит искать решение.

Медленная работа диска#

Проблемы с производительностью и медленной работой диска могут быть диагностированы по увеличению длительности контрольной точки и появлению checkpoints spikes на графике. Вероятная причина проблемы — в том, что пропускная способность памяти и диска не сбалансированы.

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

Если метрика не коррелирует с длительностью контрольной точки, проанализируйте содержимое ignite, dmesg, messages — возможно, диск утилизирован или возникла проблема на уровне ОС или железа. Для решения проблемы передайте в службу поддержки DataGrid содержимое файлов ignite, dmesg, messages для анализа.

Решение может разниться и зависит от результатов, полученных от изучения log-файла DataGrid на наличие сообщений уровня ERROR, WARN.

Взаимоблокировка (deadlock)#

Взаимоблокировку можно заметить по замедлению бизнес-операций, завершению транзакций сообщениями вида:

  1. На серверных узлах:

    [ERROR][grid-timeout-worker-#118][org.apache.ignite.internal.processors.cache.distributed.dht.colocated.GridDhtColocatedCache] <tw.transactions> Failed to acquire lock for request: GridNearLockRequest [topVer=AffinityTopologyVersion [topVer=418, minorTopVer=0], miniId=1, dhtVers=GridCacheVersion[] [null], subjId=088f0b3b-8b8c-4d41-ab0c-73cd0d5af2f8, taskNameHash=0, createTtl=-1, accessTtl=-1, flags=5, txLbl=null, filter=null, super=GridDistributedLockRequest [nodeId=088f0b3b-8b8c-4d41-ab0c-73cd0d5af2f8, nearXidVer=GridCacheVersion [topVer=245981357, order=1637825079145, nodeOrder=400], threadId=8689, futId=334a5c5cc71-0864976c-edcc-4d9e-bb9a-92b2b91a2bd2, timeout=30000, isInTx=true, isInvalidate=false, isRead=true, isolation=REPEATABLE_READ, retVals=[true], txSize=0, flags=2, keysCnt=1, super=GridDistributedBaseMessage [ver=GridCacheVersion [topVer=245981357, order=1637825079145, nodeOrder=400], committedVers=null, rolledbackVers=null, cnt=0, super=GridCacheIdMessage [cacheId=92902112, super=GridCacheMessage [msgId=155993, depInfo=null, lastAffChangedTopVer=AffinityTopologyVersion [topVer=24, minorTopVer=71], err=null, skipPrepare=false]]]]]
    org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException: Failed to acquire lock within provided timeout for transaction [timeout=30000, tx=GridDhtTxLocal[xid=8776bf55d71-00000000-0ea9-60ad-0000-000000000004, xidVersion=GridCacheVersion [topVer=245981357, order=1637825079160, nodeOrder=4], nearXidVersion=GridCacheVersion [topVer=245981357, order=1637825079145, nodeOrder=400], concurrency=PESSIMISTIC, isolation=REPEATABLE_READ, state=MARKED_ROLLBACK, invalidate=false, rollbackOnly=true, nodeId=63a1650c-7291-44be-a5b7-3be796c4ad6f, timeout=30000, startTime=1635424056538, duration=30007]]
    at org.apache.ignite.internal.processors.cache.transactions.IgniteTxLocalAdapter$PostLockClosure1.apply(IgniteTxLocalAdapter.java:1798) ~[ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.processors.cache.transactions.IgniteTxLocalAdapter$PostLockClosure1.apply(IgniteTxLocalAdapter.java:1746) ~[ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.util.future.GridEmbeddedFuture$2.applyx(GridEmbeddedFuture.java:86) ~[ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.util.future.GridEmbeddedFuture$AsyncListener1.apply(GridEmbeddedFuture.java:292) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.util.future.GridEmbeddedFuture$AsyncListener1.apply(GridEmbeddedFuture.java:285) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.util.future.GridFutureAdapter.notifyListener(GridFutureAdapter.java:399) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.util.future.GridFutureAdapter.unblock(GridFutureAdapter.java:347) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.util.future.GridFutureAdapter.unblockAll(GridFutureAdapter.java:335) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.util.future.GridFutureAdapter.onDone(GridFutureAdapter.java:511) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.processors.cache.GridCacheCompoundIdentityFuture.onDone(GridCacheCompoundIdentityFuture.java:56) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.util.future.GridFutureAdapter.onDone(GridFutureAdapter.java:490) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtLockFuture.onComplete(GridDhtLockFuture.java:802) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtLockFuture.access$900(GridDhtLockFuture.java:93) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtLockFuture$LockTimeoutObject.onTimeout(GridDhtLockFuture.java:1202) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor$TimeoutWorker.body(GridTimeoutProcessor.java:234) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:120) [ignite-core-2.10.0-p1.jar:2.10.0-p1]
    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_301]
    
  2. На инициаторе транзакции:

    Caused by: javax.cache.CacheException: class org.apache.ignite.transactions.TransactionTimeoutException: Failed to acquire lock within provided timeout for transaction [timeout=30000, tx=GridNearTxLocal[xid=f3c4b265d71-00000000-0ea9-60ad-0000-00000000019a, xidVersion=GridCacheVersion [topVer=245981357, order=1637828217919, nodeOrder=410], nearXidVersion=GridCacheVersion [topVer=245981357, order=1637828217919, nodeOrder=410], concurrency=PESSIMISTIC, isolation=REPEATABLE_READ, state=MARKED_ROLLBACK, invalidate=false, rollbackOnly=true, nodeId=68ca22f4-38be-4027-8c81-94b0ea81559e, timeout=30000, startTime=1635430164207, duration=30016, label=null]]
       at org.apache.ignite.internal.processors.cache.GridCacheUtils.convertToCacheException(GridCacheUtils.java:1263)
       at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.cacheException(IgniteCacheProxyImpl.java:2083)
       at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.get(IgniteCacheProxyImpl.java:1110)
       at org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.get(GatewayProtectedCacheProxy.java:676)
       at com.sbt.processing.data.ignite.IgniteWriter.writeIdentifiableInternal(IgniteWriter.java:95)
       at com.sbt.processing.data.ignite.IgniteWriter.appendIdentifiable(IgniteWriter.java:74)
       ... 17 more
       Caused by: class org.apache.ignite.transactions.TransactionTimeoutException: Failed to acquire lock within provided timeout for transaction [timeout=30000, tx=GridNearTxLocal[xid=f3c4b265d71-00000000-0ea9-60ad-0000-00000000019a, xidVersion=GridCacheVersion [topVer=245981357, order=1637828217919, nodeOrder=410], nearXidVersion=GridCacheVersion [topVer=245981357, order=1637828217919, nodeOrder=410], concurrency=PESSIMISTIC, isolation=REPEATABLE_READ, state=MARKED_ROLLBACK, invalidate=false, rollbackOnly=true, nodeId=68ca22f4-38be-4027-8c81-94b0ea81559e, timeout=30000, startTime=1635430164207, duration=30016, label=null]]
       at org.apache.ignite.internal.util.IgniteUtils$13.apply(IgniteUtils.java:987)
       at org.apache.ignite.internal.util.IgniteUtils$13.apply(IgniteUtils.java:984)
       ... 23 more
       Caused by: class org.apache.ignite.transactions.TransactionDeadlockException:
       Deadlock detected:
    K1: TX1 holds lock, TX2 waits lock.
    K2: TX2 holds lock, TX1 waits lock.
    Transactions:
    TX1 [txId=GridCacheVersion [topVer=245981357, order=1637828217886, nodeOrder=418], nodeId=1d0a56c0-cc47-4369-b9c5-c5fe1fffe7bf, threadId=1176]
    TX2 [txId=GridCacheVersion [topVer=245981357, order=1637828217919, nodeOrder=410], nodeId=68ca22f4-38be-4027-8c81-94b0ea81559e, threadId=12957]
    Keys:
    K1 [key=d6oDXoRGCvEAAAF8x+CxoMaIDaIpVm6K, cache=tw.transactions_bundle]
    K2 [key=d6oDXoRGCvEAAAF8x+CxoMaIDaIpVm6K, cache=tw.transactions]
        at org.apache.ignite.internal.processors.cache.distributed.dht.colocated.GridDhtColocatedLockFuture$LockTimeoutObject$1.apply(GridDhtColocatedLockFuture.java:1539)
        at org.apache.ignite.internal.processors.cache.distributed.dht.colocated.GridDhtColocatedLockFuture$LockTimeoutObject$1.apply(GridDhtColocatedLockFuture.java:1532)
        at org.apache.ignite.internal.util.future.GridFutureAdapter.notifyListener(GridFutureAdapter.java:399)
        at org.apache.ignite.internal.util.future.GridFutureAdapter.unblock(GridFutureAdapter.java:347)
        at org.apache.ignite.internal.util.future.GridFutureAdapter.unblockAll(GridFutureAdapter.java:335)
        at org.apache.ignite.internal.util.future.GridFutureAdapter.onDone(GridFutureAdapter.java:511)
        at org.apache.ignite.internal.util.future.GridFutureAdapter.onDone(GridFutureAdapter.java:490)
        at org.apache.ignite.internal.processors.cache.transactions.TxDeadlockDetection$TxDeadlockFuture.onDone(TxDeadlockDetection.java:538)
        at org.apache.ignite.internal.processors.cache.transactions.TxDeadlockDetection$TxDeadlockFuture.onDone(TxDeadlockDetection.java:163)
        at org.apache.ignite.internal.util.future.GridFutureAdapter.onDone(GridFutureAdapter.java:467)
        at org.apache.ignite.internal.processors.cache.transactions.TxDeadlockDetection$TxDeadlockFuture.detect(TxDeadlockDetection.java:314)
        at org.apache.ignite.internal.processors.cache.transactions.TxDeadlockDetection$TxDeadlockFuture.onResult(TxDeadlockDetection.java:514)
        at org.apache.ignite.internal.processors.cache.transactions.IgniteTxManager$DeadlockDetectionListener.onMessage(IgniteTxManager.java:3593)
        at org.apache.ignite.internal.managers.communication.GridIoManager.invokeListener(GridIoManager.java:1908)
        at org.apache.ignite.internal.managers.communication.GridIoManager.processRegularMessage0(GridIoManager.java:1529)
        at org.apache.ignite.internal.managers.communication.GridIoManager.access$5300(GridIoManager.java:242)
        at org.apache.ignite.internal.managers.communication.GridIoManager$9.execute(GridIoManager.java:1422)
        at org.apache.ignite.internal.managers.communication.TraceRunnable.run(TraceRunnable.java:55)
        at org.apache.ignite.internal.util.StripedExecutor$Stripe.body(StripedExecutor.java:569)
        at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:120)
        ... 1 more
    

По сообщению на инициаторе транзакции определяем, на каком ключе произошла взаимоблокировка:

K1 [key=d6oDXoRGCvEAAAF8x+CxoMaIDaIpVm6K, cache=tw.transactions_bundle]
K2 [key=d6oDXoRGCvEAAAF8x+CxoMaIDaIpVm6K, cache=tw.transactions]

Как правило, данную информацию необходимо передать прикладным разработчикам на анализ, чтобы они смогли определить причины возникновения взаимной блокировки в коде. Если добавлен параметр -DIGNITE_TO_STRING_INCLUDE_SENSITIVE=false, значение ключей не будет попадать в лог и по сообщениям не удастся узнать, по каким ключам произошла взаимоблокировка.

K1 [key=, cache=tw.transactions_bundle]
K2 [key=, cache=tw.transactions]

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

Инициатор обнаружения тупиков — это узел, в котором транзакция началась, но была прервана с TransactionTimeOutException. Этот узел будет исследовать, произошел ли тупик, обмениваясь запросами/ответами с другими удаленными узлами, а затем он подготовит отчет о deadlock с помощью TransactionDeadlockException. Каждое такое сообщение (запрос/ответ) и есть итерация.

Для предсказуемого времени отката транзакции стоит настроить максимальное количество итераций для процедуры обнаружения deadlock - Ignitesystemproperties.ignite_tx_deadlock_detection_max_iters - при значении свойства 0 и меньше deadlock detection будет отключен (по умолчанию равен 1000). Ignitesystemproperties.ignite_tx_deadlock_detection_timeout указывает время ожидания для обнаружения deadlock (по умолчанию 1 мин).

Расхождение партиций#

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

  • counter — счетчик изменения партиций;

  • размер — количество записей;

  • хеш-сумма — результат обработки данных, находящихся в партиции, хеш-функцией.

Расхождения в партициях могут возникать в результате дефектов при работе с транзакционными кешами.

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

Данная проблема имеет следующие симптомы:

  • значения метрик;

  • сообщения в логах;

  • запуск idle_verify.

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

Наличие расхождений можно установить и по косвенным признакам.

Косвенные симптомы: данные периодически не находятся по ключу, либо находятся не те данные, либо данные отсутствуют. Запрос уходит на один узел и выполняется корректно, а при запросе на другой ничего не возвращает.

В целях диагностики запустите диагностическую утилиту idle-verify при помощи следующей команды:

--cache idle_verify [--dump] [--skip-zeros] [--check-crc] [--exclude-caches cacheName1,...,cacheNameN] [--cache-filter DEFAULT|SYSTEM|PERSISTENT|NOT_PERSISTENT|USER|ALL] [cacheName1,...,cacheNameN]

где:

  • --dump — перенаправление вывода результата работы в файл по пути $IGNITE_HOME/work/, формат имени файла idle-dump-YYYY-MM-DDTHH24-MI-SS_sss.txt;

  • --skip-zeros — пропуск партиций, в которых нет записей;

  • --check-crc — проверка crc-страниц;

  • --exclude-caches cacheName1,...,cacheNameN — исключение кешей, по которым не нужно искать расхождения;

  • --cache-filter DEFAULT|SYSTEM|PERSISTENT|NOT_PERSISTENT|USER|ALL — тип кешей, по которым нужно искать расхождения:

    • DEFAULT — пользовательские кеши или все кеши, которые явно указаны;

    • SYSTEM — системные кеши;

    • PERSISTENT — персистируемые кеши;

    • NOT_PERSISTENT — неперсистируемые кеши;

    • USER — пользовательские кеши — все кеши, за исключением системных кешей;

    • ALL — все кеши, независимо от типа и места хранения их данных.

  • cacheName1,...,cacheNameN — имена кешей, в которых нужно искать расхождения.

Утилита может отработать с двумя результатами:

  • отсутствие расхождений:

      The check procedure has finished, no conflicts have been found.
    
  • наличие расхождений:

    idle_verify task was executed with the following args: caches=[], excluded=[], cacheFilter=[DEFAULT] # Аргументы, с которыми запущен idle_verify
    idle_verify check has finished, found 3 conflict partitions: [counterConflicts=0, hashConflicts=148] # Количество конфликтов (в данном примере 3), с разбивкой по типам counterConflicts и hashConflicts.
    Hash conflicts: # Все, что идет ниже, относится к расхождениям по хешу.
    
    Conflict partition: PartitionKeyV2 [grpId=1095989593, grpName=card-stream-linker-service-cache-prom, partId=851] # Сообщение указывает на то, в какой партиции (partId=851) и какой кеш-группе (grpId=1095989593, grpName=card-stream-linker-service-cache-prom) выявлены расхождения
    Partition instances: [
    PartitionHashRecordV2 [isPrimary=false, consistentId=93dce233-c0b2-4b3c-8562-28d621a69954, updateCntr=20600, partitionState=OWNING, size=17, partHash=318600276],
    PartitionHashRecordV2 [isPrimary=true, consistentId=158db893-e309-407e-9cb5-32d14ade1748, updateCntr=20600, partitionState=OWNING, size=16, partHash=-119291370]]
    
    Conflict partition: PartitionKeyV2 [grpId=1095989593, grpName=card-stream-linker-service-cache-prom, partId=286]
    Partition instances: [
    PartitionHashRecordV2 [isPrimary=false, consistentId=93dce233-c0b2-4b3c-8562-28d621a69954, updateCntr=20541, partitionState=OWNING, size=22, partHash=623413003],
    PartitionHashRecordV2 [isPrimary=true, consistentId=158db893-e309-407e-9cb5-32d14ade1748, updateCntr=20541, partitionState=OWNING, size=21, partHash=845648234],
    PartitionHashRecordV2 [isPrimary=false, consistentId=e6775c04-5c1d-416c-831c-ff5b37d23985, updateCntr=20541, partitionState=OWNING, size=21, partHash=845648234]]
    
    Conflict partition: PartitionKeyV2 [grpId=1095989593, grpName=card-stream-linker-service-cache-prom, partId=285]
    Partition instances: [
    PartitionHashRecordV2 [isPrimary=false, consistentId=93dce233-c0b2-4b3c-8562-28d621a69954, updateCntr=20599, partitionState=OWNING, size=25, partHash=481674619],
    PartitionHashRecordV2 [isPrimary=false, consistentId=158db893-e309-407e-9cb5-32d14ade1748, updateCntr=20599, partitionState=OWNING, size=24, partHash=1206168917],
    PartitionHashRecordV2 [isPrimary=true, consistentId=e6775c04-5c1d-416c-831c-ff5b37d23985, updateCntr=20599, partitionState=OWNING, size=24, partHash=1206168917]]
    

Полуавтоматическое выравнивание

Подробная информация указана в разделе «Восстановление согласованности партиций с помощью cli-утилит» документа «Руководство по системному администированию» и в разделе «Механизм Read repair» документа «Руководство прикладного разработчика».

В качестве решения используйте механизм полуавтоматического выравнивания (Read repair). Данный механизм позволяет производить контролируемое устранение расхождений партиций с применением разнообразных стратегий (LWW, PRIMARY, MAJORITY, REMOVE, REMOVE, CHECK_ONLY): Раздел «Механизм Read repair» документа «Руководство прикладного разработчика».

Развал кластера#

Проанализировать содержимое фактуры ignite, GC.

Кейс 1 java.lang.OutOfMemoryError: Direct buffer memory

В ignite.log:

2021-08-20 22:22:59.544 [ERROR][client-connector-#408][] Critical system error detected. Will be handled accordingly to configured handler [hnd=StopNodeOrHaltFailureHandler [tryStop=false, timeout=0, super=AbstractFailureHandler [ignoredFailureTypes=UnmodifiableSet [SYSTEM_WORKER_BLOCKED, SYSTEM_CRITICAL_OPERATION_TIMEOUT]]], failureCtx=FailureContext [type=CRITICAL_ERROR, err=java.lang.OutOfMemoryError: Direct buffer memory]]
java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:175) ~[?:?]
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:118) ~[?:?]
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:317) ~[?:?]
at org.apache.ignite.internal.util.nio.ssl.GridNioSslHandler.expandBuffer(GridNioSslHandler.java:642) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.ssl.GridNioSslHandler.encrypt(GridNioSslHandler.java:360) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.ssl.GridNioSslFilter.onSessionWrite(GridNioSslFilter.java:310) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioFilterAdapter.proceedSessionWrite(GridNioFilterAdapter.java:121) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioCodecFilter.onSessionWrite(GridNioCodecFilter.java:96) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioFilterAdapter.proceedSessionWrite(GridNioFilterAdapter.java:121) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioAsyncNotifyFilter.onSessionWrite(GridNioAsyncNotifyFilter.java:119) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioFilterAdapter.proceedSessionWrite(GridNioFilterAdapter.java:121) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioFilterChain$TailFilter.onSessionWrite(GridNioFilterChain.java:269) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioFilterChain.onSessionWrite(GridNioFilterChain.java:192) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioSessionImpl.send(GridNioSessionImpl.java:117) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.processors.odbc.ClientListenerNioListener.onMessage(ClientListenerNioListener.java:219) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at java.nio.Bits.reserveMemory(Bitsorg.apache.ignite.internal.processors.odbc.ClientListenerNioListener.onMessage(ClientListenerNioListener.java:17556) ~[?:?ignite-core-2.9.0-p8.jar:2.9.0-p8]
at javaorg.apache.ignite.internal.util.nio.DirectByteBufferGridNioFilterChain$TailFilter.<init>onMessageReceived(DirectByteBufferGridNioFilterChain.java:118279) ~[?:?ignite-core-2.9.0-p8.jar:2.9.0-p8]
at javaorg.apache.ignite.internal.util.nio.ByteBufferGridNioFilterAdapter.allocateDirectproceedMessageReceived(ByteBufferGridNioFilterAdapter.java:317109) ~[?:?ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.sslGridNioAsyncNotifyFilter$3.GridNioSslHandler.expandBufferbody(GridNioSslHandlerGridNioAsyncNotifyFilter.java:64297) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nioworker.sslGridWorker.GridNioSslHandler.encryptrun(GridNioSslHandlerGridWorker.java:360120) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nioworker.sslGridWorkerPool$1.GridNioSslFilter.onSessionWriterun(GridNioSslFilterGridWorkerPool.java:31070) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioFilterAdapter.proceedSessionWrite(GridNioFilterAdapter.java:121) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioCodecFilter.onSessionWrite(GridNioCodecFilter.java:96) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioFilterAdapter.proceedSessionWrite(GridNioFilterAdapter.java:121) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioAsyncNotifyFilter.onSessionWrite(GridNioAsyncNotifyFilter.java:119) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioFilterAdapter.proceedSessionWrite(GridNioFilterAdapter.java:121) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.nio.GridNioFilterChain$TailFilter.onSessionWrite(GridNioFilterChain.java:269) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
at java.lang.Thread.run(Thread.java:829) [?:?]
2021-08-20 22:22:59.558 [ERROR][client-connector-#408][] JVM will be halted immediately due to the failure: [failureCtx=FailureContext [type=CRITICAL_ERROR, err=java.lang.OutOfMemoryError: Direct buffer memory]]

Кейс 2 Пример из IPv4 и IPv6

Убрать из JVM-опций -XX:+DisableExplicitGC, -XX:MaxDirectMemorySize. Если репортер будет против, то запросить аргументы в пользу того, чтобы их оставить, и завести тикет на L3 с описанием предоставленных аргументов. Смотреть решение из проблемы про IPv4 и IPv6 выше.

Решение сетевых проблем с помощью checkRingLatency#

В случае, если вы подозреваете возможные сетевые проблемы, воспользуйтесь механизмом проверки checkRingLatency. Выполнение этой JMX-операции показывает задержки в передаче данных на узлах кластера.

Чтобы обнаружить возможную сетевую проблему, проведите тест:

  1. Подключитесь к любому хосту с помощью JMX.

  2. Перейдите в раздел Operations на вкладке слева:

    JMX_Operations

  3. Укажите число hops (количество отправок тестовых сообщений от одного узла к другому) в поле maxHops. В случае, если размер кластера составляет N серверных узлов, сообщение вернется на первый хост при значении maxHops, равном N.

  4. Нажмите checkRingLatency.

После этого на подключенном хосте сгенерируется сообщение, которое будет отправлено по механизму Discovery.

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

Название сообщения

Описание статуса

Latency check message has been read

Тестовое сообщение прочитано из сокета

Latency check processing

Тестовое сообщение обрабатывается

Latency check message has been written to socket

Тестовое сообщение записано в сокет

Latency check message has been acked

Тестовое сообщение получено следующим по кольцу узлом

После окончания теста соберите log-файлы со всех узлов и сравните значения TimeStamps, которые показывают точное время появления сообщения. В случае обнаружения более долгих ответов от одного или нескольких узлов проверьте наличие возможных ошибок в log-файле и работу сборщика мусора (Garbage Collector, GC). Если ошибок в файлах и сбоев в работе GC нет, обратитесь к сетевым инженерам.

Не запускается узел#

Установление причин осуществляется через анализ логов. Рекомендована следующая последовательность анализа:

  1. Просмотрите содержимое ignite.log — в логе будет присутствовать сообщение о причине прерывания запуска. Если лог пустой или обрывается без сообщения об ошибке, перейдите к следующему пункту.

  2. Проверьте содержимое err.out, может присутствовать сообщение об ошибке.

  3. Проверьте gc.log и узнайте, стартовала ли JVM. Проверьте на crush dump.

  4. Изучите dmesg, messages.

Причина 1 (КУ)

В ignite.log на КУ присутствует сообщение:

10.06.2021 15:36:44,654 INFO  [stdout] (ServerService Thread Pool – 105) Caused by: org.apache.ignite.spi.IgniteSpiException: Unable to establish secure connection. Was remote cluster configured with SSL? [rmtAddr=/10.107.33.137:47500, errMsg="Received fatal alert: handshake_failure"]

Необходимо убедиться в том, что в xml конфигурации:

<property name="protocols" value="#{systemProperties['https.protocols']}" />

На КУ и на СУ установлено одно и то же значение.

Причина 2 (СУ)

В ignite.log присутствует сообщение:

2021-07-02 15:35:07.381 [ERROR][main][org.apache.ignite.internal.IgniteKernal] Got exception while starting (will rollback startup routine).
org.apache.ignite.IgniteCheckedException: Failed to start processor: GridProcessorAdapter []
at org.apache.ignite.internal.IgniteKernal.startProcessor(IgniteKernal.java:1960) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgniteKernal.start(IgniteKernal.java:1237) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgnitionEx$IgniteNamedInstance.start0(IgnitionEx.java:2046) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgnitionEx$IgniteNamedInstance.start(IgnitionEx.java:1698) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgnitionEx.start0(IgnitionEx.java:1114) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgnitionEx.startConfigurations(IgnitionEx.java:1032) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgnitionEx.start(IgnitionEx.java:918) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgnitionEx.start(IgnitionEx.java:817) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgnitionEx.start(IgnitionEx.java:687) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgnitionEx.start(IgnitionEx.java:656) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.Ignition.start(Ignition.java:353) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.startup.cmdline.CommandLineStartup.main(CommandLineStartup.java:300) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
Caused by: org.apache.ignite.IgniteCheckedException: Failed to start client connector processor.
at org.apache.ignite.internal.processors.odbc.ClientListenerProcessor.start(ClientListenerProcessor.java:215) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgniteKernal.startProcessor(IgniteKernal.java:1957) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
... 11 more
Caused by: org.apache.ignite.IgniteCheckedException: Failed to bind to any [host:port] from the range [host=0.0.0.0, portFrom=10800, portTo=10800, lastErr=class org.apache.ignite.IgniteCheckedException: Failed to initialize NIO selector.]
at org.apache.ignite.internal.processors.odbc.ClientListenerProcessor.start(ClientListenerProcessor.java:203) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.IgniteKernal.startProcessor(IgniteKernal.java:1957) ~[ignite-core-2.9.0-p8.jar:2.9.0-p8]
... 11 more
  1. Необходимо проверить, кто занял порты из диапазона portFrom,portTo - netstat -anp | grep ПОРТ;

  2. С большой вероятность это будет КУ. Если так, то необходимо потушить КУ и рестартовать СУ, который не удавалось запустить. После поднятия СУ поднять КУ.

Причина 3 (ignite-provider)

Не стартует ignite-provider 4.1.0 после обновления на WildFly (WF), в server.log WildFly присутствует:

Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang.StringUtils from [Module "deployment.ignite-provider-ear-4.1.0.ear" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:255)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
... 37 common frames omitted

Необходимо провести рестарт WildFly, данная проблема возникает, если после обновления не проводить рестарт WF.

Превышение количества открытых файловых дескрипторов#

В ignite.log есть информация о том, что:

  • узел не стартует;

  • узел выпал во время работы.

Caused by: java.io.IOException: Too many open files
at java.base/sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
at java.base/sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:533)
at java.base/sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:285)
at org.apache.ignite.internal.util.nio.GridNioServer$GridNioAcceptWorker.processSelectedKeys(GridNioServer.java:2998)
at org.apache.ignite.internal.util.nio.GridNioServer$GridNioAcceptWorker.accept(GridNioServer.java:2928)
... 3 more

Для диагностики нужно проверить лимиты на количество открытых файлов. Посмотреть, кто утилизировал через lsof. Если утилизировал Ignite, то убедиться в том, что максимальное количество файлов рассчитано корректно.

Действия для проверки лимитов:

  1. Получите количество открытых обработчиков с помощью команды: sudo lsof -u user | wc -l. Где user - это имя пользователя.

  2. Проверьте конфигурацию системы на наличие файловых дескрипторов: sudo sysctl fs.file-nr. Лимит может быть увеличен в файле: /etc/sysctl.conf.

  3. Проверьте приложение на правильность закрытия файловых ресурсов и определите, какой процесс использует файловые дескрипторы.

Максимальное количество файловых дескрипторов, которые могут быть открыты в вашей файловой системе всеми процессами можно узнать так:

cat /proc/sys/fs/file-max

В Linux можно настроить на уровнях ядра ОС, сервиса и пользователя. Можно вывести текущие ограничения на количества открытых файлов в ядре Linux, Soft-ограничения как рекомендательный характер и Hard-ограничения, превысив которое пользователей не сможет открыть новые файлы. Ограничения под лимиты устанавливаются в файле /etc/security/limits.conf.

Существуют формулы расчета рекомендованного лимита. Количество требуемых файловых дескрипторов равняется числу партиций (файлов), распределенных в соответствии с affinity функцией во всем grid-кластере разделить на количество серверов + количество партиций в реплицированных cache group.

Решение состоит в том, чтобы увеличить лимиты в случае необходимости, снизить потребление.

Увеличение длительности GC-пауз во время снятия снепшота#

При увеличении длительности GC-пауз во время снятия снепшота стоит установить рекомендованные значения JVM-опций и сконфигурировать стенд согласно чек-листу.

Во время снятия снепшота увеличивается генерация мусора. Данную проблему можно компенсировать через выработанные JVM-опции. Также при снятии снепшота резко подскакивает утилизация диска до максимальных значений, что приводит к невозможности сделать запись в GC-лог, в случае если он пишется на тот же диск, на который снимается снепшот. Запись в GC-лог синхронная.

Рост очереди striped pool#

При резком росте нагрузки запросы (кеш-операции и транзакции) могут накапливаться в очереди striped pool executor. Возможны следующие ситуации с успешным и неуспешным обслуживанием очереди:

  • В случае успешного обслуживания накопившейся очереди на графике IgniteStripedThreadPoolExecutor наблюдаются узкие пики, которые демонстрируют резкий рост и резкий спад.

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

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

Для решения проблемы найдите медленно выполняющиеся транзакции и передайте информацию о проблеме прикладным разработчикам для оптимизации.

Высокая утилизация CPU#

Для решения проблемы высокой утилизации CPU java-процессом необходимо знать идентификатор PID (process identifier) проблемного процесса. Выполните следующие шаги:

  1. Получите потоки процесса по PID с помощью следующей команды:

    ps aux -T | grep PID > psaux.txt
    

    В результате выполнения этой команды будет выведен список всех потоков процесса с утилизацией CPU по каждому из них. Чтобы понять, какой участок кода внутри JVM утилизировал CPU и в какой период времени, используйте атрибуты SPID и %CPU. Отсортируйте данные из столбца %CPU по убыванию.

  2. Соберите thread dumps с помощью следующей команды:

    jstack -l PID > jstack.txt
    

    Для дальнейшей работы используйте атрибуты SPID, представленные в шестнадцатеричной системе счисления в поле nid.

  3. Сопоставьте атрибуты %CPU и SPID, полученные на предыдущих двух шагах. Это сравнение поможет понять, какой участок кода внутри JVM утилизировал CPU и на какой период времени.

Пример:

  1. В качестве примера возьмем поток JVM с PID 2350369.

  2. Запросите потоки процесса:

    ps aux -T | grep 2350369 > [psaux.txt]
    
  3. Соберите thread dumps:

    jstack -l 2350369 > [jstack.txt]
    
  4. В примере самые нагруженные по CPU потоки — это 738903 и 747596. В шестнадцатеричной системе они соответствуют b4657 и b684C соответственно.

  5. Найдите в jstack участки кода, которые соответствуют значениям b4657 и b684c:

    "kafka-producer-network-thread | transport-lib-producer-[hostname]-[union-module]-[default]-[5ac8b7d4-b6c7-4506-bf4c-77a390e9ecad]" #99 daemon prio=5 os_prio=0 tid=0x00007f8e098ea000 nid=0xb4657 runnable [0x00007f8e05964000]
    java.lang.Thread.State: RUNNABLE
    
    "[union-module]-[com.sbt.core.commons.config_impl.PlatformPropertyLoaderImpl-pci-union-module-D-01.021.01------]-kafka-processor-thread-2" #622 prio=5 os_prio=0 tid=0x00007f8a98043000 nid=0xb684c runnable [0x00007ef40abe9000]
    java.lang.Thread.State: RUNNABLE
    

Проблемы с таймаутами соединения узлов#

Параметр connectionRecoveryTimeout устанавливает величину промежутка времени, в течение которого узел будет предпринимать попытки переподключиться к соседнему узлу кластера. Значение таймаута по умолчанию составляет 10 000 мс. Значение, равное нулю, означает, что узел не будет перепроверять проблемные узлы, с которыми не удалось установить подключение.

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

Для решения проблемы реализован следующий механизм. Проблемный узел, с которым первично не удалось установить соединение, будет последовательно пытаться подключиться к следующим узлам. В случае, если вновь выбранный узел уже подключился к предыдущему узлу, это заставит проблемный узел повторить попытку подключения к предыдущему узлу. Эти попытки будут продолжаться до тех пор, пока проблемный узел не сможет подключиться либо пока не истечет значение таймаута connectionRecoveryTimeout. Если таймаут истечет, а успешного подключения так и не состоится, проблемный узел сегментирует себя самостоятельно.

Можно самостоятельно установить новый таймаут, изменив значение параметра connectionRecoveryTimeout в конфигурации TcpDiscoverySPI. Так, увеличение таймаута имеет смысл в кластере, где присутствуют длинные GC-паузы или медленная нестабильная сеть. Однако новое значение таймаута connectionRecoveryTimeout не может быть больше значения, установленного в параметре failureDetectionTimeout.

Пример XML-конфигурации:

    <bean abstract="false" id="ignIgniteConfiguration" class="org.apache.ignite.configuration.IgniteConfiguration">  
        <property name="communicationSpi"> 
            <bean id="ignTcpDiscoverySpi" class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi"> 
                <property name="connectionRecoveryTimeout" value="30000"/>  
            </bean> 
        </property>
    </bean>

Развал грида#

В общем случае, развал грида происходит, когда узлы перестают отвечать на heartbeat по достижении определенного таймаута.

Если необходимо выполнить расширенные настройки обнаружения сбоев и IgniteConfiguration.getFailureDetectionTimeout() не подходит, то могут использоваться различные параметры конфигурации TCPDiscoverySpi. Например, для стабильных сетей с низкой задержкой рекомендуется такие настройки (время обнаружения ~200 ms):

  • частота Heartbeat — 100 мс;

  • socket timeout — 200 мс;

  • таймаут сообщения подтверждения — 50 мс.

GC-паузы#

Из-за длительных GC-пауз может как замедляться работа грида, так могут и выходить узлы из топологии. В зависимости от их длительности и частоты.

Исходя из практики, топ-причины:

  1. Прикладной код удерживает свои объекты.

  2. Прикладной код получает большие выборки данных без флага lazy.

  3. Прикладной код получает большие выборки с сортировками и группировками (флаг lazy не помогает).

  4. Не выставлены рекомендованные настройки, некорректно сконфигурирована JVM.

  5. Сбор tread dump.

Проблемы с сетью#

Проблемы могут возникать на старте узла кластера, нужно проверить открыты ли порты (nc ip port), часто возникает в pci dss.

Во время работы Apache Ignite проблемы с сетью возникают, в основном, из-за плановых работ на сети, о которых обычно предупреждают заранее.

Если возникают подозрения в неадекватной работе сети или в логе видны адреса, которые не принадлежат ни серверным, ни клиентским узлам — следует проверить, что в конфигурации серверных узлов для beans discoverySpi и communicationSpi корректно задано свойство localAddress.

Аппаратный сбой#

При аппаратных сбоях обычно происходит перезагрузка. Если это произошло, необходимо обратиться к linux-администраторам. Чтобы самостоятельно проанализировать проблему, можно вывести историю сообщений с помощью команды dmesg или зайти в директорию /var/log/messages.

Человеческий фактор#

kill процесса, накат обновлений (смотрим в messages), запуск ПО, которое занимает всю оставшуюся память, приводит к падению jvm.

Сбой на уровне ОС#

Ломалась файловая система, в ignite.log были стеки с попытками работать с диском, в messages были сообщения о поломанной файловой системе.

На виртуальных машинах#

Нехватка CPU#

Симптомы проблемы:

  • выпадают узлы с разными ошибками;

  • метрика на Steal Time имеет ненулевое значение.

Сообщите о проблеме администраторам виртуальной инфраструктуры.

Фризы#

Симптомы: выпадают узлы по таймауту.

Диагностика: в GC-логах могут присутствовать длительные GC-паузы, содержимое GC-логов будет выглядит так, будто сборщик мусора некоторое время не собирал мусор.

Решение: передать проблему на анализ администраторам виртуальной инфраструктуры.

LRT#

Симптомы: solation=REPEATABLE_READ, concurrency=PESSIMISTIC, timeout=0, sysInvalidate=false, sys=false, plc=2, commitVer=null, finalizing=NONE, invalidParts=null, state=ACTIVE, timedOut=false.

Шифт ставит ограничение на количество открытых файлов от приложения, такое может произойти, если обычное приложение внутри виртуальной инфраструктуры открывает много файлов.

Если это происходит на виртуальной инфраструктуре, появляется ошибка, но внутри шифта может ничего не происходить, просто все зависает. То же самое может произойти и с тредами.

Мы создаем новый тред, открываем в нем транзакцию, затем создаем еще один, шифт это блокирует и все зависает, а внутри Ignite остаются открытые транзакции.

Репликация change data capture, CDC - experimental feature#

Кумулятивный тикет для сбора проблем:

 `server`          Jira SberWorks
 `serverId`        611daf70-25e6-3844-a434-3583e234ac1b
 `key`             IGN-4694

Чтобы CdcStreamer не завершил работу с ошибкой, необходимо до запуска репликации:

  1. Активировать destination-кластере.

  2. Создать реплицируемый кеш на destination-кластере.

  3. "Пролить" на destination-кластер всю необходимую binary-meta (вставка в кеш, IgniteBinary#registerClass), так как авторепликации binary-meta на текущий момент нет. В процессе работы все обновления binary-meta также необходимо делать на обоих кластерах. Фича на синхронизацию binary-meta: IGNITE-14449.

Во избежание проблем на серверных узлах:

  1. cdcWalPath и walArchivePath должны быть расположены на одном разделе файловой системы, иначе серверный узел завершит работу с ошибкой: IGNITE-16541.

  2. Необходимо уменьшать размер WAL-архива и WAL-сегмента, так как после длительной работы серверный узел может зависать при старте при размерах WAL-архива в 1 Гб и больше и WAL-сегмента в 1 Гб (ansible-конфигурация по умолчанию). Кроме того, может потребоваться отключить сжатие сегментов (WAL-compaction).

Во избежание зацикливание сообщений при active-active репликации необходимо убедиться в следующем:

  1. Настроен conflict resolver для всех реплицируемых кешей.

  2. В conflict resolver указаны разные clusterId для разных кластеров.

Исчерпание места на диске#

Проблема проявляется через появление следующего симптома: ошибка OutOfDiskSpace проявляется при невозможности записи очередного сегмента WAL архива. Журнал узла будет содержать ошибку java.io.IOException: There is not enough space on the disk.

Источник проблемы в том, что свободное место на диске на узлах должно быть в scope метрик для мониторинга.

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

Проблемы с хранением данных#

Симптом проблемы

Возможная причина

Решение

Возникает ошибка вида OutOfMemory Errors в Java

1. Недостаточный размер Heap;
2. Выполнение объемных SQL запросов

1. Увеличьте -Xmx:
-XX:InitiatingHeapOccupancyPercent=40;
-XX:InitiatingHeapOccupancyPercent=60;
-XX:InitiatingHeapOccupancyPercent=80
2. Используйте lazy queries; избегайте большого количества одновременных запросов; разделите SQL-запрос для снижения размера объема данных

Возникает исключение вида IgniteOutOfMemoryException

Недостаточный размер региона данных (Data Region)

Увеличьте DataRegionConfiguration.maxSize; используйте Native Persistence; установите DataRegionConfiguration.pageEvictionMode=RANDOM_2_LRU; используйте политику истечения срока действия

OC останавливает Ignite JVM

Суммарный размер процессов превысил RAM

Проверьте наличие сообщения Out of memory: Kill process <PID> (java) score <SCORE> or sacrifice child; убедитесь, что общий объем процессов находится в пределах границ; отключите overcommit, чтобы получать более аккуратные ошибки в процессе. Важно: использование команды sysctl -w vm.overcommit_memory=2 может повлиять на другие приложения

Происходит полная или частичная потеря данных после перезапуска одного или нескольких узлов кластера. Динамику этих изменений можно увидеть на графике cache size

Отсутствует или не хватает backup-узлов для in-memory-кеша

В случае отсутствия backup-узла для in-memory-кеша всегда будет происходить потеря данных при перезапуске узла. В случае, если в in-memory-кеше есть один или несколько backup-узлов, не рекомендуется одновременно перезапускать больше узлов, чем в backup; подождите перезапуска после возвращения узла с использованием web console

Возвращаются неправильные или неполные SQL-данные

Произошла колокация данных

См. раздел «Выполнение JOIN»

Происходит потеря данных на некоторых узлах. Ошибку можно обнаружить в Persistence Storage по следующим признакам:
— включен Native Persistence;
— данные хранятся только в одном узле или в подмножестве узлов;
— новые узлы не сохраняют данные

Базовая топология не включает некоторые узлы

Измените состав топологии в baseline, используя control.sh или Admin UI

Исчерпание кучи#

Симптомом исчерпания кучи является появление сообщений об OutOfMemoryError и наличие проблемы «PROBLEM: High Heap utilisation on» в мониторинге.

NB! Утилизация heap, которая не приводит к OutOfMemoryError, проблемой по сути не является. Утилизация выше 80% нормальная ситуация, на некоторые стенды мы отключаем триггеры на 80%. Стоит пересмотреть конфигурацию мониторинга в 80%.

Исчерпание кучи может быть спровоцировано неверным планированием емкости кластера, когда реальная нагрузка и использование ресурса выше. Это большие транзакции SQL с сортировками, группировками. Таким запросам необходимо временно сохранять результат выборки.

Если обнаружена или подозревается утечка памяти, необходимо устранить ее. Если проблема не вызвана утечками памяти:

  • Увеличить объем Heap на узлах, выставить опцию -xmx.

  • Увеличить количество узлов.

Утечки памяти#

Во время подозрения или обнаружения утечки памяти стоит обратить внимание на наличие незакрытых курсоров в gc.log в [Full GC (Allocation Failure) 2021-12-14T09:48:53.527+0300: 88071.654: Class Histogram (before full gc):

| 1: | 94848703   | 4704015512 | `[C`
| 2: | 1681751    | 2323398064 | `[Ljava.lang.Object;`
| 3: | 94809127   | 2275419048 | `java.lang.String`
| 4: | 92417807   | 1478684912 | `org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2String`
| 5: | 24014516   | 576348384  | `org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2Long`
| 207: | 5866     | 375424     | `org.apache.ignite.internal.processors.cache.query.RegisteredQueryCursor`

Решение состоит в том, чтобы через анализ гистограммы изучить информацию по созданным объектам и найти дефект.

С помощью analyzer нужно изучить данные heap dump, чтобы понять, какие instance классов были созданы и зачем.

Падение серверных узлов с «Unknown connection detected» в логе#

Серверные узлы аварийно завершают работу с подобным стэктрейсом:

2021-11-07 01:08:25.603 [ERROR][tcp-disco-srvr-[:47500]-#3-#57][] Critical system error detected. Will be handled accordingly to configured handler [hnd=StopNodeOrHaltFailureHandler [tryStop=false, timeout=0, super=AbstractFailureHandler [ignoredFailureTypes=UnmodifiableSet [SYSTEM_WORKER_BLOCKED, SYSTEM_CRITICAL_OPERATION_TIMEOUT]]], failureCtx=FailureContext [type=SYSTEM_WORKER_TERMINATION, err=java.net.SocketTimeoutException: Accept timed out]]
java.net.SocketTimeoutException: Accept timed out
at java.net.PlainSocketImpl.socketAccept(Native Method) ~[?:?]
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:458) ~[?:?]
at java.net.ServerSocket.implAccept(ServerSocket.java:565) ~[?:?]
at java.net.ServerSocket.accept(ServerSocket.java:533) ~[?:?]
at org.apache.ignite.spi.discovery.tcp.ServerImpl$TcpServer.body(ServerImpl.java:6603) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:120) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.spi.discovery.tcp.ServerImpl$TcpServerThread.body(ServerImpl.java:6526) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
at org.apache.ignite.spi.IgniteSpiThread.run(IgniteSpiThread.java:58) [ignite-core-2.9.0-p8.jar:2.9.0-p8]
2021-11-07 01:08:25.609 [ERROR][tcp-disco-srvr-[:47500]-#3-#57][] JVM will be halted immediately due to the failure: [failureCtx=FailureContext [type=SYSTEM_WORKER_TERMINATION, err=java.net.SocketTimeoutException: Accept timed out]]

Падению предшествуют предупреждения вида:

Unknown connection detected (is some other software connecting to this Ignite port?) [rmtAddr=/<rmtAddr>:52082, locAddr=/<localAddr>:47100]

Источником попыток подключения в большинстве случаев может быть сканер безопасности. Основная причина падения узлов - дефект в работе OpenJDK: JDK-8237858.

Дополнительная обработка SocketTimeoutException будет в версиях 4.2110.4 (hot-fix) и 4.2120.0 Ignite SE: IGNITE-15767, целевым решением проблемы является обновление до указанных версий.

Проблема с ресурсами ОС#

Проблема с ресурсами ОС проявляется через ошибки в логах с узла: java.lang.OutOfMemoryError: unable to create new native thread.

OutOfMemoryError в данном случае не говорит о нехватке heap space или RAM, эта проблема об OutOfResources, чем об OutOfMemory. В данном случае проблема говорит о том, что ОС не имеет достаточно ресурсов для дополнительных потоков. Информация о том, что 50% free memory в этом случае не будет релевантной.

Проблема редкая, так как нечасто нужно так много потоков. Количество потоков в ОС ограничено и разнится для разных систем.

Стоит рассмотреть возможность переписать и использовать Callable/Runnable под контроль Executor.

Если JVM запускается через systemd, найдите service status и проверьте maxTasks (tasks = threads) per process limit.

Ошибки при использовании NULL Cipher Suites#

По умолчанию при использовании плагина и SSL шифрование не используется в целях снижения нагрузки на кластер. Для этого используются NULL Cipher Suites, которые отключены в версиях JDK 8u201 и выше. При попытке использования шифров на версии Java с отключенными NULL Cipher Suites можно наблюдать следующую ошибку:

org.apache.ignite.IgniteException: Unable to establish secure connection. Was remote cluster configured with SSL? [rmtAddr=/127.0.0.1:47500, errMsg="No appropriate protocol (protocol is disabled or cipher suites are inappropriate)"]

Варианты решения ошибки:

  1. Исключить значения NULL из параметра jdk.tls.disabledAlgorithms файла java.security. Для этого в файле $JAVA_HOME/jre/lib/security/java.security (в версии 11 файл называется jdk-11.0.2.jdk/Contents/Home/conf/security/java.security) необходимо найти строку

    jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ 
    EC keySize < 224, 3DES_EDE_CBC, anon, NULL 
    

    и заменить ее на

    jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ 
    EC keySize < 224, 3DES_EDE_CBC, anon
    
  2. В случае, если не получается отредактировать файл java.security, можно скопировать JDK в другую папку и изменить java.security там. Измененный файл можно скопировать и использовать в среде разработки.

  3. Создать отдельный файл (например, disabledAlgorithms.properties). В этом файле прописать следующее:

    jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon
    

После этого запустить Java с опцией java -Djava.security.properties=disabledAlgorithms.properties.

Ошибки при попытках подключения с разными настройками jdk.tls.disabledAlgorithms#

По умолчанию в настройках файла jdk.tls.disabledAlgorithms указано значение NULL. Это значение необходимо удалить. В случае, если на стороне сервера и клиента используются файлы jdk.tls.disabledAlgorithms с разными настройками (с NULL и без NULL), могут возникать следующие ошибки:

  • ошибка No appropriate protocol (protocol is disabled or cipher suites are inappropriate) появляется, если сервер использует файл jdk.tls.disabledAlgorithms без NULL, а клиент — файл с NULL. Для решения проблемы необходимо удалить значение NULL в файле клиента;

  • ошибка Received fatal alert: handshake_failure появляется, если сервер использует файл jdk.tls.disabledAlgorithms с NULL, а клиент — файл без NULL. Для решения проблемы необходимо удалить значение NULL в файле сервера.

Некорреткные признаки EKU в сертификатах#

EKU (extended key usage) должны содержать оба признака: serverAuth и clientAuth (см. раздел «Создание и подпись сертификатов» документа «Руководство по безопаности»).

При включенном SSL неполное число признаков в EKU сертификата приводит к ошибкам:

  • ошибки рукопожатия SSL (javax.net.ssl.SSLHandshakeException) — узел не может войти в топологию;

  • у толстого клиента отсутсвие serverAuth при наличии clientAuth приводит к тому, что клиенты будут входить в топологию и затем выходить из нее по ошибке взаимодействия по TcpCommunication через некоторое время.

Валидация EKU сертификата в плагине безопаности#

В плагине безопасности есть валидация параметров EKU. При неверных признаках узел будет завершать работу с одной из указанных ниже ошибок.

Пустой EKU:

2023-06-16 09:00:38.616 [ERROR][main][org.apache.ignite.internal.IgniteKernal] Got exception while starting (will rollback startup routine).
org.apache.ignite.plugin.security.SecurityException: The ExtendedKeyUsage extension of the local node certificate is not set. Make sure ExtendedKeyUsage contains both 'serverAuth' and 'clientAuth'.

Не хватает какого-либо из признаков в EKU:

2023-06-16 09:00:38.616 [ERROR][main][org.apache.ignite.internal.IgniteKernal] Got exception while starting (will rollback startup routine).
org.apache.ignite.plugin.security.SecurityException: The ExtendedKeyUsage extension of the local node certificate is not valid. Make sure ExtendedKeyUsage contains both 'serverAuth' and 'clientAuth' [expEku=[1.3.6.1.5.5.7.3.1, "1.3.6.1.5.5.7.3.2], certEku=[1.3.6.1.5.5.7.3.2]]

Ошибка «Unacknowledged messages queue size overflow» в log-файлах и низкая скорость операций#

Проблема:

При включенном SSL и/или плагине безопасности наблюдается снижение производительности и следующие сообщения в логах:

[2023-05-14T15:16:46,231][WARN ][grid-nio-worker-tcp-comm-3-#26%TcpCommunicationSpi%][TcpCommunicationSpi] Unacknowledged messages queue size overflow, will attempt to reconnect [remoteAddr=/<ip-address:port>, queueLimit=4096]
 
[2023-05-14T15:16:47,233][ERROR][grid-nio-worker-tcp-comm-3-#26%TcpCommunicationSpi%][TcpCommunicationSpi] Failed to process selector key ...
    at org.apache.ignite.internal.util.nio.ssl.GridNioSslHandler.encrypt(GridNioSslHandler.java:393) ~[ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.ssl.GridNioSslFilter.encrypt(GridNioSslFilter.java:337) ~[ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$DirectNioClientWorker.processWriteSsl(GridNioServer.java:1506) ~[ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$DirectNioClientWorker.processWrite(GridNioServer.java:1405) ~[ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$AbstractNioClientWorker.processSelectedKeysOptimized(GridNioServer.java:2529) [ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$AbstractNioClientWorker.bodyInternal(GridNioServer.java:2281) [ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$AbstractNioClientWorker.body(GridNioServer.java:1910) [ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:125) [ignite-core-2.15.0.jar:2.15.0]
    at java.lang.Thread.run(Thread.java:834) [?:?]
 
[2023-05-14T15:16:47,234][WARN ][grid-nio-worker-tcp-comm-3-#26%TcpCommunicationSpi%][TcpCommunicationSpi] Client disconnected abruptly due to network connection loss or because the connection was left open on application shutdown ...
    at org.apache.ignite.internal.util.nio.ssl.GridNioSslHandler.encrypt(GridNioSslHandler.java:393) ~[ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.ssl.GridNioSslFilter.encrypt(GridNioSslFilter.java:337) ~[ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$DirectNioClientWorker.processWriteSsl(GridNioServer.java:1506) ~[ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$DirectNioClientWorker.processWrite(GridNioServer.java:1405) ~[ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$AbstractNioClientWorker.processSelectedKeysOptimized(GridNioServer.java:2529) [ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$AbstractNioClientWorker.bodyInternal(GridNioServer.java:2281) [ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.nio.GridNioServer$AbstractNioClientWorker.body(GridNioServer.java:1910) [ignite-core-2.15.0.jar:2.15.0]
    at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:125) [ignite-core-2.15.0.jar:2.15.0]
    at java.lang.Thread.run(Thread.java:834) [?:?]

Решение:

Как видно, в потоке grid-nio-worker-tcp-comm-3-#26%TcpCommunicationSpi% сначала происходит превышение очереди unacknowledged-сообщений TcpCommunication, а затем принудительный разрыв соединения.

Проблема возникает из-за роста очереди неподтвержденных сообщений TcpCommunication во время всплеска нагрузки, особенно putAll. Необходимо оптимизировать бизнес-нагрузку на кластер и/или выполнить вертикальное и горизонтальное масштабирование кластера DataGrid.

В качестве обходного решения можно увеличить размер очереди, по умолчанию равный 4096, указав параметр TcpCommunicationSpi#unacknowledgedMessagesBufferSize. Может потребоваться установить его больше в несколько раз, например 65535. Выбранное значение следует тщательно протестировать на стенде для нагрузочного тестирования.

Проблемы при работе CDC#

Диагностика и устранение сбоев в работе CDC#

Причины нарушений работы CDC#

Нарушения в работе CDC могут быть вызваны следующими причинами:

  • особенности использования CDC;

  • ошибки конфигурации серверных узлов и приложений CDC;

  • инфраструктурные ошибки, ошибки со стороны окружения;

  • смена public API при обновлении.

Каждая из причин рассмотрена подробнее в следующих разделах.

Особенности использования CDC#

Существуют особенности в работе, которые следует учитывать при настройке и эксплуатации, иначе будут возникать ошибки в работе приложений CDC:

  • кластеры-приемники должен быть активированы, иначе появится ошибка:

    Can not perform the operation because the cluster is inactive
    
  • кеши должны быть созданы на обоих кластерах, иначе появится ошибка:

    Cache with id not found [cacheId=1231231]
    
  • на версиях DataGrid ниже 4.2130 до старта CDC на всех кластерах должны быть осуществлены вставки в реплицируемые кеши, чтобы была зарегистрирована binary metadata, иначе появится ошибка:

    BinaryObjectException: Cannot find metadata for object with compact footer
    

Ошибки возникают при применении изменений и приводят к остановке:

  • ignite-cdc.sh — в случае прямой репликации между кластерами DataGrid;

  • kafka-to-ignite.sh — в случае репликации DataGrid через Kafka/Corax.

Общий алгоритм для анализа проблем, связанных с CDC#

Для анализа проблем, связанных с CDC, выполните действия:

  1. Проверьте метрики или триггеры CDC в системе мониторинга; убедитесь, что метрики по всем запущенным приложениям CDC увеличиваются на всех кластерах (если есть нагрузка на кластеры).

  2. В случае репликации через Kafka/Corax проверьте метрики log-end-offset и lag в мониторинге Kafka/Corax.

  3. Проанализируйте логи СУ (ignite.log) и приложений CDC (ignite-cdc.log и kafka-ignite-streamer.log) на предмет ошибок и предупреждений. Убедитесь, что данная проблема не относится к настройке DataGrid и настройке плагина безопасности. Описание сообщений логов при работе CDC приведено в разделе «Первичный анализ логов» документа «Руководство по системному администрированию».

  4. Если на кластер-источник есть нагрузка, и приложения CDC завершают работу в течение нескольких минут после старта, то данное поведение, как правило, говорит о проблемах с настройкой приложений.

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

  6. Спонтанные ошибки, например, таймауты отправки, могут говорить о проблемах с сетью или аппаратным обеспечением.

Ошибки конфигурации серверных узлов#

Для анализа данных ошибок проанализируйте серверные логи.

Медленная ротация сегментов#

Проблема:

Ступеньки в росте размеров кешей в системе мониторинга; расхождение содержимого кешей и их размеров больше, чем ожидается (желтый график):

Slow Segment Rotation

Решение:

  1. В логах серверных узлов проверьте частоту ротации WAL-сегментов:

    2022-12-15 05:35:35.768 [INFO ][grid-timeout-worker-#38][FileWriteAheadLogManager] Rollover segment [11324 to 11325], recordType=null
    2022-12-15 06:54:46.798 [INFO ][grid-timeout-worker-#38][FileWriteAheadLogManager] Rollover segment [11325 to 11326], recordType=null
    
  2. Если ротация очень редкая (минуты или часы), проверьте в конфигурации наличие параметра walForceArchiveTimeout:

    <bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
        <property name="walForceArchiveTimeout" value="10000"/>
    ...
    
Не включена запись журнала на серверном узле#

Проблема:

Не записывается журнал репликации, то есть не копятся сегменты в директории CDC. Данные не реплицируются.

Решение:

Проверьте, установлен ли параметр cdcEnabled=true для регионов данных (DataRegion), в которых находятся реплицируемые кеши (не путать с REPLICATED-режимом кешей). Если параметр не установлен, то создание жестких ссылок не будет производиться, в итоге изменения не будут реплицироваться на кластер-приемник.

Разные разделы WAL-архива и журнала репликации#

Сегменты, расположенные в директории журнала репликации, являются жесткими ссылками на сегменты WAL-архива. Linux не поддерживает создание жестких ссылок на файлы, расположенные на другом разделе файловой системы. Для решения проблемы разместите WAL-архив и журнал CDC на одном разделе файловой системы.

С версии DataGrid 4.2130 и выше — ошибка при старте серверного узла:

Paths are not stored at the same device or partition. Creating hard links is not available.

На версии DataGrid 4.2120 — другая ошибка, возникает на серверном узле во время ротации WAL-сегмента:

org.apache.ignite.internal.processors.cache.persistence.StorageException: Failed to archive WAL segment
...
Caused by: java.nio.file.FileSystemException: /opt/ignite/data/.../0000000000000000.wal ->
/opt/ignite/wal_archive/.../0000000000000000.wal: Invalid cross-device link
Некорректные параметры ConflictResolver#

Примечание

Настройка плагина ConflictResolver описана в разделе «Разрешение конфликтов репликации при помощи CacheVersionConflictResolver» документа «Руководство по системному администрированию».

Ошибки отображаются в серверных логах, так как плагин ConflictResolver настраивается для серверных узлов.

Не настроен ConflictResolver#

Если не настроен ConflictResolver или в нем не указаны требуемые кеши, то при изменении данных в обоих кластерах будут дублироваться и зацикливаться сообщения репликации.

Симптомы:

  • хаотично меняются значения в кеше и постоянно применяются события репликации;

  • нагрузки на кластеры нет, но в логах ignite-cdc.sh, kafka-to-ignite.sh постоянно присутствуют сообщения Event received, Applying put batch, Applying remove batch;

  • CDC through Kafka: в топике событий растет log-end-offset, при определенной нагрузке может начать расти расхождение (lag);

  • в логах СУ наблюдаются сообщения о выполнении checkpoint и ротации WAL-сегментов (косвенный признак).

Решение:

  1. Перезапустите все кластеры с корректной настройкой ConflictResolver. Если настроено поле conflictResolvableField, то конфликты разрешатся сами по себе.

  2. Проверьте и восстановите согласованность между кластерами (подробнее в разделе Восстановление согласованности кластеров текущего документа).

Одинаковый clusterId#

Симптомы:

С точки зрения разрешения конфликтов кластеры будут одинаковыми, поэтому будет происходить безусловное применение событий репликации без сравнения значений conflictResolvableField. Две конкурентные вставки значения (INSERT) на разных кластерах будут применены безусловно, приводя к несогласованности.

Решение:

  1. Задайте разные clusterId в настройках кластеров.

  2. Проверьте и восстановите согласованность между кластерами (подробнее в разделе Восстановление согласованности кластеров текущего документа).

  3. Устраните конфликты из прикладного кода или вручную.

Не указано поле conflictResolveField#

Не настроенное поле CacheVersionConflictResolverPluginProvider#conflictResolveField будет приводить к тому, что конфликтные изменения (изменения одних и тех же записей на разных кластерах) применяться не будут, а в логах серверных узлов будут сообщения об ошибках следующего вида:

[2023-05-23T18:03:12,756][ERROR][sys-stripe-13-#14][CacheVersionConflictResolverImpl] <cache_name> Conflict can't be resolved, update ignored [key=keyValue, fromCluster=1, toCluster=2]

Решение:

  1. Задайте поле conflictResolveField в настройках серверных узлов.

  2. Проверьте и восстановите согласованность между кластерами (смотри раздел Восстановление согласованности кластеров текущего документа).

Отсутствует поле conflictResolveField в объектах#

Если поля не заданы в объектах, будет появляться ошибка разрешения конфликта и соответствующие записи в логе СУ:

2023-07-17T14:29:30,785 [ERROR][client-connector-#103%ignite-2029-server%][CacheVersionConflictResolverImpl] <CacheName> Error while resolving replication conflict. [field=modificationDate, key=org.examples.model.Key  [idHash=1992838831, hash=1745342858, keyId=2, stringId=ID2]]
java.lang.NullPointerException: null
    at org.apache.ignite.cdc.conflictresolve.CacheVersionConflictResolverImpl.isUseNew(CacheVersionConflictResolverImpl.java:128) ~[ignite-cdc-ext-14.1.0.jar:14.1.0]
 
...
 
2023-07-17T14:29:30,787 [ERROR][client-connector-#103%ignite-2029-server%][CacheVersionConflictResolverImpl] <CacheName> Conflict can't be resolved, update ignored [key=org.examples.model.Key  [idHash=1992838831, hash=1745342858, keyId=2, stringId=ID2], fromCluster=2, toCluster=1]

Решение:

  1. Исправьте код приложения или сервиса, осуществляющего вставки в DataGrid: необходимо указывать монотонно возрастающее значение conflictResolveField во вставляемых объектах.

  2. Проверьте и восстановите согласованность между кластерами (подробнее в разделе Восстановление согласованности кластеров текущего документа).

Значение null для conflictResolveField#

Если значение поля null, будет появляться ошибка разрешения конфликта и соответствующие записи в логе (stack trace может отличаться, если другой тип поля) СУ:

2023-07-17T14:06:51,025 [ERROR][client-connector-#105%ignite-2029-server%][CacheVersionConflictResolverImpl] <CacheName> Error while resolving replication conflict. [field=modificationDate, key=org.examples.model.Key  [idHash=420148468, hash=321295221, keyId=1, stringId=ID1]]
java.lang.NullPointerException: null
at java.sql.Timestamp.compareTo(Timestamp.java:515) ~[?:1.8.0_322]
at java.sql.Timestamp.compareTo(Timestamp.java:72) ~[?:1.8.0_322]
at org.apache.ignite.cdc.conflictresolve.CacheVersionConflictResolverImpl.isUseNew(CacheVersionConflictResolverImpl.java:128) ~[ignite-cdc-ext-14.1.0.jar:14.1.0]
...
 
2023-07-17T14:06:51,030 [ERROR][client-connector-#105%ignite-2029-server%][CacheVersionConflictResolverImpl] <CacheName> Conflict can't be resolved, update ignored [key=org.examples.model.Key  [idHash=420148468, hash=321295221, keyId=1, stringId=ID1], fromCluster=2, toCluster=1]

Решение:

  1. Исправьте код приложения или сервиса, осуществляющего вставки в DataGrid: необходимо указывать монотонно возрастающее значение conflictResolveField во вставляемых объектах.

  2. Проверьте и восстановите согласованность между кластерами (подробнее в разделе Восстановление согласованности кластеров текущего документа).

Ошибки настройки приложений CDC#

Клиенты DataGrid (тонкий, толстый)#

Все ошибки можно разделить на два основных типа:

  • ошибка плагина безопасности, аудита, параметров SSL или неверные логин/пароль;

  • DataGrid-специфичные настройки: неверный список адресов, неверные настройки клиентского узла Ignite и так далее. Например, перепутаны адреса кластеров, или использованы сертификаты от другого кластера.

Данные ошибки не относятся напрямую к CDC и должны решаться тем же образом, что и проблемы настройки клиентских узлов и тонких клиентов (подробнее в разделе «Часто встречающиеся проблемы и пути их устранения» документа «Руководство по системному администрированию»). При разборе следует учитывать следующее:

  • для CDC Ignite2Ignite (прямая репликация между кластерам DataGrid): клиент DataGrid запускается внутри приложения ignite-cdc.sh на каждом серверном узле кластера-источника (source cluster);

  • для CDC Ignite through Kafka (репликация через Kafka/Corax): клиент Ignite запускается внутри приложения kafka-to-ignite.sh. Для работы достаточно одного клиента на каждый кластер-приемник.

Неверный путь до директории журнала CDC#

Ошибка касается приложения ignite-cdc.sh. При конфигурации по умолчанию приложение запрашивает конфигурационный файл серверного узла, но возможны ошибки:

  • при использовании отдельного конфигурационного файла-дубликата серверной конфигурации с отличающимися путями до журнала CDC;

  • если путь до директории может меняться динамически, например, зависеть от JVM-опций CLUSTER_TYPE и CLUSTER_NAME, когда эти опции отличаются для приложения CDC и серверного узла.

Неверный список кешей#

При указании неверного списка кешей возможны следующие ситуации:

  • Реплицируются не все данные, если список неполный. К падению приложений не приводит, но изменения в таком случае теряются. Возможно решить выгрузкой снепшота либо выгрузкой данных через CDC (доступно в DataGrid начиная, с версии 15.0). Подробнее в разделе Восстановление согласованности кластеров текущего документа.

  • Приложение CDC завершает работу с ошибкой, так как кеш в кластере-приемнике не найден.

Некорректное число партиций Kafka#

Если число партиций в конфигурации меньше, чем в топике Kafka:

  • ignite-cdc.sh: ошибок в работе и потери данных не будет.

  • kafka-to-ignite: если в настройках ignite-cdc.sh указано верное количество партиций, то kafka-to-ignite.sh будет вычитывать события только из части партиций, что приведет к потере событий при очистке по таймауту устаревших записей из топиков (из тех партиций Kafka/Corax, которые не вычитывались).

Если число партиций в конфигурации больше, чем в топике Kafka:

  • ignite-cdc.sh: Завершит работу с ошибкой (по умолчанию через 60 секунд):

    2022-11-07 13:08:17.537 [ERROR][Thread-18][] Cdc error
    java.lang.RuntimeException: java.util.concurrent.ExecutionException: org.apache.kafka.common.errors.TimeoutException:
    Topic TOPIC_NAME not present in metadata after 60000 ms.
        at org.apache.ignite.cdc.kafka.IgniteToKafkaCdcStreamer.onEvents(IgniteToKafkaCdcStreamer.java:183) ~[ignite-cdc-ext-2.12.0-p7.jar:2.12.0-p7]
        at org.apache.ignite.internal.cdc.WalRecordsConsumer.onRecords(WalRecordsConsumer.java:157) ~[ignite-core-2.12.0-p7.jar:2.12.0-p7]
        at org.apache.ignite.internal.cdc.CdcMain.consumeSegment(CdcMain.java:472) ~[ignite-core-2.12.0-p7.jar:2.12.0-p7]
    
  • kafka-to-ignite.sh: ошибок в работе и потери данных не будет, но KafkaConsumer в приложении будет ждать в течение kafkaRequestTimeout при запросе данных с несуществующих партиций. Это может привести к росту lag в Kafka/Corax по части партиций и росту разницы размеров и состава кешей между кластерами (в системе мониторинга Grafana).

Слишком малое значение kafkaRequestTimeout (CDC through Kafka)#

Проблема:

Частое завершение работы ignite-cdc.sh и kafka-to-ignite.sh по таймауту. Примеры ошибок ниже в разделе «Задержки при обмене сетевыми сообщениями».

Для стабильной работы приложений ignite-cdc.sh и kafka-to-ignite.sh значение kafkaRequestTimeout следует задавать больше в несколько раз, чем request.timeout.ms, таким образом, позволяя клиенту Kafka/Corax совершить несколько повторных запросов.

Кроме того, в текущих версиях DataGrid значение по умолчанию для kafkaRequestTimeout (3с) меньше значения по умолчанию для request.timeout.ms(30с).

Смена public API#

В DataGrid, начиная с версии 4.2130, поменялись и добавились настройки:

Новая настройка

Старая настройка

Где указывается

DataRegionConfiguration#cdcEnabled (для каждого региона)

DataStorageConfiguration#cdcEnabled

Серверная конфигурация, раздел с настройками непосредственно СУ

KafkaToIgniteCdcStreamerConfiguration#metadataTopic (обязательная опция)

-

Конфигурация kafka-to-ignite.sh

IgniteToKafkaCdcStreamer#metadataTopic (обязательная опция)

-

Серверная конфигурация, раздел с настройками CdcConsumer

Если не поменять и не добавить данные настройки при обновлении, то запустить кластер и приложения CDC не получится.

Нарушения со стороны окружения#

Не все процессы CDC запущены#

Возможное поведение в случае, если не все процессы CDC запущены:

  • ignite-cdc.sh:

    • ни один процесс ignite-cdc.sh не запущен:

      • рост размеров реплицируемых кешей в кластере-приемнике прекратится, если нет нагрузки на него, либо снизится, если нагрузка есть;

      • репликация через Kafka/Corax: log-end-offset в Kafka/Corax перестают расти по всем Kafka-партициям;

      • прямая репликация DataGrid в DataGrid: наблюдается уменьшенное число подключений клиентов к кластеру-приемнику. Так как ignite-cdc.sh запускается на каждом СУ кластера-источника, то количество клиентов в кластере-приемнике будет уменьшено на число серверных узлов кластера-источника. Если в настройках CDC используется толстый клиент, то в логах СУ будут выходы клиентов из топологии.

    • если часть процессов ignite-cdc.sh не запущены:

      • рост размеров кешей в кластере-приемнике отстает от роста размеров кешей в кластере-источнике;

      • репликация через Kafka/Corax: log-end-offset в Kafka/Corax растут по части партиций быстрее, чем по другим Kafka-партициям;

      • прямая репликация DataGrid в DataGrid: Наблюдается уменьшенное число подключений клиентов к кластеру-приемнику. Если в настройках CDC используется толстый клиент, то в логах СУ будут выходы клиентов из топологии.

    На серверных узлах, где остановлены процессы ignite-cdc.sh, в директории CDC накапливаются сегменты WAL.

  • kafka-to-ignite.sh (только для варианта CDC через Kafka/Corax):

    • если все процессы kafka-to-ignite.sh не запущены, то lag в Kafka/Corax растет равномерно по всем Kafka-партициям (при равномерной нагрузке на DataGrid). Рост размеров реплицируемых кешей в кластере источнике прекратится, если нет нагрузки на кластер, либо снизится, если нагрузка есть.

    • если часть процессов kafka-to-ignite.sh не запущены, то lag в Kafka/Corax растет по части партиций быстрее, чем по другим Kafka-партициям (при равномерной нагрузке на DataGrid). Рост размеров кешей отстает от роста размеров кешей в кластере источнике;

    • если разница между временем начала получения данных из Kafka/Corax и временем отправки сообщений из кластера-источника в Kafka/Corax превысит таймаут retention.time.ms, то события репликации будут удалены из Kafka.

Решение:

  1. Запустите процессы и проверьте, что они не завершают работу с ошибкой. Если появляются ошибки с остановкой процессов, проанализируйте и устраните ошибки.

  2. Убедитесь, что расхождение между кластерами уменьшается: размеры кешей приблизительно равны или состав кешей близок (если есть инструменты сверки).

  3. Избегайте ситуаций, когда приложения ignite-cdc.sh на кластере-источнике запущены, а экземпляры kafka-to-ignite.sh на кластере-приемнике длительное время не запущены.

Постоянное расхождение между кластерами#

Проблема:

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

Такое состояние говорит, что данные потеряны по одной из причин:

  • какое-то время была отключена запись CDC на кластере-источнике, при этом данные изменились;

  • была удалена часть WAL-сегментов в директории CDC;

  • данные потеряны в Kafka/Corax по истечении времени, по переполнению места или удалены каким-либо другим способом.

Решение:

Проверьте и восстановите согласованность между кластерами (подробнее в разделе Восстановление согласованности кластеров текущего документа).

Задержки при обмене сетевыми сообщениями#

Возможные причины:

  • нарушения сетевого обмена;

  • задержки обработки сообщений или длительная недоступность кластера-приемника или Kafka/Corax, например, из-за GC или неисправности оборудования.

Прямая репликация DataGrid

При ошибках и таймаутах обмена сообщениями между кластером-приемником и клиентом DataGrid, последний ведет себя типичным для таких ситуаций образом. При первой же ошибке применения событий в удаленный кластер, приложение ignite-cdc.sh завершит работу. Необходимо провести анализ ошибок подключения толстого или тонкого клиента к кластеру.

Репликация через Kafka/Corax

  • ignite-cdc.sh:

    • если обращение в Kafka/Corax будет происходить дольше, чем kafkaRequestTimeout, приложение завершит исполнение с ошибкой (пример для таймаута 10 секунд):

      Caused by: java.util.concurrent.TimeoutException: Timeout after waiting for 10000 ms.
          at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:78)
          at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:30)
          at org.apache.ignite.cdc.kafka.IgniteToKafkaCdcStreamer.sendOneBatch(IgniteToKafkaCdcStreamer.java:280)
          ... 14 more
      
    • при прочих ошибках обращения к Kafka/Corax ignite-cdc.sh также завершит работу. Для диагностики ошибок обмена с Kafka/Corax обратитесь к документации Kafka/Corax.

  • kafka-to-ignite.sh:

    • при ошибках и таймаутах обмена сообщениями между кластером-приемником и клиентом DataGrid, последний ведет себя типичным для таких ситуаций образом. При первой же ошибке применения событий в удаленный кластер, kafka-to-ignite.sh завершит работу;

    • если обращение в Kafka/Corax будет происходить дольше, чем kafkaRequestTimeout, приложение kafka-to-ignite.sh может завершить исполнение с одной из ошибок (пример для таймаута 10 секунд):

      [2023-05-23T17:14:11,512][ERROR][applier-thread-3][KafkaToIgniteCdcStreamerApplier] Applier error!
      org.apache.kafka.common.errors.TimeoutException: Timeout of 10000ms expired before successfully committing the current consumed offsets
      
      [2023-05-23T17:54:30,908][ERROR][applier-thread-1][KafkaToIgniteCdcStreamerApplier] Applier error!
      org.apache.kafka.common.errors.TimeoutException: Failed to get offsets by times in 10013ms
      
      [2023-05-23T17:58:01,155][ERROR][applier-thread-1][KafkaToIgniteCdcStreamerApplier] Applier error!
      org.apache.kafka.common.errors.TimeoutException: Timeout of 10000ms expired before successfully committing the current consumed offsets
      
      Failed to run app: Timeout expired while fetching topic metadata
      class org.apache.ignite.IgniteException: Timeout expired while fetching topic metadata
      at org.apache.ignite.cdc.kafka.AbstractKafkaToIgniteCdcStreamer.run(AbstractKafkaToIgniteCdcStreamer.java:127)
      at org.apache.ignite.cdc.kafka.KafkaToIgniteCdcStreamer.run(KafkaToIgniteCdcStreamer.java:71)
      at org.apache.ignite.cdc.kafka.KafkaToIgniteCommandLineStartup.main(KafkaToIgniteCommandLineStartup.java:68)
      
    • при прочих ошибках обращения к Kafka/Corax kafka-to-ignite.sh также завершит работу. Для анализа и устранения данных ошибок обратитесь к документации Kafka.

Все запущено, но расхождение между кластерами растет#

Если все процессы CDC запущены, то увеличивающаяся задержка возможна в ситуации, когда вставка в кластер-приемник не успевает за отправкой сообщений с кластера-источника:

  • Прямая репликация DataGrid в DataGrid: скорость генерации WAL выше, чем скорость применения в удаленный кластер: медленный удаленный кластер или сеть. В директории CDC копятся сегменты.

  • Репликация через Kafka/Corax:

    • низкопроизводительный кластер Kafka/Corax;

    • медленная запись в Kafka, быстрое чтение — lag в Kafka/Corax нулевой. В директории CDC копятся сегменты.

    • медленный кластер-приемник — медленное чтение, lag в Kafka/Corax будет расти.

Решение:

Устраните проблемы с производительностью, в первую очередь с сетью, серверами DataGrid и Kafka/Corax.

Нехватка места на диске под WAL-архив#

Проблема:

WAL-сегменты копятся из-за того, что они не обработаны приложением ignite-cdc.sh. При длительном накоплении это приводит к падению серверных узлов из-за переполнения места на разделе с WAL-архивом.

Решение:

В большинстве случаев проблема связана с тем, что не запущено приложение ignite-cdc.sh.

Запустите процесс ignite-cdc.sh. Убедитесь, что он продолжает работу, при этом число сегментов перестало увеличиваться.

Примечание

В версиях DataGrid до 14.1.2 при перестроении индексов на кластере без нагрузки происходит накопление сегментов, так как ignite-cdc.sh не удаляет обработанные сегменты. В данном случае может потребоваться очистка директории CDC, но целевое решение — обновление DataGrid. Работы по перестроению рекомендуется планировать после обновления.

Дополнительно:

  1. Следите за местом на диске.

  2. Рекомендуется увеличить раздел под WAL-архив.

  3. При длительном отключении реплики можно отключать запись журнала (cdcEnabled=false или через control.sh), но нужно учитывать, что это приводит к потере изменений и может потребовать восстановления согласованности (смотри раздел Восстановление согласованности кластеров текущего документа).

Потеря WAL-сегментов#

При пропуске сегментов ignite-cdc.sh завершает работу с ошибкой. В сообщении будет выведен индекс первого нехватающего сегмента:

2023-07-17T21:40:29,250 [ERROR][Thread-1][] Cdc error
org.apache.ignite.IgniteException: Found segment greater then saved state. Some events are missed. Exiting! [state=IgniteBiTuple [val1=WALPointer [idx=2, fileOff=43303, len=0], val2=0], segment=8]
    at org.apache.ignite.internal.cdc.CdcMain.consumeSegment(CdcMain.java:488) ~[ignite-core-14.1.0.jar:14.1.0]

Решение:

  1. Выполните пропуск потерянных сегментов, чтобы приложение ignite-cdc.sh смогло запуститься (подробнее в разделе Обработка пропущенных сегментов документа «Руководство по системному администрированию»).

  2. Выполните выгрузку данных из кластера с потерянными сегментами (подробнее в разделе Восстановление согласованности кластеров текущего документа).

Некорректные настройки брокеров Kafka/Corax и клиентов#

Учитывайте, что у клиентов и брокеров Kafka/Corax, запускаемых в приложениях CDC, есть множество настроек, значительно влияющих на их поведение. Могут встречаться следующие ошибки:

  • превышение допустимого размера сообщений для топика — ignite-cdc.sh завершит работу. Потребуется перенастройка топиков (брокеров);

  • установка auto.offset.reset=latest в настройках kafka-to-ignite.sh приведет к тому, что при перезапуске чтение событий будет начинаться не с самого раннего события (auto.offset.reset=earliest), а с последнего, что будет приводить к потере изменений, записанных в топики между моментами остановки и последующего запуска. В таком случае потребуется восстановление согласованности (смотри раздел Восстановление согласованности кластеров текущего документа);

  • установка enable.auto.commit=true может привести к ситуации, когда kafka-to-ignite.sh не смог применить изменения, а смещение успешно было применено. В таком случае изменения, которые не были применены, будут утеряны. В kafka-to-ignite.sh используется ручное применение смещений только после успешного применения изменений, поэтому необходимо устанавливать enable.auto.commit=false;

  • переполнение места в Kafka/Corax при большом потоке событий CDC. Решается повторным расчетом сайзинга Kafka.

Восстановление согласованности кластеров#

Определить расхождение согласованности можно косвенно по симптомам конкретной проблемы. Типичные проблемы описаны в разделе «Диагностика и устранение сбоев в работе CDC».

Более точный способ — прикладная сверка — требует от пользователя DataGrid написания утилиты или сервиса, который сможет определить расхождения объектов на разных кластерах и предложить решения по устранению конфликтов с учетом бизнес-логики.

Копирование данных через CDC#

Внимание!

Функциональность работает, начиная с версии DataGrid 15.0.

Помимо этого для восстановления согласованности можно использовать выгрузку данных в CDC в следующих ситуациях:

  • если понятно, с какого кластера были отправлены не все изменения данных (был отключен CDC, очищен WAL CDC, Kafka/Corax и тому подобное). В таком случае нужно выгрузить данные с этого кластера на остальные кластеры;

  • если какой-либо из кластеров признан несогласованным и планируется его очистка (либо очистка некоторых кешей). Данные клонируются с других кластеров.

Для копирования данных с кластера выгрузите данные в журнал CDC. Процедура описана в разделе Принудительная повторная отправка всех данных кеша в CDC документа «Руководство по системному администрированию», при этом:

  1. Команда выгрузит все текущие данные из указанных кешей в WAL-журнал CDC.

  2. Данные скопируются на кластер-приемник при помощи приложений CDC.

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

Клонирование кластера можно также использовать для развертывания нового кластера.