Apache Kafka 3.1 и KRaft: разворачиваем кластер без ZooKeeper в продакшне
KRaft-режим Kafka 3.1 рекомендован для новых продакшн-установок. Разворачиваем тестовый кластер, убираем ZooKeeper из схемы и проверяем совместимость с существующими producer/consumer.
Apache Kafka 3.1 (январь 2022): KRaft-режим достиг production-ready для новых кластеров без ZooKeeper
ZooKeeper в Kafka-стеке - это отдельный разговор. Не потому что он плохой, а потому что каждый, кто хоть раз поднимал Kafka в продакшне, знает: у тебя теперь два кластера вместо одного. Kafka-брокеры + ZooKeeper-ансамбль. Отдельный мониторинг, отдельная конфигурация, отдельные точки отказа. Kafka 3.1, вышедшая в январе, объявила KRaft-режим production-ready для новых установок - и мы решили разобраться, что это значит на практике.
Что такое KRaft и почему это важно
KRaft (Kafka Raft Metadata mode) - это реализация консенсусного протокола Raft прямо внутри Kafka, без ZooKeeper. Идея простая: Kafka сама хранит метаданные о топиках, партициях и брокерах, используя внутренний лог и кворум контроллеров.
До версии 3.1 KRaft был помечен как экспериментальный. Теперь Apache-проект официально рекомендует его для новых продакшн-кластеров. Важная оговорка: для миграции существующих кластеров с ZooKeeper инструментарий ещё не готов - речь именно про новые установки.
Что меняется архитектурно:
- Без ZooKeeper. Три-пять нод ансамбля ZooKeeper уходят из схемы. Один тип инфраструктуры вместо двух.
- KRaft-контроллеры. Выделенные контроллер-ноды (или совмещённые broker+controller) хранят метаданные в специальном топике
__cluster_metadata. - Быстрее восстановление после сбоя. ZooKeeper-режим при перезапуске читал метаданные из ZooKeeper нелинейно; KRaft реплицирует их как обычный лог.
Разворачиваем тестовый кластер 3.1
Взяли три ноды: каждая работает в режиме broker+controller (роль broker,controller в конфиге). Это допустимо для небольших кластеров - для крупных имеет смысл разделить роли.
Ключевые параметры server.properties:
process.roles=broker,controller
node.id=1
controller.quorum.voters=1@node1:9093,2@node2:9093,3@node3:9093
listeners=PLAINTEXT://:9092,CONTROLLER://:9093
inter.broker.listener.name=PLAINTEXT
controller.listener.names=CONTROLLER
log.dirs=/var/kafka/data
Перед первым стартом обязательно генерируем кластерный UUID и форматируем хранилище:
KAFKA_CLUSTER_ID=$(kafka-storage.sh random-uuid)
kafka-storage.sh format -t $KAFKA_CLUSTER_ID -c server.properties
Этот шаг обязателен - без форматирования брокеры не поднимутся. UUID должен быть одинаковым на всех трёх нодах.
Проверяем совместимость producer/consumer
Тут была главная часть упражнения. У нас есть несколько pipeline'ов, которые пишут в Kafka и читают из неё: инжест событий из нескольких источников, потоковая обработка через Kafka Streams, чтение в ClickHouse через kafka-движок.
Результат: producer и consumer не заметили разницы. Клиентский протокол Kafka не изменился - KRaft это изменение внутри кластера, не на уровне API. Java-клиенты версий 2.x и 3.x работают без каких-либо изменений в конфигурации приложений. ClickHouse kafka-движок тоже подключился без вопросов - он работает через стандартный Kafka-протокол.
Единственное, на что нужно обратить внимание: в новом кластере нет zookeeper.connect в конфиге брокеров, и если у вас есть клиентский код, который явно обращается к ZooKeeper (старые скрипты, legacy-утилиты), он, понятно, работать не будет. Но это и есть суть изменения.
Операционные наблюдения
Несколько вещей, которые стоит знать до того, как идти в продакшн.
Инструменты. Часть административных утилит Kafka ещё имеет аргументы --zookeeper. В KRaft-режиме они не работают, нужно использовать --bootstrap-server. Большинство современных утилит уже поддерживают оба варианта, но старые скрипты придётся пересмотреть.
Метрики. ZooKeeper-специфичные метрики, которые были в мониторинге, становятся неактуальными. Вместо них смотрим на метрики контроллера: kafka.controller:type=KafkaController,name=ActiveControllerCount и связанные. Grafana-дашборды для KRaft-кластеров пока менее распространены - пришлось адаптировать существующий.
Логи. В KRaft-режиме активнее используется __cluster_metadata топик. Его нужно мониторить как любой системный топик - не трогать руками и следить за репликацией.
Кворум контроллеров. Три контроллера - минимум для отказоустойчивости. При потере одного из трёх кластер продолжает работать, при потере двух - нет. Это то же поведение, что у ZooKeeper-ансамбля.
Где сейчас
Тестовый кластер 3.1 в KRaft-режиме работает вторую неделю. Нагрузку гоняли близкую к продакшновой: несколько тысяч сообщений в секунду, несколько топиков, consumer groups. Проблем не обнаружили.
Для существующих продакшн-кластеров на ZooKeeper менять ничего не будем - нет инструмента миграции, нет и смысла рисковать. Но следующий новый кластер для аналитической инфраструктуры поднимем уже на KRaft: схема стала проще, и это само по себе веский аргумент.
Надо отметить, что ClickHouse в апреле сделал похожий шаг со своим Keeper - тоже убирает ZooKeeper из стека, но другим способом. Тренд понятен: зависимость от ZooKeeper в стриминговых и аналитических системах постепенно уходит.