Лог-компакция: последнее значение по ключу

Урок про особую политику очистки, которая делает из лога снимок актуальных значений по ключу.

Лог-компакция (log compaction) — политика очистки, при которой Kafka сохраняет хотя бы последнее значение для каждого ключа, удаляя более старые версии того же ключа.

Зачем это нужно

Иногда вам важна не вся история, а текущее значение по ключу: последний профиль пользователя, актуальная цена товара, текущая конфигурация. Хранить все промежуточные версии вечно расточительно, а обычный retention по времени снёс бы и нужные «последние» значения. Компакция решает это: старые версии ключа удаляются, последняя — остаётся навсегда.

Как это выглядит

  До компакции (лог с историей значений ключа):
  key=u1:"A"  key=u2:"X"  key=u1:"B"  key=u1:"C"  key=u2:"Y"

  После компакции (только последнее на ключ):
  key=u1:"C"  key=u2:"Y"

  Топик стал "таблицей": ключ -> актуальное значение.

Так compacted-топик работает как материализованная таблица состояний, но остаётся логом: новые обновления по-прежнему дописываются в конец, а старые версии вычищаются фоном.

Tombstone: удаление ключа

Чтобы удалить ключ из «таблицы», публикуют tombstone — событие с этим ключом и значением null. Компакция, увидев tombstone, удаляет ключ полностью (после выдержки delete.retention.ms, чтобы потребители успели увидеть удаление).

# включить компакцию на топике user-profiles
kafka-configs.sh --bootstrap-server localhost:9092 \
  --alter --entity-type topics --entity-name user-profiles \
  --add-config cleanup.policy=compact

Где применяется

СценарийКлючЗачем компакция
Текущий профильuser_idхранить последнюю версию профиля
Конфигурацияconfig_keyактуальное значение настройки
__consumer_offsetsгруппа+партицияпоследний оффсет группы (так и устроен)

Как работает под капотом

Фоновый поток-«чистильщик» (log cleaner) проходит по сегментам, строит карту «ключ -> последний оффсет» и переписывает сегменты, выбрасывая устаревшие версии. Активный сегмент не компактится — поэтому самые свежие обновления могут какое-то время сосуществовать со старыми, пока cleaner до них не доберётся. Компакция гарантирует, что последнее значение ключа точно сохранится; промежуточные — нет. Это ровно та модель, что нужна для восстановления текущего состояния: прочитал compacted-топик с начала — получил актуальный снимок по всем ключам.

Частые ошибки

  • Ждать полной истории от compacted-топика. Промежуточные версии исчезают; для аудита нужен обычный retention=delete.
  • Сообщения без ключа в compact-топике. Компакция работает по ключу; событие с null-ключом некорректно для compaction.
  • Забыть про tombstone. Без события-надгробия ключ останется в «таблице» навсегда.

Итоги

  • Компакция хранит последнее значение на ключ, превращая топик в таблицу актуальных состояний.
  • Удаление ключа — через tombstone (значение null).
  • Это модель для текущего состояния (профили, конфиги, оффсеты), а не для полной истории.
Проверьте себя
1. Что сохраняет лог-компакция для каждого ключа?
AВсе версии навсегда
BХотя бы последнее значение, удаляя старые версии того же ключа
CТолько первое значение
DСлучайную версию
2. Как удалить ключ из compacted-топика?
AКомандой DELETE
BОпубликовать tombstone — событие с этим ключом и значением null
CУменьшить retention
DУдалить партицию
3. Для чего НЕ подходит compacted-топик?
AДля текущих профилей
BДля полной истории изменений (аудита) — промежуточные версии теряются
CДля хранения оффсетов
DДля актуальных конфигов