Kafka 4.0 без ZooKeeper: как мы мигрировали production-кластер на KRaft и что пошло не так с мониторингом
Перевели production-кластер Kafka с ZooKeeper на KRaft до выхода 4.0: рассказываем о реальном downtime, проблемах с мониторингом и нюансах живой миграции.
Apache Kafka 4.0 - выход без ZooKeeper, только KRaft - финальный переход на новую архитектуру
Apache Kafka 4.0 вышла без ZooKeeper. Совсем. Если у вас кластер на 3.x с ZooKeeper - к 4.0 нужно мигрировать или остаться на ветке 3.x. Мы решили не ждать финального дедлайна и прошли миграцию на одном из production-кластеров заранее, ещё на Kafka 3.7. Делимся тем, что реально произошло.
Зачем вообще KRaft
Для тех, кто смотрит на это впервые: ZooKeeper в Kafka - это отдельный кластер (обычно 3 ноды) для хранения метаданных: топиков, партиций, ISR, конфигурации брокеров. Исторически это была правильная идея - взять готовый координатор вместо написания своего. Но со временем ZooKeeper стал главной операционной болью: отдельный мониторинг, отдельный хип JVM, отдельные требования к latency между нодами, отдельные версии, которые надо обновлять.
KRaft (Kafka Raft) - встроенный механизм консенсуса, где метаданные живут внутри самой Kafka в выделенных нодах-контроллерах. Идея не новая - KIP-500 появился в 2019-м, но до production-готовности без ZooKeeper дошли только к 3.3-3.5. В 4.0 ZooKeeper-режим убрали окончательно.
Как выглядел наш кластер
У нас кластер для одного из заказчиков: ETL-пайплайн, данные от нескольких источников идут через Kafka в ClickHouse. Не огромный - 6 брокеров, около 200 топиков, несколько десятков активных consumer group. ZooKeeper на 3 нодах, живёт на тех же VM, что и брокеры - что само по себе не лучшая практика, но сложилось исторически.
Kafka 3.6. Решение мигрировать на KRaft пришло не из любви к новому, а из конкретного раздражения: два инцидента за полгода, оба - из-за ZooKeeper session timeout при плановом обслуживании нод.
Сам процесс миграции
Kafka 3.x поддерживает миграцию с ZooKeeper на KRaft без полной остановки кластера - так называемый migration mode. Официальная документация его описывает, но с оговорками: это не zero-downtime в полном смысле, а «rolling migration с контролируемым окном».
На практике процесс такой:
- Первый шаг - контроллеры. Поднимаем новые ноды в режиме KRaft-controller. Они пока не обслуживают трафик, только синхронизируют метаданные из ZooKeeper.
- Второй шаг - перевод брокеров. По одному перезапускаем брокеры с новым конфигом, указывающим на KRaft-контроллеры вместо ZooKeeper. Каждый брокер переходит в dual-write режим.
- Третий шаг - финализация. Когда все брокеры переведены, мигрируем метаданные финально, выключаем ZooKeeper.
Звучит аккуратно. На деле - работает, но с несколькими неприятными моментами.
Во время rolling-перезапуска брокеров consumer lag вырастал - не критично, но заметно. Источники продолжали писать, consumers догоняли. На одном из топиков с большим retention и активными consumers мы поймали кратковременный rebalance consumer group в самый неудобный момент - во время перезапуска второго брокера. Consumer group переназначала партиции, часть consumers остановилась на несколько секунд. Данные не потерялись, но отставание в пайплайне заказчик заметил - пришлось объяснять.
Итоговый downtime в смысле «данные не движутся вообще» - около 3 минут во время финализации метаданных. Это тот момент, когда кластер переключается с ZooKeeper на KRaft-контроллеры как единственный source of truth. Мы не смогли этот момент полностью убрать - только уменьшить.
Мониторинг: тут всё было веселее
Главная проблема после миграции оказалась не в кластере, а в мониторинге.
У нас Prometheus + Grafana, метрики из Kafka через JMX Exporter. Часть дашбордов была построена под ZooKeeper-специфичные метрики: zookeeper_session_state, zookeeper_initsync_connections, kafka_controller_active_controller_count в старом понимании (где active controller - ZooKeeper-ориентированный концепт). После миграции эти метрики либо пропали, либо начали вести себя иначе.
Конкретно поломалось три вещи:
- Алерт на active controller. Мы следили за тем, что в кластере ровно один active controller. В KRaft-режиме метрика
kafka_controller_active_controller_countпо-прежнему существует, но её смысл чуть другой - и наш алерт начал ложно срабатывать в первые часы после миграции, пока контроллеры выбирали leader. - ZooKeeper-дашборд. Очевидно, стал бесполезным. Но мы не убрали его сразу, и несколько дней коллеги периодически на него смотрели и спрашивали «а почему тут всё красное». Потому что ZooKeeper выключен.
- Метрики leader election. В KRaft elections происходят иначе - через Raft-протокол, со своими метриками (
kafka_controller_election_rate,kafka_controller_time_since_last_leader_election_seconds). Их не было в нашем стеке, пришлось добавлять вручную.
Хорошая новость: JMX Exporter для Kafka 3.7+ нормально отдаёт KRaft-метрики - нужно только добавить нужные имена в конфиг. Это заняло не час, но и не день. Плохая новость: готового «набора метрик для KRaft кластера» в публичном виде почти нет - собирали по документации, по issues в GitHub, по тому что видели в jconsole после миграции.
Что стало лучше
Честно: операционно стало тише. ZooKeeper-инцидентов больше нет - потому что ZooKeeper больше нет. Конфигурация кластера проще на 3 VM и на один отдельный стек мониторинга.
Скорость leader election при падении брокера субъективно выросла - это одно из задекларированных улучшений KRaft, и наблюдения это подтверждают. Хотя у нас недостаточно данных, чтобы делать точные выводы - штатных падений брокеров в production немного.
Metadata operations (создание топиков, изменение конфига) работают быстрее - это заметно при автоматизированном управлении топиками через Terraform-провайдер.
Kafka 4.0 - что это меняет
Выход 4.0 без ZooKeeper означает, что если вы ещё не перешли на KRaft - нужно это сделать до обновления на 4.0. Миграцию Kafka 3.x -> KRaft в рамках ветки 3.x мы прошли, как описано выше. Обновление до 4.0 после этого - обычный rolling upgrade без зоопарка.
Если у вас кластер на 3.x с ZooKeeper и вы планируете обновление до 4.0 - не рассчитывайте на то, что это будет одним шагом. Это два этапа: сначала миграция на KRaft внутри 3.x, потом апгрейд до 4.0.
Мы сопровождаем кластеры Kafka в рамках DWH/BI-проектов и готовы помочь спланировать миграцию - особенно если у вас продакшн-нагрузка и нужно минимизировать окно обслуживания.