Лог-компакция: последнее значение по ключу
Урок про особую политику очистки, которая делает из лога снимок актуальных значений по ключу.
Лог-компакция (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). - Это модель для текущего состояния (профили, конфиги, оффсеты), а не для полной истории.