# Raft и отказоустойчивость

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

Raft предполагает, что в кластере всегда существует явно выделенный
лидер (`leader`). Только он отправляет новые записи на другие узлы
кластера. Если обычный узел (`follower`) долго не получает сообщений от
лидера, то он переходит в состояние "кандидат" (`candidate`) и проводит
процедуру голосования.

## Динамическое переключение голосующих узлов в Raft (Raft voter failover) {: #raft_voter_failover }

Все узлы Raft в кластере делятся на два типа: голосующие (`voter`) и
неголосующие (`learner`). За консистентность raft-группы отвечают только
первые. Для применения каждой записи требуется собрать кворум из `N/2 +
1` голосующих узлов. Неголосующие узлы в кворуме не участвуют и всегда
находятся в состоянии `follower`.

Чтобы сохранить баланс между надежностью кластера и удобством его
эксплуатации, в Picodata предусмотрено автоматическое распределение
голосующих узлов. Количество голосующих узлов в кластере не настраивается
и зависит только от количества инстансов из [тиров] со свойством
`can_vote`, которое является полем системной таблицы [`_pico_tier`].

[тиров]: ../overview/glossary.md#tier
[`_pico_tier`]: system_tables.md#_pico_tier

Зависимость количества голосующих узлов в Raft от количества инстансов
из тиров со свойством `can_vote`:

- 1 инстанс — 1 голосующий узел;
- 2 инстанса — 2 голосующих узла;
- 3 или 4 инстанса — 3 голосующих узла;
- 5 и более инстансов — 5 голосующих узлов;

Если один из голосующих узлов становится недоступным
или прекращает работу (что может нарушить кворум в Raft), то тип `voter`
автоматически присваивается одному из доступных и подходящих
для голосования узлов.
Переключение происходит незаметно для пользователя.

## Пример распределения голосующих узлов {: #voters_distribution_example }

Приведем пример кластера с одним уровнем распределения узлов между
локациями. Пусть это будет два датацентра (`MSK`, `SPB`) и третья
локация для арбитража (решающего голоса в случае потери сетевой
связности между датацентрами). Вне зависимости от общего числа узлов в
кластере предполагается наличие всего 5 голосующих узлов, которые, в
данном случае, распределятся так:

- 2 в локации `MSK`;
- 2 в локации `SPB`;
- 1 в третьей локации.

Если весь датацентр в локации `SPB` теряет доступность и связь с арбитром,
то его 2 голосующих узла перемещаются в датацентр локации `MSK`. При
восстановлении связности, голосующие узлы возвращаются обратно и
исходная конфигурация восстанавливается.

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

С точки зрения надежности хранения данных, в кластере лучше иметь
нечетное число узлов (3, 5...) — именно при таком подходе при выходе из
строя части узлов оставшиеся смогут составить большинство (и кворум).

См. также:

- [Репликация и зоны доступности](../tutorial/deploy.md#failure_domains)

## Использование тиров для повышения отказоустойчивости {: #tier_based_failover }

Тиры позволяют более выгодно использовать вычислительные ресурсы
кластера: таблицы с данными разных типов можно создавать на тирах с
оптимальным фактором репликации и нужным числом бакетов. Помимо этого,
правильная установка параметра `can_vote` для тира имеет значение для
повышения отказоустойчивости кластера. Вычислительная нагрузка на узлы,
участвующие в raft-кворуме (raft-лидер и остальные голосующие узлы),
существенно влияет на соблюдение таймаутов на запись данных о состоянии
кластера в глобальные таблицы. Поэтому, для повышения надежности
промышленного кластера имеет смысл использовать минимум два тира.
Голосующие инстансы следует сгруппировать в отдельный тир с параметром
[`can_vote = true`] и убедиться, что на него не попадут шардированные
таблицы с данными  и сервисы плагинов. Для тира с голосующими инстансами
нет смысла использовать [репликацию], поэтому рекомендуется установить для
него также параметр `replication_factor: 1`. Все остальные инстансы
следует распределить в один или несколько других тиров с параметром
`can_vote = false` и использовать для хранения и обработки шардированных
данных и работы плагинов, а также, если необходимо, использовать параметр
`replication_factor: X`, где `X` ≥ 2.

[`can_vote = true`]: ../reference/config.md#cluster_tier_tier_can_vote
[репликацию]: ../overview/glossary.md#replication_factor
