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

Kafka 3.8: tiered storage в GA и закрываем последний ZooKeeper-кластер

Apache Kafka 3.8 переводит tiered storage в GA, KRaft без ZooKeeper - единственный поддерживаемый режим. Документируем финальную миграцию своего последнего ZK-кластера.

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

Apache Kafka 3.8 выходит: tiered storage переходит в GA, KRaft без ZooKeeper объявлен единственным поддерживаемым режимом

Kafka 3.8 вышла в начале октября, и в этом релизе два важных события произошли одновременно: tiered storage перешёл из preview в GA, и ZooKeeper-режим официально объявлен единственным несовместимым с дальнейшим развитием продукта - то есть KRaft без ZooKeeper теперь не опция, а требование. Для нас это стало последним пинком завершить то, что висело с весны: перевести последний оставшийся ZK-кластер на KRaft.

Почему он вообще оставался - история банальная. Тот кластер живёт в контуре заказчика с достаточно консервативным change management, и каждое окно на плановое обслуживание там расписано за месяц вперёд. Kafka 3.7 дала нам хороший аргумент начать готовить документацию. 3.8 дала аргумент получить окно и наконец сделать.

Что поменялось в 3.8 по tiered storage

Функция работала в preview начиная с 3.6. В GA изменилось не только маркетинговое название - доработали несколько критичных вещей:

Стабилизировали форматы internal-топиков. В preview версиях metadata-топики tiered storage могли поменять формат между релизами. GA гарантирует обратную совместимость формата - можно обновляться без сброса remote-данных.

Улучшена обработка rebalance при недоступности remote storage. Раньше при временной недоступности S3/объектного хранилища брокер мог застрять в бесконечных retry-циклах и блокировать leader election. В 3.8 добавлена configurable backoff-логика с circuit breaker-поведением.

Quota-метрики для remote reads. Появились отдельные метрики для чтения из remote tier - раньше всё сваливалось в общий fetch-metric, и понять откуда именно читает consumer было нетривиально.

Tiered storage мы пока не раскатываем у заказчиков в production - интересно, но требует отдельного решения для remote storage в их контуре. Фиксируем как "GA достигнут, можно планировать пилот".

Финальная миграция ZK-кластера на KRaft: процедура

Кластер небольшой по меркам Kafka: пять брокеров, три ZooKeeper-ноды, несколько десятков топиков, реальная нагрузка в продакшне. Миграция - rolling, без остановки продюсеров и консьюмеров. Версия до миграции - Kafka 3.6 с ZooKeeper 3.7.

Процедура в целом хорошо описана в официальной документации через kafka-storage.sh migrate-to-kraft, но документация не покрывает несколько моментов, которые всплыли на практике.

Шаг 1: проверка совместимости metadata версии. Запускаем kafka-metadata-quorum.sh --bootstrap-server :9092 describe --status и смотрим на MetadataVersion. Для 3.8 нужна версия не ниже 3.3-IV0. У нас была 3.3-IV2, всё чисто.

Шаг 2: генерация cluster ID. В KRaft-режиме cluster ID хранится в KRaft-логе, а не в ZooKeeper. Генерируем: kafka-storage.sh random-uuid. Этот ID пойдёт во все kafka-storage.sh format команды для KRaft-контроллеров.

Шаг 3: поднимаем KRaft-контроллеры как отдельный процесс. Здесь у нас не combined режим (controller + broker в одном), а разделённый. Три KRaft-контроллера на тех же машинах, где были ZK-ноды, но на других портах. Форматируем KRaft-лог на каждом, прописываем process.roles=controller, запускаем.

На этом шаге был первый сюрприз: один из контроллеров отказался стартовать с ошибкой KRaft controller quorum needs majority to be available. Оказалось, мы опечатались в controller.quorum.voters - перепутали один IP. Пять минут отладки, исправили, подняли.

Шаг 4: команда миграции. На каждом брокере по очереди:

  • Останавливаем брокер
  • Добавляем в конфиг zookeeper.metadata.migration.enable=true и указываем KRaft-контроллеры через controller.quorum.voters
  • Стартуем брокер

При старте первого брокера в migration mode он начинает синхронизировать metadata из ZooKeeper в KRaft-лог. Это занимает несколько минут в зависимости от количества топиков и партиций. Следить можно через kafka-metadata-quorum.sh describe --status - там появляется поле MigrationState.

Шаг 5: проверка consumer group lag до и после каждого брокера. Это, пожалуй, самое важное место. Мы смотрели lag через kafka-consumer-groups.sh --bootstrap-server :9092 --all-groups --describe и фиксировали текущее состояние перед перезапуском каждого брокера. После рестарта - ждём пока lag вернётся к исходному уровню (или к нулю, если consumers активны) и только потом идём к следующему брокеру.

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

Шаг 6: финализация. Когда все брокеры перезапущены в migration mode и MigrationState показывает MIGRATION_COMPLETE, убираем ZK-конфиг из брокеров, делаем ещё один rolling restart уже в чистом KRaft-режиме. ZK-ноды останавливаем последними.

Весь процесс занял около трёх часов на пять брокеров. Downtime для продюсеров и консьюмеров - ноль: rolling restart по одному брокеру, topic replication factor 3, клиенты переключались на живые брокеры без потерь.

Откат: когда и как

Откат возможен только до финализации - пока ZK ещё работает и брокеры в migration mode. Если что-то пошло не так на этапе 4 или 5: останавливаем миграцию, убираем zookeeper.metadata.migration.enable из конфига проблемного брокера, возвращаем его в чистый ZK-режим. KRaft-контроллеры при этом можно оставить запущенными - они безвредны пока брокеры с ними не общаются.

После MIGRATION_COMPLETE и финального rolling restart откат уже невозможен. Именно поэтому важно делать полный снапшот ZK-данных и конфигов перед стартом - на случай если нужно будет поднять кластер с нуля из бэкапа.

Где сейчас

Кластер работает на KRaft уже неделю, ZK-ноды остановлены. Мониторинг штатный, consumer lag в норме, инцидентов не было. Tiered storage пока не включаем - это следующий разговор с заказчиком о том, куда класть remote tier в их инфраструктуре.

Работу по интеграции и миграции Kafka-кластеров мы ведём регулярно, но "последний ZooKeeper-кластер" - всё-таки приятная отметка. Осталось убедить ещё пару заказчиков, что откладывать это до 4.x - не лучшая идея.

Контакт

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

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