Що таке offset в Kafka
Offset — це НЕ унікальний ID повідомлення. Це позиція в лозі. Одне й те саме повідомлення в різних партиціях має різні offsets. Offset монотонно росте (0, 1, 2...) і ніколи не з...
Рівень Junior
Визначення
Offset — це порядковий номер повідомлення в партиції.
Offset — це НЕ унікальний ID повідомлення. Це позиція в лозі. Одне й те саме повідомлення в різних партиціях має різні offsets. Offset монотонно росте (0, 1, 2…) і ніколи не зменшується, навіть якщо повідомлення видалені.
Кожне повідомлення отримує унікальний offset.
Партиція 0:
offset 0: {"user": "user-1", "action": "login"}
offset 1: {"user": "user-2", "action": "purchase"}
offset 2: {"user": "user-1", "action": "logout"}
offset 3: {"user": "user-3", "action": "login"}
Основні властивості
- Offset — це число, що починається з 0
- Offset унікальний тільки всередині однієї партиції
- Offset не можна змінити після запису
- Повідомлення впорядковані по offset
Як консьюмер використовує offset?
Консьюмер запам'ятовує свій offset:
Прочитав offset 5 → запам'ятав 5
При перезапуску → продовжує з offset 6
Приклад коду
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, String> record : records) {
System.out.println("Partition: " + record.partition());
System.out.println("Offset: " + record.offset());
System.out.println("Value: " + record.value());
}
Рівень Middle
Committed Offset
Committed offset — останній оброблений offset, збережений в Kafka
Консьюмер читає offset 5 → обробляє → коммітить offset 5
При перезапуску → продовжує з offset 6
Consumer Position
// Поточна позиція (наступний offset для читання)
long position = consumer.position(new TopicPartition("orders", 0));
// Останній закоммічений offset
OffsetAndMetadata committed = consumer.committed(new TopicPartition("orders", 0));
Offset Management
// Ручний комміт
props.put("enable.auto.commit", "false");
// Синхронний комміт (надійний)
consumer.commitSync();
// Асинхронний комміт (швидкий)
consumer.commitAsync((offsets, exception) -> {
if (exception != null) {
log.error("Commit failed", exception);
}
});
Seek — читання з певного offset
TopicPartition partition = new TopicPartition("orders", 0);
// Читання з конкретного offset
consumer.seek(partition, 1000);
// Читання з початку
consumer.seekToBeginning(List.of(partition));
// Читання з кінця
consumer.seekToEnd(List.of(partition));
Типові помилки
- Комміт до обробки:
consumer.commitSync(); // ❌ спочатку комміт process(records); // потім обробка // Якщо впав → дані втрачені - Ручна зміна offsets без причини:
consumer.seek(partition, 0); // читання з початку // Може викликати дублікати
Рівень Senior
Internal Implementation
__consumer_offsets topic:
Внутрішній топик Kafka для зберігання offsets
- Компактується (log compaction)
- Зберігає offsets для всіх consumer groups
- Ключ: group.id + topic + partition
- Значення: offset + metadata + timestamp
Offset Storage Format:
Key: [group.id, topic, partition]
Value: {
offset: long,
metadata: String,
leaderEpoch: int,
timestamp: long
}
Offset Commit Strategies
1. Synchronous Commit:
// Блокує до підтвердження брокером
consumer.commitSync();
// Надійно, але повільніше
2. Asynchronous Commit:
// Не чекає підтвердження
consumer.commitAsync((offsets, exception) -> {
if (exception != null) {
// Retry або логування
log.error("Commit failed for offsets: {}", offsets, exception);
}
});
// Швидше, але можлива втрата при збої
3. Batch Commit:
// Комміт кожні N повідомлень
int count = 0;
for (var record : records) {
process(record);
if (++count % 100 == 0) {
consumer.commitAsync();
}
}
Offset Reset Policy
// auto.offset.reset — поведінка при відсутності committed offset
props.put("auto.offset.reset", "earliest"); // читати з початку
props.put("auto.offset.reset", "latest"); // читати з кінця (за замовчуванням)
props.put("auto.offset.reset", "none"); // виключення
Leader Epoch і Offset Validation
Починаючи з Kafka 0.11:
- Leader Epoch зберігається з кожним offset
- При failover консьюмер може визначити
які повідомлення могли бути втрачені
- Запобігає silent data loss
Leader Epoch — номер покоління лідера партиції. Кожного разу при зміні лідера epoch
збільшується. Дозволяє консьюмеру визначити, які повідомлення могли бути втрачені
при failover.
Offset Monitoring
Ключові метрики:
Current Offset → останній прочитаний
Committed Offset → останній закоммічений
Log End Offset → останній в партиції
Consumer Lag = Log End Offset - Committed Offset
Monitoring lag:
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--describe --group my-group
GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG
my-group orders 0 1000 1200 200
LAG=200 означає: 200 повідомлень в партиції ще не прочитані. Критичність залежить від throughput: при 100 msg/s — 2 секунди відставання (нормально), при 1 msg/s — 200 секунд (критично).
Offset Recovery After Failure
Сценарій:
1. Консьюмер прочитав offset 100
2. Почав обробку → впав
3. Не закоммітив offset
При перезапуску:
- Committed offset = 99
- Продовжить з offset 100
- Повідомлення 100 обробиться знову (at-least-once)
Best Practices
✅ Комміт після обробки
✅ Синхронний комміт для надійності
✅ Асинхронний комміт для high-throughput
✅ Моніторинг lag
✅ Налаштування auto.offset.reset
❌ Автокомміт для критичних даних
❌ Комміт до обробки
❌ Ручна зміна offsets без причини
❌ Ігнорування consumer lag
❌ Без monitoring offsets
Архітектурні рішення
- Committed offset — основа at-least-once — гарантує доставку
- __consumer_offsets — компактний внутрішній топик — ефективне зберігання
- Leader epoch validation — запобігає silent data loss
- Monitoring lag — ранній індикатор проблем
Резюме для Senior
- Offset — фундаментальний механізм відстеження прогресу
- __consumer_offsets зберігає offsets для всіх груп
- Комміт стратегія впливає на reliability і performance
- Leader epoch validation критичний для data safety
- Monitoring lag обов’язковий для production
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
- Offset — порядковий номер повідомлення в партиції, починається з 0
- Offset унікальний тільки всередині однієї партиції, не глобально
- Offset не можна змінити після запису; повідомлення впорядковані по offset
- Committed offset — останній оброблений offset, збережений в
__consumer_offsets - Consumer Lag = LogEndOffset - CommittedOffset — ключова метрика здоров’я
auto.offset.reset: earliest (з початку), latest (з кінця, за замовчуванням), none (exception)- Leader Epoch (з Kafka 0.11) — запобігає silent data loss при failover
- Seek дозволяє читати з будь-якого offset: початку, кінця, конкретного номера, timestamp
Часті уточнюючі запитання:
- Що таке Leader Epoch? — Номер покоління лідера; допомагає визначити втрачені повідомлення при failover.
- Де зберігаються committed offsets? — У внутрішньому топику
__consumer_offsets(compact). - Що означає LAG=200? — 200 повідомлень ще не прочитані; критичність залежить від throughput.
- Що буде при комміті до обробки? — При crash повідомлення втрачені (offset закоммічений, не оброблений).
Червоні прапорці (НЕ говорити):
- «Offset — унікальний ID повідомлення» — це позиція в лозі, не ID
- «Offset можна змінити» — не можна, immutable
- «Offset унікальний у всьому топику» — тільки всередині партиції
- «Комміт перед обробкою — норма» — це data loss при crash
Пов’язані теми:
- [[13. Як працює commit offset]]
- [[14. У чому різниця між auto commit і manual commit]]
- [[26. Як моніторити lag консьюмера]]
- [[15. Що таке ребаланс і коли він відбувається]]