В прошлом уроке Kafka удаляла старые сегменты по времени. Для координат курьеров это то, что нужно. Но у Отто есть табло статусов заказов: открыл его утром и видишь, где сейчас каждый заказ, даже созданный неделю назад. Удалить по времени статус «оплачен» нельзя, табло его потеряет. Хранить всю историю вечно тоже не хочется: у заказа, который прошёл десять статусов, табло нужен только последний. Для такого случая у Kafka есть компакция.
Записная книжка
В старой записной книжке у каждого знакомого несколько номеров: переезжал, менял оператора. Старые номера зачёркнуты, новый дописан ниже. Раз в год книжку переписывают начисто: у каждого знакомого остаётся только последний номер, а тех, кого вычеркнули совсем, в новую книжку не переносят.
Страницу, которую заполняешь сейчас, не переписывают: на ней ещё могут появиться исправления.
Лог-компакция делает с топиком то же самое.
Что делает компакция
Компакция включается настройкой топика cleanup.policy=compact. В таком топике у каждой записи обязан быть ключ: Kafka отклоняет запись без ключа ошибкой InvalidRecordException, мы проверили это на Kafka 4.3.1.
Фоновый процесс брокера, log cleaner, проходит по закрытым сегментам и для каждого ключа оставляет только самую свежую запись. Было:
оффсет ключ значение
0 order-1 created
1 order-2 created
2 order-1 paid
3 order-1 delivered
Стало:
оффсет ключ значение
1 order-2 created
3 order-1 delivered
Заметь, что оффсеты не перенумеровываются. После компакции в логе дыры: за оффсетом 1 сразу идёт 3. Консьюмер это нормально переживает, он просто продолжает со следующей существующей записи. А порядок записей одного ключа сохраняется, как в уроке про ключи.
Компакция трогает только закрытые сегменты, как и retention: активный сегмент остаётся как есть, со всеми повторами. Поэтому сразу после записи в компактированном топике видны все статусы, а чистится он позже.
Как удалить ключ совсем
Заказ закрыт, и с табло его надо убрать. Для этого пишут запись с тем же ключом и значением null. Такую запись называют tombstone, надгробием. Компакция удалит все прежние записи этого ключа, а сам tombstone оставит ещё на delete.retention.ms, по умолчанию сутки. Он нужен, чтобы консьюмер, который читает топик прямо сейчас, успел узнать об удалении. Потом исчезнет и он.
В консольном продюсере пустое значение задают свойством null.marker: строка, которая означает null.
kafka-console-producer.sh --bootstrap-server localhost:9092 --topic order-status \
--reader-property parse.key=true --reader-property key.separator=: --reader-property null.marker=NULL
>order-2:NULL
урок из курса
Урок из курса «Data Engineering». Курс покупается один раз и остаётся навсегда: 500 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.