Управление топологией¶
Общие сведения¶
Топологией кластера в Picodata называется совокупность конфигураций инстансов и репликасетов, связей между ними, их состояний относительно друг друга. Picodata хранит эту информацию в глобальных таблицах, содержимое которых реплицируется на все узлы посредством алгоритма Raft.
Важной составляющей топологии является информация о стейтах всех
узлов. Данный термин является специфичным для Picodata. Он отражает не
состояние самого инстанса, а конфигурацию остальных участников кластера
по отношению к нему. Существуют две разновидности стейтов: текущий
(current_state
) и целевой (target_state
).
Управление топологией в Picodata происходит за счет последовательного
изменения стейтов: сначала меняется значения target_state
,
затем это значение задается в current_state
.
Изменение target_state
происходит в следующих ситуациях:
- запуск инстанса (
target_state = Online
) - штатное выключение инстанса (
target_state = Offline
) - аварийное переключение (
target_state = Offline
) - удаление инстанса из кластера (
target_state = Expelled
)
Конфигурацией инстансов и обновлением current_state
централизованно
управляет raft-лидер. По мере
появления изменений target_state
, он применяет изменения к остальным
инстансам кластера (к каждому в отдельности) и обновляет
current_state
. Реализует эту логику компонент governor
.
Изменить current_state
может только лидер при поддержке кворума, что
гарантирует консистентность принятого решения (и поддерживает доверие к
системе в плане отказоустойчивости).
Все изменения стейтов в кластере регистрируются в журнале аудита.
Сценарии управления топологией¶
Присоединение (joining) инстанса к кластеру¶
Добавление нового инстанса в работающий кластер происходит по следующему сценарию:
- Администратор лично или средствами автоматизации запускает новый инстанс командой picodata run
- Инстанс определяет, что рабочие файлы инстанса в начале жизненного цикла отсутствуют
- Инстанс выполняет алгоритм discovery — связывается с другими узлами из параметра picodata run --peer и определяет адрес текущего raft-лидера
- Инстанс отправляет raft-лидеру запрос proc_raft_join, содержащий
- его сетевой адрес
advertise_address
- домен отказа
failure_domain
- тир
tier
- также, опционально можно явно передать
instance_id
,replicaset_id
- его сетевой адрес
- raft-лидер, получив этот запрос, выполняет ряд транзакций в глобальные
таблицы:
- если переданного тира нет в таблице
_pico_tier
, запрос отклоняется - если требуется,
INSERT ... INTO _pico_replicaset
- если
instance_id
передан явно и уже добавлен в кластер, проверяет возможность автоматически его удалить - генерирует
raft_id
для инстанса, никому другому ранее не принадлежавший - инициализирует
current/target_state = Offline
INSERT ... INTO _pico_peer_address
INSERT ... INTO _pico_instance
- если переданного тира нет в таблице
- инстанс инициализирует локальную БД и актуализирует свое состояние относительно других реплик
Штатное выключение инстанса¶
Чтобы выключение инстанса прошло штатно и не имело негативных последствий, Picodata обеспечивает соблюдение следующих условий:
- инстанс не должен оставаться голосующим, если можно его заменить другим
- инстанс не должен оставаться raft-лидером
При срабатывании триггера on_shutdown
инстанс сначала отправляет
лидеру запрос на изменение target_state = Offline
. Завершение работы
происходит после того, как будет применено соответствующее изменение
current_state
.
Логика изменения собственного target_state
до Offline
реализована в
алгоритме sentinel
.
Максимальное время ожидания составляет 3 с и не настраивается. По истечении времени инстанс в любом случае завершает свою работу.
Аварийное переключение¶
За обслуживание отказов инстансов также отвечает raft-лидер и алгоритм
sentinel
, который при обнаружении
отказа инициирует изменение target_state = Offline
.
Критерием отказа является невозможность доставки raft-сообщений в течение 5 секунд.
Governor — централизованное управление кластером¶
Большинство механизмов, связанных с отказоустойчивостью в Picodata, так или иначе
связаны с компонентом governor. С технической точки зрения governor — это
поток управления (fiber), всегда выполняющийся на raft-лидере.
Губернатор действует в два этапа. По данным из системных таблиц, которые отражают
состояние кластера, генерируется событие. Например, лидер некоторого репликасета имеет target_state
= Offline
.
Второй этап - реакция на событие, при этом все необходимые действия, предпринимает также губернатор.
Например в случае с недоступностью лидера репликасета, необходимые вызовы RPC, а также записи в глобальные таблицы
будет делать непосредственно губернатор.
Доступность инстансов¶
Инстанс называется доступным или логически доступным, если его
целевой стейт (target_state
) не равен Offline
или Expelled
.
Физическая доступность хоть и связана с этим понятием, но это не одно и
то же. Например, инстанс, адрес которого стал аргументом команды
picodata expel
, некоторое время будет
считаться логически недоступным, несмотря на его физическую доступность.
Доступный инстанс может участвовать в raft-голосовании и быть назначенным в лидеры как репликасета, так и raft-группы. Соответственно, недоступный инстанс такую роль играть не может.
Автоматическое назначение мастеров репликасетов¶
Picodata следит за тем, чтобы в каждом репликасете была ровно одна мастер-реплика. Для этого для губернатора реализован алгоритм автоматического переключения мастера, срабатывающий в том случае, если мастер-реплика потеряла связь с кластером. Этот алгоритм, разбит на 2 шага, что увеличивает его надежность, а также позволяет администратору БД использовать его для ручного переключения мастера в репликасете.
Первым шагом губернатор ищет репликасет, мастер которого недоступен. Найдя такой репликасет, губернатор выбирает в нем нового кандидата на роль мастера. На момент написания этих строк, единственный критерий, по которому делается выбор, такой: инстанс должен быть доступен. Однако, в будущем могут быть добавлены дополнительные критерии.
В конце первого шага губернатор изменяет запись в глобальной таблице
_pico_replicaset для
выбранного репликасета, где в поле target_master_id
указывается
идентификатор инстанса, ставшего новым мастером.
Вторым шагом губернатор находит в таблице _pico_replicaset
запись с несовпадающими полями target_master_id
и current_master_id
. Такая ситуация возможна либо после
выполнения первого шага алгоритма, либо после ручного назначения мастера администратором.
В случае, если текущий мастер репликасета доступен для связи, губернатор отправляет ему запрос на перевод в режим "только для чтения", и получает от него в ответ его текущее значение vclock. Дальше отправляется запрос новому мастеру на перевод его в активный режим. Здесь, при наличии значения vclock от предыдущего мастера, оно используется для синхронизации перед тем как инстанс станет доступен для записи, что предотвращает потенциальную потерю данных.
Стоит заметить, что в случае потери связи с текущим мастером, синхронизация не происходит, и потеря данных из реплицируемых асинхронно таблиц все таки может произойти.
В конце этого шага губернатор обновляет запись в таблице _pico_replicaset,
актуализируя значения колонок current_master_id
и promotion_vclock
.
Стоит заметить, что второй шаг, если имеется возможность, выполняется в первую очередь. Губернатор не начинает поиск нового кандидата в мастеры репликасета, пока есть хотя бы один репликасет с целевым мастером, который отличается от текущего.
Автоматическое назначение весов шардирования¶
Picodata следит за тем, чтобы репликасеты содержали количество реплик не ниже чем фактор репликации соответствующего тира. До тех пор пока это условие не будет выполнено, данные на такой репликасет подаваться не будут. Технически это реализовано при помощи так называемых весов шардирования, за актуальностью которых следит губернатор.
Вес шардирования определяет то, какая пропорция бакетов со всего кластера должна быть распределена на данный репликасет по сравнению с остальными. Изначально все добавляемые репликасеты в Picodata имеют нулевой вес, что означает, что данные на них поступать не будут. И только после того, как в репликасете окажется достаточно реплик, губернатор автоматически установит ему ненулевой вес, тем самым запустив в работу подсистему vshard, отвечающую за перераспределение бакетов.
Первичное распределение бакетов¶
Репликасеты в Picodata начинают свое существование с нулевым весом и только в какой-то определенный момент жизненного цикла кластера появляется первый репликасет с ненулевым весом, на который можно распределять бакеты. Для этого у губернатора есть специальный шаг, который выполняется не больше одного раза за жизнь кластера.
Автоматическое изменение конфигурации vshard¶
Во время нормальной работы кластера Picodata возможно динамическое изменение топологии, как штатное, так и не очень: инстансы и репликасеты могут добавляться, связь между ними может пропадать. При этом Picodata поддерживает безотказный доступ к данным через распределенный SQL. Для этого все инстансы должны знать информацию о конфигурации кластера, а также своевременно обновлять состояние подсистемы vshard.
Триггерами для изменения конфигурации vshard служат почти все изменения топологии — например, добавление нового инстанса, или возвращение в строй инстанса, потерявшего связь с кластером на какое-то время; а также изменения весов шардирования (см. параграф выше). Как только губернатор обнаруживает такое изменение, он обновляет запись о целевой конфигурации vshard в глобальной системной таблице, что обеспечивает отказоустойчивость такого изменения: если raft-лидер выйдет из строя, на его замену будет избран новый, который продолжит выполнять алгоритм губернатора с того места, где остановился предыдущий.
Следующим шагом губернатор обнаруживает несовпадение текущей и целевой конфигураций vshard и приступает к ее актуализации, отправляя запрос на все инстансы кластера одновременно. Если хотя бы от одного инстанса не будет получен положительный результат, этот шаг повторяется.
Автоматическое переключение узлов, голосующих в raft¶
Governor следит за выполнение ограничений, описанных здесь.
Применение изменений кластерной схемы данных¶
Governor гарантирует отказоустойчивость изменений кластерной схемы данных. Подробнее алгоритм описан здесь.