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

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

 

В уроке 25 мы разбирались с kafka-broker-api-versions.sh — смотрели, какие версии протокола поддерживает брокер, и учились диагностировать ошибки UNSUPPORTED_VERSION при rolling upgrade. Там речь шла о низкоуровневой совместимости на уровне API.

Сегодня спускаемся на уровень ниже — не к протоколу, а к данным. Конкретно к офсетам. Любой, кто разбирается с lag-ом консьюмеров, готовится запустить kafka-delete-records.sh или просто хочет понять, сколько сообщений накопилось в партиции, в первую очередь задаёт один вопрос: «Какой сейчас earliest и latest офсет?» Именно для этого существует kafka-get-offsets.sh.

Утилита простая, но незаменимая в повседневной диагностике. В курсе «Администрирование кластера Kafka» мониторинг офсетов разбирают в блоке операционных задач — рядом с retention-политиками и управлением лагом consumer-групп.

 

Что такое kafka-get-offsets.sh

 

kafka-get-offsets.sh — утилита командной строки из стандартного набора Apache Kafka, которая возвращает офсеты для топиков и партиций. Она напрямую опрашивает брокер через API ListOffsets и выдаёт результат в виде строк формата топик:партиция:офсет.

Это не метрика и не лог — это снимок текущего состояния границ лога. Утилита показывает два принципиально разных типа офсетов: начало (earliest) и конец (latest) видимого диапазона каждой партиции. Кроме того, она умеет принимать временную метку и возвращать первый офсет, который был записан не раньше этого момента.

Важно: kafka-get-offsets.sh работает без consumer group. Она не читает сообщения и не трогает committed offsets. Это чистый query к брокеру о состоянии партиции.

 

Как Kafka считает офсеты в партиции

 

Прежде чем идти дальше, стоит разобраться с тем, что именно возвращает утилита. В каждой партиции Kafka поддерживает два ключевых показателя.

Log start offset (он же earliest, он же low watermark) — это минимальный офсет, доступный для чтения. Всё, что ниже этой границы, уже удалено по retention-политике или через kafka-delete-records.sh. Новый консьюмер с позицией auto.offset.reset=earliest начнёт читать именно отсюда.

Log end offset (он же latest, он же high watermark) — это офсет следующей записи, которая будет добавлена в партицию. Последнее доступное сообщение имеет офсет на единицу меньше. Консьюмер с позицией auto.offset.reset=latest начнёт читать начиная с этого значения — то есть только новые сообщения после запуска.

Разница между latest и earliest показывает, сколько сообщений сейчас доступно в партиции. Это не то же самое, что общее количество записанных сообщений — часть могла уже уйти по retention. Это и есть «видимый» размер лога.

 

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

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

 

Базовый запуск команды kafka-get-offsets.sh

Без дополнительных флагов утилита возвращает latest-офсеты для всех партиций всех топиков кластера:

kafka-get-offsets.sh --bootstrap-server localhost:9092

Вывод — по одной строке на каждую партицию. Например, для кластера с двумя топиками по три партиции вы получите шесть строк:

# Пример вывода: топик:партиция:офсет
orders:0:1542
orders:1:1389
orders:2:1601
payments:0:842
payments:1:756
payments:2:819

Формат топик:партиция:офсет постоянный — его удобно парсить в скриптах через awk или cut.

Без флага —time утилита по умолчанию возвращает latest. Если нужен earliest — указывайте явно.

 

Флаг —time. Earliest, latest и поиск по метке времени

Ключевой флаг утилиты — —time. Он принимает три варианта значений.

  • latest — вернуть log end offset (значение по умолчанию).
  • earliest — вернуть log start offset, то есть первый доступный офсет.
  • числовая метка времени в миллисекундах — вернуть первый офсет, чья временная метка не меньше указанной. Это позволяет найти «точку входа» для конкретного момента времени.

Запрос earliest-офсетов для конкретного топика выглядит так:

kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 \
  --topic orders \
  --time earliest

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

Поиск по временной метке особенно полезен при инцидентах. Скажем, нужно найти офсет, соответствующий 6:00 UTC 1 мая 2025 года. Переводим метку в миллисекунды и передаём значение:

# 2025-05-01 06:00:00 UTC = 1746075600000 мс

kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 \
  --topic orders \
  --time 1746075600000

Брокер вернёт первый офсет в каждой партиции, чья временная метка больше или равна указанной. Если в тот момент данных ещё не было — вернёт -1. Если все данные уже ушли по retention — тоже -1.

 

Фильтрация по топику и партиции

Запускать утилиту по всему кластеру не всегда разумно — в production-среде топиков могут быть сотни. Для адресного запроса есть два флага.  —topic ограничивает вывод одним топиком. Его можно указать несколько раз, если нужно запросить несколько конкретных топиков:

kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 \
  --topic orders \
  --topic payments \
  --time latest

—partitions принимает список номеров партиций через запятую. Используется вместе с —topic:

# Получить latest-офсет только для партиций 0 и 2 топика orders
kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 \
  --topic orders \
  --partitions 0,2 \
  --time latest

Такая фильтрация сокращает нагрузку на брокер при частых опросах — особенно если скрипт мониторинга гоняется каждые 30 секунд.

 

Все флаги kafka-get-offsets.sh

Утилита немногословна по части опций, но каждый флаг нужен в своём сценарии. Вот полная таблица:

Флаг Значение / формат Описание
—bootstrap-server host:port Адрес брокера. Обязательный параметр
—topic имя топика Фильтр по топику. Можно указать несколько раз
—partitions 0,1,2 (через запятую) Фильтр по номерам партиций. Только вместе с —topic
—time earliest / latest / мс Какой офсет вернуть. По умолчанию latest
—exclude-internal-topics нет значения (флаг) Исключить служебные топики (__consumer_offsets и др.)
—command-config путь к файлу .properties Файл с настройками безопасности (SASL/SSL)

Флаг —exclude-internal-topics удобен при полном сканировании кластера — без него в вывод попадёт __consumer_offsets и другие служебные топики, что засоряет картину.

 

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

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

 

Практические сценарии

Сценарий 1. Подготовка к kafka-delete-records.sh

Перед сдвигом log start offset нужно знать текущие границы. Правильный порядок действий — сначала запросить earliest и latest, убедиться, что понимаете что и где лежит, и только потом писать JSON-файл для удаления.

# Шаг 1: смотрим нижнюю границу
kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 \
  --topic orders \
  --time earliest

# Шаг 2: смотрим верхнюю границу
kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 \
  --topic orders \
  --time latest

После этого вы точно знаете, в каком диапазоне лежат данные каждой партиции — и можно безопасно задавать целевые офсеты для kafka-delete-records.sh.

Сценарий 2. Ручной подсчёт размера топика

Быстро оценить, сколько сообщений сейчас доступно в топике, можно одной командой с небольшим конвейером:

# Считаем сумму latest-офсетов по всем партициям топика orders

kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 \
  --topic orders \
  --time latest \
  | awk -F: '{sum += $3} END {print "Total latest offsets:", sum}'

Результат — не точное количество сообщений (часть могла уйти по retention), а сумма latest-офсетов. Для оценки объёма и сравнения с предыдущими снимками этого достаточно.

Сценарий 3. Поиск точки входа после инцидента

Инцидент случился в 10:30 UTC. Нужно передать консьюмеру офсет, с которого начинались проблемные данные. Узнаём метку времени в миллисекундах и делаем запрос:

# Получить Unix timestamp в миллисекундах для 2025-05-03 10:30:00 UTC
TS=$(date -u -d "2025-05-03 10:30:00" +%s%3N)
echo "Timestamp: $TS"

kafka-get-offsets.sh \
  --bootstrap-server localhost:9092 \
  --topic orders \
  --time $TS

Полученные офсеты можно передать в kafka-consumer-groups.sh —reset-offsets —to-offset или использовать напрямую в consumer-коде через метод seek().

Сценарий 4. Мониторинг в скрипте

Минимальный bash-скрипт для периодического снятия снимка состояния топиков и сохранения в файл:

#!/bin/bash

# Снимок latest-офсетов для мониторинга. Запускать через cron каждые 5 минут.

BOOTSTRAP="localhost:9092"
SNAPSHOT_DIR="/var/log/kafka-offsets"
mkdir -p "$SNAPSHOT_DIR"

TIMESTAMP=$(date -u +"%Y%m%d_%H%M%S")
OUTPUT="$SNAPSHOT_DIR/offsets_${TIMESTAMP}.txt"

kafka-get-offsets.sh \
  --bootstrap-server "$BOOTSTRAP" \
  --exclude-internal-topics \
  --time latest > "$OUTPUT"

echo "Saved: $OUTPUT ($(wc -l < "$OUTPUT") partitions)"

Накопленные снимки позволяют строить тренды роста топиков и замечать аномальные скачки без Prometheus и Grafana — достаточно простого diff или awk.

 

Как kafka-get-offsets.sh соотносится с другими утилитами

Офсеты в Kafka можно получить несколькими инструментами — разница в том, что именно каждый из них показывает.

Инструмент Что показывает Когда использовать
kafka-get-offsets.sh Log start / end offset партиции (earliest, latest, по времени) Диагностика топика, подготовка к delete-records, поиск офсета по времени
kafka-consumer-groups.sh Committed offset группы, lag, текущее положение каждого консьюмера Мониторинг и управление consumer group, сброс офсетов
kafka-dump-log.sh Содержимое лог-сегментов с диска, офсеты внутри батчей Глубокая диагностика, анализ отдельных файлов сегментов
kcat -Q Офсеты через low-level query к брокеру Быстрый разовый запрос без установки Kafka bin

Разница между kafka-get-offsets.sh и kafka-consumer-groups.sh важна на практике. Первый показывает, что есть в партиции. Второй показывает, где находится группа внутри этого диапазона. Lag — это разница между тем, что видит второй, и верхней границей, которую показывает первый.

 

Аналог через kcat

Если Kafka bin недоступен, те же данные можно получить через kcat (kafkacat). Флаг -Q делает именно то, что нужно — запрашивает офсет для заданного топика, партиции и временной метки:

# Получить earliest-офсет для orders, партиция 0
kcat -b localhost:9092 -Q -t orders:0:0

# Получить latest-офсет для orders, партиция 0
kcat -b localhost:9092 -Q -t orders:0:-1

# Поиск по временной метке (ms) для партиции 1
kcat -b localhost:9092 -Q -t orders:1:1746075600000

Синтаксис -t топик:партиция:timestamp при этом использует те же зарезервированные значения: 0 = earliest, -1 = latest, число в мс = поиск по времени. Для ad hoc запросов kcat удобнее — одна строка вместо полного пути к kafka-get-offsets.sh.

 

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

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

 

Диаграмма — как работает запрос офсетов


flowchart LR
    CLI["kafka-get-offsets.sh\n--bootstrap-server\n--topic / --time"] --> BK["Брокер-лидер\nпартиции"]
    CLI -->|"ListOffsets API\n(API Key 2)"| BK
    BK -->|"earliest"| LSO["Log Start Offset\n(low watermark)"]
    BK -->|"latest"| LEO["Log End Offset\n(high watermark)"]
    BK -->|"timestamp"| TSO["Первый офсет\n>= timestamp"]
    LSO --> OUT["Вывод:\nтопик:партиция:офсет"]
    LEO --> Out2["Вывод:\nтопик:партиция:офсет"]
    TSO --> OUT3["Вывод:\nтопик:партиция:офсет\n(-1 если нет данных)"]

Запрос идёт напрямую к лидеру каждой партиции. Для топика с тремя партициями на разных брокерах утилита выполнит три отдельных ListOffsets-запроса — по одному к каждому лидеру.

 

Что дальше

В следующем уроке переходим к kafka-verifiable-producer.sh и kafka-verifiable-consumer.sh. Эта пара утилит создана специально для тестирования — они отправляют и читают сообщения с подробным логированием каждого события: что отправлено, с каким офсетом, на какую партицию, было ли подтверждение. Незаменимо при проверке надёжности кластера и экспериментах с acks, retries и delivery semantics.

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

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

№ Тема URL
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 https://bigdataschool.ru/blog/news/lesson11-kafka-cluster-cheatsheet/
12 kafka-metadata-shell.sh https://bigdataschool.ru/blog/news/lesson13-kafka-metadata-shell/
13 kafka-configs.sh https://bigdataschool.ru/blog/news/lesson15-kafka-configs/
14 kafka-log-dirs.sh https://bigdataschool.ru/blog/news/lesson16-kafka-log-dirs/
15 kafka-dump-log.sh https://bigdataschool.ru/blog/news/lesson17-kafka-dump-log/
16 kafka-delete-records.sh https://bigdataschool.ru/blog/news/lesson18-kafka-delete-records/
17 kafka-consumer-groups.sh https://bigdataschool.ru/blog/news/lesson19-kafka-consumer-groups/
18 kafka-streams-application-reset.sh https://bigdataschool.ru/blog/news/lesson20-kafka-streams-reset/
19 kafka-leader-election.sh https://bigdataschool.ru/blog/news/lesson21-kafka-leader-election/
20 kafka-reassign-partitions.sh https://bigdataschool.ru/blog/news/lesson22-kafka-reassign-partitions/
21 kafka-replica-verification.sh https://bigdataschool.ru/blog/news/lesson23-kafka-replica-verification/
22 kafka-acls.sh https://bigdataschool.ru/blog/news/lesson24-kafka-acls/
23 kafka-broker-api-versions.sh https://bigdataschool.ru/blog/news/lesson25-kafka-broker-api-versions/
24 kafka-get-offsets.sh https://bigdataschool.ru/blog/news/lesson26-kafka-get-offsets/
25 kafka-verifiable-producer/consumer.sh https://bigdataschool.ru/blog/news/lesson27-kafka-verifiable/
26 kafka-producer-perf-test.sh https://bigdataschool.ru/blog/news/lesson28-kafka-producer-perf/
27 kafka-consumer-perf-test.sh https://bigdataschool.ru/blog/news/lesson29-kafka-consumer-perf/
28 kafka-mirror-maker.sh https://bigdataschool.ru/blog/news/lesson30-kafka-mirror-maker/
29 connect-standalone.sh https://bigdataschool.ru/blog/news/lesson31-kafka-connect-standalone/
30 connect-distributed.sh https://bigdataschool.ru/blog/news/lesson32-kafka-connect-distributed/
31 kcat. Альтернативный CLI https://bigdataschool.ru/blog/news/lesson33-kcat/