Изучаем Apache Kafka с нуля. Урок 10. kafka-storage.sh

Изучаем Apache Kafka с нуля. Урок 10. kafka-storage.sh

 

В уроке 9 мы разобрали kafka-server-start.sh и kafka-server-stop.sh — как запускать брокер в foreground и daemon-режиме, какие переменные окружения влияют на JVM и как правильно останавливать процесс без потери данных. Но прежде чем брокер вообще сможет стартовать в KRaft-режиме, нужно сделать один обязательный шаг — отформатировать хранилище метаданных.

Этот шаг мы уже делали в уроке 2 по инструкции. Настало время разобраться, что именно происходит за кулисами, что записывается на диск и почему без этого шага KRaft-брокер откажется запускаться. Всем этим занимается утилита kafka-storage.sh.

Понимание того, как устроено хранилище метаданных KRaft, — обязательная тема для администраторов Kafka. Глубже она разбирается в курсе «Администрирование кластера Kafka», включая сценарии восстановления после сбоев.

Что такое kafka-storage.sh и зачем она нужна

kafka-storage.sh — утилита для управления хранилищем метаданных KRaft. В отличие от большинства утилит из предыдущих уроков, она не работает с живым брокером через сеть. Она работает напрямую с файловой системой — читает и создаёт файлы в директории, указанной в параметре log.dirs конфигурации.

В KRaft-режиме метаданные кластера (список топиков, количество партиций, распределение реплик, ACL и многое другое) хранятся в специальном внутреннем топике __cluster_metadata. Этот топик — обычный Kafka-лог, но обслуживается не брокером, а контроллером. Перед первым запуском этот лог нужно инициализировать — присвоить кластеру уникальный идентификатор и создать служебный файл.

Если форматирование не выполнено, kafka-server-start.sh завершится с ошибкой: брокер увидит пустую директорию и откажется стартовать. Именно поэтому kafka-storage.sh всегда идёт в паре с командой запуска.

Три подкоманды утилиты

У kafka-storage.sh есть три рабочих подкоманды. Каждая из них отвечает за отдельный этап работы с хранилищем.

  • random-uuid. Генерирует случайный UUID — уникальный идентификатор кластера. Этот идентификатор потом передаётся в команду форматирования.
  • format. Форматирует директорию хранилища: создаёт служебный файл meta.properties и инициализирует структуру для лога метаданных.
  • info. Показывает текущее состояние директории хранилища: отформатирована она или нет, какой cluster ID записан, версия метаданных.

На практике вы будете использовать их строго по порядку: сначала random-uuid, затем format, а info — для диагностики и проверки.

 

Apache Kafka: администрирование кластера

Код курса
KAFKA
Ближайшая дата курса
14 декабря, 2026
Продолжительность
24 ак.часов
Стоимость обучения
76 800

 

Шаг 1. Генерация cluster ID через random-uuid

random-uuid — самая простая из трёх подкоманд. Она генерирует случайный UUID в формате Base64 и выводит его в stdout. Никаких файлов при этом не создаётся.

# Проверено: Apache Kafka 4.2.0, Ubuntu 22.04
kafka-storage.sh random-uuid

Вывод будет выглядеть примерно так:

xtzWnoMyEkahzrAFKnMzmg

Это строка из 22 символов — UUID, закодированный в URL-safe Base64. Он уникален для каждого кластера. Удобнее всего сразу записать его в переменную окружения, чтобы не копировать вручную.

# Проверено: Apache Kafka 4.2.0, Ubuntu 22.04
KAFKA_CLUSTER_ID=$(kafka-storage.sh random-uuid)
echo $KAFKA_CLUSTER_ID

Этот приём особенно полезен при автоматизации — в скриптах развёртывания переменная передаётся напрямую в следующую команду без ручного вмешательства.

 

Шаг 2. Форматирование хранилища через format

Подкоманда format выполняет основную работу: инициализирует директорию хранилища для работы в KRaft-режиме. Без этого шага брокер не запустится.

# Проверено: Apache Kafka 4.2.0, Ubuntu 22.04
kafka-storage.sh format \
  --cluster-id $KAFKA_CLUSTER_ID \
  --config $KAFKA_HOME/config/kraft/server.properties

Два обязательных флага команды.

  • —cluster-id (-t). UUID кластера, полученный на предыдущем шаге. Именно это значение будет записано в meta.properties и станет идентификатором кластера навсегда.
  • —config (-c). Путь к файлу конфигурации брокера. Утилита читает из него параметр log.dirs, чтобы найти директорию для форматирования.

После успешного выполнения вы увидите сообщение вроде этого:

Formatting /tmp/kraft-combined-logs with metadata.version 4.0-IV3.

Теперь хранилище готово — брокер можно запускать.

Что именно записывается на диск

После форматирования в директории log.dirs появляется файл meta.properties. Это обычный текстовый файл в формате Java properties. Посмотреть его можно командой cat:

# Проверено: Apache Kafka 4.2.0, Ubuntu 22.04
cat /tmp/kraft-combined-logs/meta.properties

Содержимое файла выглядит так:

#
#Thu May 01 12:34:56 UTC 2025
cluster.id=xtzWnoMyEkahzrAFKnMzmg
node.id=1
version=1

Три ключевых поля этого файла.

  • cluster.id. UUID кластера, который вы передали через —cluster-id. По нему брокер идентифицирует, к какому кластеру он принадлежит.
  • node.id. Идентификатор узла, берётся из параметра node.id в server.properties. Должен быть уникальным в кластере.
  • version. Версия формата хранилища. Меняется при мажорных обновлениях Kafka.

Кроме meta.properties, в директории создаётся поддиректория __cluster_metadata-0 — это партиция 0 внутреннего топика метаданных. В ней будет храниться Raft-лог с историей всех изменений кластера.

 

Шаг 3. Проверка состояния через info

Подкоманда info позволяет в любой момент проверить, в каком состоянии находится хранилище. Это особенно полезно при диагностике проблем с запуском брокера.

# Проверено: Apache Kafka 4.2.0, Ubuntu 22.04
kafka-storage.sh info \
  --config $KAFKA_HOME/config/kraft/server.properties

Если хранилище отформатировано, вывод покажет cluster ID и версию метаданных:

Found log directory:
  /tmp/kraft-combined-logs: FORMATTED: cluster ID = xtzWnoMyEkahzrAFKnMzmg, metadata.version = 4.0-IV3 (3).

Если хранилище пустое — ещё не форматировалось:

Found log directory:
  /tmp/kraft-combined-logs: EMPTY

Статус EMPTY означает, что брокер при попытке старта выдаст ошибку. Нужно сначала выполнить format.

 

 

Apache Kafka: администрирование кластера

Код курса
KAFKA
Ближайшая дата курса
14 декабря, 2026
Продолжительность
24 ак.часов
Стоимость обучения
76 800

 

Флаг —ignore-formatted и когда он нужен

По умолчанию kafka-storage.sh format завершится с ошибкой, если директория уже отформатирована. Это защита от случайного стирания метаданных живого кластера.

Log directory /tmp/kraft-combined-logs is already formatted. Use --ignore-formatted to skip this check.

Флаг —ignore-formatted отключает эту проверку. Если директория уже отформатирована, команда просто пропустит её без ошибки. Это полезно в двух сценариях.

  • Скрипты развёртывания. Если скрипт запускается повторно (например, при перезапуске provisioning), форматирование не сломает уже настроенный узел.
  • Docker и оркестраторы. При перезапуске контейнера с persistent volume хранилище уже будет существовать. Флаг позволяет переиспользовать его без ручной проверки.
# Безопасное форматирование - не затронет уже отформатированную директорию
kafka-storage.sh format \
  --cluster-id $KAFKA_CLUSTER_ID \
  --config $KAFKA_HOME/config/kraft/server.properties \
  --ignore-formatted

Важно понимать: —ignore-formatted не перезаписывает данные. Он просто говорит «если уже готово — пропусти». Принудительно перезаписать хранилище этот флаг не позволяет.

 

Форматирование в многонодовом кластере

При развёртывании кластера из нескольких узлов все брокеры должны получить одинаковый cluster ID. Это критически важно: узлы с разными cluster ID не смогут образовать кластер — они будут считать себя принадлежащими к разным кластерам.

Типичный порядок действий при инициализации кластера из трёх узлов такой.

  • Генерация UUID. Выполняется один раз на любом из узлов — или вообще на отдельной машине. Главное — сохранить полученный UUID.
  • Форматирование на каждом узле. Команда format запускается на каждом сервере отдельно, но с одним и тем же cluster ID и с конфигом именно этого узла.
  • Запуск брокеров. После форматирования всех узлов можно запускать брокеры.
# --- Шаг 1: генерация UUID (один раз, на любой машине) ---
KAFKA_CLUSTER_ID=$(kafka-storage.sh random-uuid)
echo "Cluster ID: $KAFKA_CLUSTER_ID"

# --- Шаг 2: форматирование на каждом узле (broker-1, broker-2, broker-3) ---
# Выполнить на каждом сервере, передав одинаковый $KAFKA_CLUSTER_ID
kafka-storage.sh format \
  --cluster-id $KAFKA_CLUSTER_ID \
  --config $KAFKA_HOME/config/kraft/server.properties

# --- Шаг 3: проверка перед запуском ---
kafka-storage.sh info \
  --config $KAFKA_HOME/config/kraft/server.properties

На практике UUID удобно распространять через переменную окружения в системе управления конфигурацией — Ansible, Chef или аналогах. Именно так это делается в production-окружениях.

 

Что происходит при принудительном переформатировании

Если нужно полностью сбросить кластер и начать заново, хранилище можно переформатировать вручную. Для этого нужно сначала удалить содержимое директории, а затем выполнить format с новым или тем же UUID.

# ВНИМАНИЕ: команда удаляет все данные кластера безвозвратно
# Использовать только на тестовых окружениях

# Остановить брокер перед очисткой
kafka-server-stop.sh

# Удалить содержимое директории хранилища (не саму директорию)
rm -rf /tmp/kraft-combined-logs/*

# Сгенерировать новый UUID и отформатировать заново
KAFKA_CLUSTER_ID=$(kafka-storage.sh random-uuid)
kafka-storage.sh format \
  --cluster-id $KAFKA_CLUSTER_ID \
  --config $KAFKA_HOME/config/kraft/server.properties

После такого сброса кластер становится чистым — все топики, сообщения и конфигурации удалены. В учебных целях это удобно: быстрый способ вернуть Kafka в исходное состояние.

 

Сравнение сценариев использования kafka-storage.sh

Соберём основные сценарии в таблицу — чтобы сразу было понятно, какую комбинацию команд использовать в каждом случае.

Сценарий Команды —ignore-formatted Данные сохраняются?
Первый запуск одного узла random-uuid + format нет н/д (данных ещё нет)
Первый запуск кластера (3 узла) random-uuid (1 раз) + format на каждом узле нет н/д
Idempotent-скрипт развёртывания format —ignore-formatted да да (существующие данные не трогаются)
Docker с persistent volume format —ignore-formatted да да
Полный сброс тестового кластера rm -rf + random-uuid + format нет нет (всё удаляется)
Проверка перед стартом info н/д да (read-only)

Для production-окружений всегда добавляйте —ignore-formatted в скрипты форматирования. Это страховка от случайного сноса данных при повторном прогоне автоматизации.

 

Apache Kafka для инженеров данных

Код курса
DEVKI
Ближайшая дата курса
7 декабря, 2026
Продолжительность
24 ак.часов
Стоимость обучения
76 800

 

Процесс инициализации KRaft-кластера

Для наглядности — полная последовательность шагов от генерации UUID до готового к работе брокера.

процесс инициализации Apache Kafka кластера в Kraft режиме


Что дальше

Теперь вы понимаете, что происходит с хранилищем до первого старта Kafka: как генерируется cluster ID, что записывается в meta.properties и как обеспечить идемпотентность при автоматическом развёртывании.

В уроке 11 разберём утилиту kafka-cluster.sh. Она позволяет получить идентификатор уже запущенного кластера через сеть — полезно для сверки с тем, что записано в meta.properties, и для диагностики проблем с membership в многонодовых конфигурациях.

Референсные ссылки

Все уроки курса

№ Тема Ссылка
1 Установка Kafka с Zookeeper https://bigdataschool.ru/blog/news/lesson1-kafka-zookeeper-install/
2 Установка Kafka в режиме KRaft https://bigdataschool.ru/blog/news/lesson2-kafka-kraft-install/
3 Docker KRaft. Однонодовый кластер https://bigdataschool.ru/blog/news/lesson3-kafka-docker-single/
4 Docker KRaft. 3-нодовый кластер https://bigdataschool.ru/blog/news/lesson4-kafka-docker-cluster/
5 Утилиты bin/. Переменные окружения и основы https://bigdataschool.ru/blog/news/lesson5-kafka-bin-intro/
6 kafka-topics.sh. Управление топиками https://bigdataschool.ru/blog/news/lesson6-kafka-topics/
7 kafka-console-producer.sh https://bigdataschool.ru/blog/news/lesson7-kafka-console-producer/
8 kafka-console-consumer.sh https://bigdataschool.ru/blog/news/lesson8-kafka-console-consumer/
9 kafka-server-start.sh / kafka-server-stop.sh https://bigdataschool.ru/blog/news/lesson9-kafka-server-start-stop/
10 kafka-storage.sh https://bigdataschool.ru/blog/news/lesson10-kafka-storage/
11 kafka-cluster.sh https://bigdataschool.ru/blog/news/lesson11-kafka-cluster/
12 kafka-metadata-quorum.sh https://bigdataschool.ru/blog/news/lesson12-kafka-metadata-quorum/
13 kafka-metadata-shell.sh https://bigdataschool.ru/blog/news/lesson13-kafka-metadata-shell/
14 kafka-features.sh https://bigdataschool.ru/blog/news/lesson14-kafka-features/
15 kafka-configs.sh https://bigdataschool.ru/blog/news/lesson15-kafka-configs/
16 kafka-log-dirs.sh https://bigdataschool.ru/blog/news/lesson16-kafka-log-dirs/
17 kafka-dump-log.sh https://bigdataschool.ru/blog/news/lesson17-kafka-dump-log/
18 kafka-delete-records.sh https://bigdataschool.ru/blog/news/lesson18-kafka-delete-records/
19 kafka-consumer-groups.sh https://bigdataschool.ru/blog/news/lesson19-kafka-consumer-groups/
20 kafka-streams-application-reset.sh https://bigdataschool.ru/blog/news/lesson20-kafka-streams-reset/
21 kafka-leader-election.sh https://bigdataschool.ru/blog/news/lesson21-kafka-leader-election/
22 kafka-reassign-partitions.sh https://bigdataschool.ru/blog/news/lesson22-kafka-reassign-partitions/
23 kafka-replica-verification.sh https://bigdataschool.ru/blog/news/lesson23-kafka-replica-verification/
24 kafka-acls.sh https://bigdataschool.ru/blog/news/lesson24-kafka-acls/
25 kafka-broker-api-versions.sh https://bigdataschool.ru/blog/news/lesson25-kafka-broker-api-versions/
26 kafka-get-offsets.sh https://bigdataschool.ru/blog/news/lesson26-kafka-get-offsets/
27 kafka-verifiable-producer/consumer.sh https://bigdataschool.ru/blog/news/lesson27-kafka-verifiable/
28 kafka-producer-perf-test.sh https://bigdataschool.ru/blog/news/lesson28-kafka-producer-perf/
29 kafka-consumer-perf-test.sh https://bigdataschool.ru/blog/news/lesson29-kafka-consumer-perf/
30 kafka-mirror-maker.sh https://bigdataschool.ru/blog/news/lesson30-kafka-mirror-maker/
31 connect-standalone.sh https://bigdataschool.ru/blog/news/lesson31-kafka-connect-standalone/
32 connect-distributed.sh https://bigdataschool.ru/blog/news/lesson32-kafka-connect-distributed/
33 kcat. Альтернативный CLI https://bigdataschool.ru/blog/news/lesson33-kcat/