ADG Оставить заявку
Блог Интеграции 5 мин чтения

Apache Kafka 4.0: мигрируем последний кластер клиента с ZooKeeper на KRaft

Kafka 4.0 убрала ZooKeeper из дистрибутива. Документируем процедуру миграции, подводные камни с consumer-группами и rollback-сценарий для production.

Контекст момента

Apache Kafka 4.0: KRaft-режим объявлен единственным поддерживаемым, ZooKeeper убран из дистрибутива

С выходом Kafka 4.0 разработчики закрыли вопрос, который висел несколько лет: ZooKeeper убран из дистрибутива, KRaft теперь единственный поддерживаемый режим. Для большинства команд это просто новость для changelog. У нас в работе оставался один кластер клиента, который до последнего держался на ZooKeeper - хотели дождаться большей зрелости KRaft. Дождались. Фиксируем, как прошла миграция, что укусило, и как мы готовили откат.

Контекст кластера

Кластер - шесть брокеров, партиции разнесены по двум стойкам, retention по некоторым топикам - несколько суток. Consumer-групп штук двадцать, несколько из них критичные: обрыв обработки даже на минуту виден в бизнес-метриках клиента. ZooKeeper - ансамбль из трёх нод, отдельные VM, работал стабильно, поводов жаловаться не было. Именно поэтому клиент и не торопился мигрировать: «работает - не трогай».

Kafka 4.0 сделала трогание неизбежным. Оставаться на 3.x с ZooKeeper - это оставаться без security-патчей и без новых фич навсегда.

Подготовка: что делали до начала

Неделю до миграции потратили на подготовку, и это того стоило.

Инвентаризация consumer-групп. kafka-consumer-groups.sh --list даёт список, но не состояние. Прошлись по каждой группе через --describe, зафиксировали текущие offsets и lag. Оказалось, что три группы имеют ненулевой lag постоянно - не из-за проблем, а по архитектуре: они обрабатывают исторические данные в фоне. Это важно знать заранее, иначе после миграции непонятно - lag был до, или это артефакт перехода.

Snapshot метаданных ZooKeeper. Выгрузили все пути /brokers, /consumers, /config через zookeeper-shell.sh, положили в git. Скорее как страховка для сверки, чем как реальный механизм отката.

Прогон на стейджинге. Развернули уменьшенную копию кластера, прошли процедуру полностью. На стейджинге и поймали первый подводный камень - об этом ниже.

Ansible-плейбуки для отката. Подготовили процедуру возврата на случай если что-то пойдёт не так после первых двух брокеров. Откат после полного перехода всего кластера - уже отдельная история, которую лучше не допускать.

Сама процедура миграции

Официальный путь для миграции с ZooKeeper на KRaft - kafka-storage.sh с командой format и специальный migration-режим, где кластер временно работает в dual-mode: брокеры регистрируются и в ZooKeeper, и в KRaft-контроллерах одновременно. Это позволяет мигрировать брокеры по одному без полной остановки.

Порядок действий в общих чертах:

  • Поднять KRaft-контроллеры (в нашем случае - три отдельные VM, не совмещённые с брокерами)
  • Перевести кластер в migration-режим через kafka-features.sh --enable
  • Переключать брокеры по одному, наблюдая за состоянием партиций
  • Дождаться полной синхронизации метаданных в KRaft
  • Финализировать миграцию, отключить ZooKeeper-режим
  • Вывести ZooKeeper из эксплуатации

На стейджинге всё прошло чисто. В production пошло почти чисто - но «почти» сыграло.

Подводный камень с consumer-группами

После переключения третьего брокера (из шести) две consumer-группы начали вести себя странно: lag начал расти, хотя consumers продолжали коммитить offsets. В логах брокеров - сообщения про rebalance. Сами consumers при этом не упали, координатор группы переехал на другой брокер в момент переключения.

Корень проблемы: при migration-mode переключение брокера - это фактически graceful restart, и coordinator-партиция для двух групп жила именно на переключаемом брокере. После перехода координатор переехал, но несколько in-flight offset commit-ов потерялись в процессе переезда. Consumers это не заметили - они получили OFFSET_COMMIT_SUCCESS, но на новом координаторе эти offsets не появились. Классический split-brain окно на несколько секунд.

В итоге lag был ложным: реальные offsets на несколько сотен сообщений отстали от того, что consumers считали закоммиченным. Обработки без дублей не случилось бы - consumers пошли бы перечитывать уже обработанное.

Обнаружили это потому, что мониторили lag в реальном времени и у нас была базовая линия из подготовительной инвентаризации. Без неё могли пропустить.

Решение: принудительный rebalance проблемных групп после переключения каждого брокера - kafka-consumer-groups.sh --reset-offsets не нужен, достаточно дождаться стабильного состояния координатора (несколько минут) прежде чем переключать следующий брокер. Добавили паузу в плейбук между переключениями.

Rollback-сценарий

В migration-mode откат возможен пока не выполнена финализация. Пока кластер в dual-mode, ZooKeeper-ансамбль работает параллельно и содержит актуальные метаданные. Откат - это перевод брокеров обратно в ZooKeeper-only режим и отключение KRaft-контроллеров.

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

ZooKeeper-ансамбль выключили через сутки после финализации - дали запас на случай если что-то вылезет. Пока он стоял - психологически спокойнее.

Состояние на сейчас

Кластер работает на KRaft третью неделю. Поведение стабильное, latency брокеров в норме, consumer-группы не испытывают аномальных rebalance-ов. KRaft-контроллеры ведут себя тихо - в хорошем смысле, просто работают.

Одно неожиданное плюс: мониторинг немного упростился. ZooKeeper требовал отдельного набора метрик и отдельных алертов - теперь это выпало из картины, метаданные кластера видны через стандартный Kafka JMX без обращения к отдельному сервису.

Если у вас остались кластеры на ZooKeeper и вы занимаетесь интеграциями на базе Kafka - миграцию лучше делать сейчас, пока 3.x ещё есть рядом как ориентир. Процедура рабочая, но без тщательной подготовки и мониторинга consumer-групп в процессе - можно получить сюрпризы именно там, где казалось всё прозрачно.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.