Хабрахабр

Концепция BaselineTopology в Apache Ignite 2.4

image

На момент появления в Apache Software Foundation проекта Ignite он позиционировался как чистое in-memory-решение: распределенный кэш, поднимающий в память данные из традиционной СУБД, чтобы выиграть во времени доступа. Но уже в релизе 2.1 появился модуль встроенной персистентности (Native Persistence), который позволяет классифицировать Ignite как полноценную распределенную базу данных. С тех пор Ignite перестал зависеть от внешних систем обеспечения персистентного хранения данных, и вязанка граблей конфигурации и администрирования, на которые не раз наступали пользователи, исчезла.

Однако persistent-режим порождает свои сценарии и новые вопросы. Как предотвратить неразрешимые конфликты данных в ситуации split-brain? Можем ли мы отказаться от перебалансировки партиций, если выход узла теперь не означает, что данные на нем потеряны? Как автоматизировать дополнительные действия вроде активации кластера? BaselineTopology нам в помощь.

BaselineTopology: первое знакомство

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

На самом деле, задать группы можно и в in-memory-режиме

При помощи cluster groups и user attributes пользователь может на основе выбранных признаков распределять узлы по классам. Однако перезапуск любого узла заставляет его «забыть», что происходило с ним до перезапуска. Данные кэшей будут перезапрошены в кластере, вычислительные задачи исполнены повторно, а сервисы развернуты вновь. Раз узлы не хранят состояния, то они полностью взаимозаменяемы.

В режиме персистентности узлы сохраняют свое состояние даже после перезапуска: в процессе старта данные узла считываются с диска, и его состояние восстанавливается. Поэтому перезагрузка узла не приводит к необходимости полного копирования данных с других узлов кластера (процесс, известный как rebalancing): данные на момент падения будут восстановлены с локального диска. Это открывает возможности для очень заманчивых оптимизаций сетевого взаимодействия, и в итоге вырастет производительность всего кластера. Значит, нам нужно как-то отличать множество узлов, способных сохранять своё состояние после перезапуска, от всех остальных. Этой задаче служит BaselineTopology.

Стоит заметить, что пользователь может задействовать persistent-кэши одновременно с in-memory-кэшами. Последние будут продолжать жить той же жизнью, что и раньше: считать все узлы равноправными и взаимозаменяемыми, начинать перераспределение партиций при выходе узлов для поддержания количества копий данных — BaselineTopology будет регулировать только поведение persistent-кэшей.

BaselineTopology (далее BLT) на самом верхнем уровне — это просто коллекция идентификаторов узлов, которые были сконфигурированы для хранения данных. Как создать BLT в кластере и управлять ею, разберемся чуть позже, а сейчас давайте посмотрим, какая от этой концепции польза в реальной жизни.

Persisted-данные: разъезд запрещен

Проблема распределенных систем, известная как split brain, и без того сложная, при использовании persistence становится еще более коварной.

Простой пример: у нас есть кластер и реплицированный кэш.

Кэши реплицированные и партицированные

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

Произведем над ним простые манипуляции в следующей последовательности:

  1. Остановим кластер и запустим группу узлов A.
  2. Обновим какие-либо ключи в кэше.
  3. Остановим группу A и запустим группу Б.
  4. Применим другие обновления для тех же самых ключей.

image

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

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

Предотвращение этой ситуации — как раз одна из задач BLT.

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

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

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

Таким образом, BaselineTopology поддерживает цепочку хэшей, описывающих состав кластера на момент каждой активации.

На этапах 1 и 3 после запуска групп узлов пользователю придется явно активировать неполный кластер, и каждый online-узел обновит BLT локально, добавив в нее новый хэш. Все узлы каждой группы смогут вычислить одинаковые хэши, но в разных группах они будут разные.

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

Стоит заметить, что этот механизм валидации не даёт полной защиты от конфликтов в ситуации Split-Brain. Если кластер разделился на две половины таким образом, что в каждой половине осталась хотя бы одна копия партиции, и переактивация половин не производилась, то всё равно возможна ситуация, когда в половины поступят конфликтующие изменения одних и тех же данных. BLT не опровергает CAP-теорему, но защищает от конфликтов при явных ошибках администрирования.

Плюшки

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

Плюшка №1 — минус одно ручное действие. Уже упомянутая выше активация должна была выполняться вручную после каждой перезагрузки кластера; средства автоматизации «из коробки» отсутствовали. При наличии BLT кластер может самостоятельно принять решение об активации.

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

image

При первой активации кластера свежесозданная BaselineTopology запоминает, какие узлы должны присутствовать в топологии. После перезагрузки каждый узел проверяет статус других узлов BLT. Как только все узлы окажутся в режиме онлайн, кластер активируется автоматически.

Плюшка №2 — экономия на сетевом взаимодействии. Идея, опять же, основана на допущении, что топология будет оставаться стабильной на протяжении длительного времени. Раньше выход узла из топологии даже на 10 минут приводил к запуску ребалансировки партиций кэшей для поддержания количества бэкапов. Но зачем тратить сетевые ресурсы и замедлять работу кластера, если проблемы с узлом решатся в течение минут, и он снова будет в онлайне. BaselineTopology как раз и оптимизирует это поведение.

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

Управление BaselineTopology

Что ж, один способ нам уже известен: BaselineTopology автоматически создается при самой первой активации кластера. При этом в BLT попадут все серверные узлы, которые на момент активации были в режиме онлайн.

Ручное администрирование BLT осуществляется с помощью control-скрипта из дистрибутива Ignite, подробнее о котором можно почитать на странице документации, посвященной активации кластера.

Скрипт предоставляет очень простой API и поддерживает всего три операции: добавление узла, удаление узла и установка новой BaselineTopology.

При этом если добавление узлов — достаточно простая операция без особых подвохов, то удаление активного узла из BLT — задача более тонкая. Ее выполнение под нагрузкой чревато гонками, в худшем случае — зависанием всего кластера. Поэтому удаление сопровождается дополнительным условием: удаляемый узел должен быть в оффлайне. При попытке удалить online-узел, control-скрипт вернет ошибку и операция не будет запущена.

Поэтому при удалении узла из BLT по-прежнему требуется одна ручная операция: остановка узла. Впрочем, этот сценарий использования явно не будет основным, так что дополнительные трудозатраты не слишком велики.

Java-интерфейс для управления BLT еще проще и предоставляет всего один метод, позволяющий установить BaselineTopology из списка узлов.

Пример изменения BaselineTopology с помощью Java API:

Ignite ignite = /* ... */;
IgniteCluster cluster = ignite.cluster(); // Получаем BaselineTopology.
Collection<BaselineNode> curBaselineTop = cluster.baselineTopology(); for (ClusterNode node : cluster.topology(cluster.currentTopologyVersion())) { // Если мы хотем, чтобы данный узел был в BaselineTopology // (shouldAdd(ClusterNode) - пользовательская функция) if (shouldAdd(node) curTop.add(node);
} // Обновляем BaselineTopology
cluster.setBaselineTopology(curTop);

Заключение

Обеспечение целостности данных — важнейшая задача, которую должно решать любое хранилище данных. В случае распределенных СУБД, к которым относится Apache Ignite, решение этой задачи становится существенно сложнее.

Концепция BaselineTopology позволяет закрыть часть реальных сценариев, в которых целостность данных может нарушиться.

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

Функциональность Native Persistence появилась в проекте совсем недавно, и, без сомнения, будет развиваться, становиться надежнее, производительнее и удобнее в использовании. А вместе с ней будет развиваться и концепция BaselineTopology.

Показать больше

Похожие публикации

Кнопка «Наверх»