Kafka: репликация, Leader, Follower и ISR — Часть 4

Содержание
Коротко: Репликация защищает Kafka от отказов Broker. Leader принимает чтение и запись, Followers синхронизируются, а ISR помогает выбрать актуальную реплику при сбое.

До этого момента мы рассматривали Kafka так, будто каждая Partition хранится только на одном сервере. Для объяснения это удобно. Для production — примерно как хранить единственный бэкап на ноутбуке стажёра.

Но возникает очевидный вопрос.

Что произойдёт, если этот сервер выйдет из строя?

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

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

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

Репликация

Представим кластер из трёх Broker.

Broker 1

Broker 2

Broker 3

И Topic orders, состоящий из одной Partition.

Вместо хранения данных только на одном сервере Kafka создаёт несколько копий.

Partition 0

Broker 1  (Leader)

Broker 2  (Follower)

Broker 3  (Follower)

Количество копий задаётся параметром replication.factor.

Например:

replication.factor=3

означает:

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

Leader

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

Для каждой Partition выбирается один Leader.

Partition 0

Leader
Broker 1

Именно он принимает:

  • все записи;
  • все операции чтения по умолчанию;
  • подтверждения клиентов.

Producer никогда не пишет сразу во все реплики.

Он всегда работает только с Leader.

Follower

Остальные Broker становятся Follower.

Leader
   |
   v
Follower
   |
   v
Follower

Они не принимают записи напрямую.

Вместо этого постоянно копируют изменения с Leader.

Этот процесс происходит непрерывно.

Как только в журнале появляется новое сообщение, Followers начинают его считывать и сохранять у себя.

Как происходит запись

Допустим, Producer отправляет сообщение.

{
  "orderId": 5123,
  "status": "paid"
}

Последовательность будет такой:

Producer
   |
   v
Leader
   |
   v
Follower
   |
   v
Follower

То есть:

  • Producer отправил сообщение Leader.
  • Leader записал его в свой лог.
  • Followers скопировали запись.
  • После этого Producer получил подтверждение, в зависимости от настроек acks.

Очень важно понимать:

Producer никогда не взаимодействует с Followers напрямую.

In-Sync Replicas (ISR)

Не все реплики одинаково полезны.

Представим:

Leader

Offset = 1000

Первый Follower успел догнать Leader.

Follower 1

Offset = 1000

А второй начал отставать.

Follower 2

Offset = 950

Можно ли доверить ему роль нового Leader?

Конечно нет.

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

Он называется ISR (In-Sync Replicas).

ISR

Leader

Follower 1

Follower 2 в список уже не входит.

Только реплики из ISR могут стать новым Leader.

Что считается отставанием

Kafka постоянно сравнивает:

  • насколько реплика отстаёт по Offset;
  • сколько времени прошло с момента последней синхронизации.

Если реплика слишком долго не догоняет Leader, она исключается из ISR.

Но данные продолжает получать.

Как только она полностью синхронизируется, Kafka автоматически вернёт её обратно в ISR.

Что произойдёт при падении Leader?

Представим следующую ситуацию.

Broker 1 (Leader)

X

Сервер отключился.

Producer больше не может записывать сообщения.

Что дальше?

Kafka запускает процедуру выбора нового Leader.

Кто выбирает нового Leader?

В современных версиях Kafka этим занимается Controller.

Это специальная роль внутри кластера, которая следит за состоянием Broker.

Controller замечает:

Leader

Offline

После чего выбирает нового лидера.

Например:

Broker 2
   |
   v
Leader

Причём выбрать можно только Broker из ISR.

Именно поэтому список ISR настолько важен.

Что происходит с Producer?

Producer узнаёт, что старый Leader недоступен.

Получает обновлённые метаданные кластера.

Теперь запись происходит уже сюда:

Producer
   |
   v
Broker 2 (Leader)

Для приложения это обычно занимает доли секунды.

Если всё настроено правильно, пользователь даже не заметит переключения.

А что будет со старым Leader?

Представим, сервер снова заработал.

Broker 1

Online

Он не станет Leader автоматически.

Сначала Kafka догонит его журнал.

Leader

Offset 15234
   |
   v
Broker 1

Offset 15234

После синхронизации он станет обычным Follower.

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

Что такое acks

При записи Producer может выбрать, насколько надёжно Kafka должна сохранить сообщение.

Есть три основных режима.

acks=0

Producer просто отправляет сообщение и сразу продолжает работу.

Producer
   |
   v
Kafka

Никаких подтверждений нет.

Максимальная скорость.

Минимальная надёжность.

Если Broker упал — сообщение потеряно.

acks=1

Самый популярный режим.

Producer ждёт подтверждение только от Leader.

Producer
   |
   v
Leader

OK

Followers могут ещё не успеть получить данные.

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

acks=all

Самый безопасный вариант.

Producer ждёт подтверждение от всех реплик из ISR.

Producer
   |
   v
Leader
   |
   v
Follower
   |
   v
Follower

OK

Только после этого запись считается завершённой.

Даже если Leader сразу выйдет из строя, данные уже существуют на других Broker.

Этот режим обеспечивает максимальную надёжность ценой небольшой дополнительной задержки.

Можно ли потерять сообщения?

Да.

Но только при определённых условиях.

Kafka надёжная, но не волшебная. Если попросить её подтвердить запись слишком рано, она честно подтвердит слишком рано.

Например:

  • используется acks=1;
  • Leader подтвердил запись;
  • Followers ещё не успели получить данные;
  • Leader сразу вышел из строя.

Последние сообщения могут исчезнуть.

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

  • acks=all;
  • достаточный replication.factor;
  • настройки min.insync.replicas, запрещающие подтверждать запись, если в ISR осталось слишком мало реплик.

Почему Kafka выдерживает отказы

Теперь становится понятно, почему Kafka считается одной из самых надёжных систем передачи данных.

Каждая Partition:

  • хранится на нескольких Broker;
  • имеет только одного Leader;
  • автоматически переключается на резервную реплику;
  • использует ISR для защиты от выбора устаревших данных.

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

Что дальше?

Теперь мы понимаем, как Kafka хранит данные и защищает их от потери.

Но остаётся ещё один вопрос.

Почему Kafka способна обрабатывать миллионы сообщений в секунду, тогда как многие другие брокеры начинают заметно замедляться при высокой нагрузке?

В следующей части разберём, откуда берётся скорость: последовательная запись на диск, Page Cache, пакетная передача данных (Batching), Zero Copy и другие инженерные решения. Там будет меньше магии и больше уважения к файловой системе.