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

Raft был предложен Диего Онгаро и Джоном Оустерхаутом в 2014 году как более понятная альтернатива Paxos. Авторы поставили цель: создать алгоритм консенсуса, который легко понять и правильно реализовать. Результат — де-факто стандарт для систем вроде etcd, CockroachDB, TiKV и Consul.

Что такое консенсус в распределённых системах?

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

  • Узлы могут выходить из строя и восстанавливаться
  • Сеть между узлами может задерживать или теряла сообщения
  • Нельзя заранее знать, упал ли узел или просто замедлился
  • Система должна продолжать работу при отказе меньшинства узлов

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

Три ключевых компонента Raft

1. Выборы лидера

Raft разделяет время на термы (terms) — монотонно возрастающие целые числа. Каждый терм начинается с выборов: один или несколько узлов становятся кандидатами и запрашивают голоса у остальных. Узел становится лидером, если получает голоса от большинства (⌊N/2⌋ + 1 узлов).

"Raft гарантирует, что в один момент времени может быть только один лидер в пределах данного терма — именно это делает алгоритм безопасным."

Последователи переходят в состояние кандидата, если не получили heartbeat от лидера в течение случайного интервала (election timeout). Случайность необходима, чтобы избежать одновременного старта выборов несколькими узлами.

2. Репликация журнала

Лидер принимает все записи от клиентов. Каждая запись сначала добавляется в локальный журнал лидера, затем отправляется последователям через RPC AppendEntries. Когда большинство узлов подтвердили запись, она считается «закреплённой» (committed) и применяется к машине состояний.

Диаграмма журнала репликации Raft: пять строк журнала с индексами и термами, закрашенные ячейки обозначают закреплённые записи, пустые — незакреплённые
Структура журнала репликации: каждая запись содержит индекс, терм и команду

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

3. Безопасность

Raft гарантирует свойство «безопасности лидера»: если запись закреплена в данном терме, она будет присутствовать в журналах всех будущих лидеров. Это достигается ограничением: узел может получить голос только если его журнал «не хуже» журнала голосующего.

Практическое применение: etcd и Kubernetes

etcd — основное хранилище состояния Kubernetes — построен на Raft. Каждое изменение ресурса в кластере (создание пода, обновление ConfigMap) сначала реплицируется через Raft на большинство узлов etcd, и только потом Kubernetes API Server сообщает клиенту об успехе.

Это означает: при потере связи с большинством etcd-узлов, запись в кластер Kubernetes прекратится. Доступность приносится в жертву ради согласованности — типичный CP-выбор в терминах CAP-теоремы.

Raft против Paxos: в чём реальное различие?

Paxos — более старый алгоритм, математически эквивалентный Raft по гарантиям безопасности. Ключевое отличие — в декомпозиции. Raft явно разделяет выборы лидера, репликацию журнала и безопасность на независимые подзадачи. Paxos описывает только консенсус для одного значения, а Multi-Paxos для журнала — уже неформальное расширение, реализованное по-разному в разных системах.

Исследование авторов Raft показало, что студенты, изучившие оба алгоритма, значительно лучше отвечали на вопросы по Raft. Это не значит, что Paxos хуже — но инженерная ценность понятности высока: меньше ошибок в реализации, проще код-ревью, быстрее онбординг.

Ограничения и когда Raft не подходит

Raft оптимален для кластеров из 3–7 узлов. При большем количестве задержки выборов и стоимость репликации на большинство могут стать заметными. Для масштабов в сотни узлов лучше рассматривать иерархические или партиционированные подходы.

Raft также не решает задачу Byzantine fault tolerance: он предполагает, что узлы могут упасть, но не могут вести себя злонамеренно. Для систем, требующих защиты от компрометации узла, необходимы PBFT или аналогичные BFT-алгоритмы.

Поделиться: