Как правильно передавать данные в Kafka, чтобы избежать проблем с изменяемостью объектов?
Что проверяют
Понимаете ли вы, где на самом деле возникает проблема с изменяемыми объектами при работе с Kafka, а не просто знаете слово «иммутабельность». Следом спрашивают, что будет, если поменять объект после send(), и как это устроено в Kafka Streams.
Как отвечать
Разберите по местам, где объект живёт:
- продюсер:
KafkaProducer.send()асинхронный, но ключ и значение сериализуются синхронно, ещё внутри вызова. После возврата изsend()байты сообщения зафиксированы. Опасность в другом: если объект держат в своём буфере для повторной отправки или читают в колбэке, там окажется уже изменённое состояние; - Kafka Streams: когда у узла топологии несколько потомков, одно и то же значение передаётся каждому по ссылке, без копии. Мутация в
peek()илиmapValues()одной ветки видна в другой, поэтому обработчики возвращают новый объект; - консьюмер: десериализованный объект отдают в пул потоков или кладут в кэш и меняют из нескольких мест. Это обычная гонка данных, и Kafka тут ни при чём.
Как сделать класс сообщения неизменяемым:
record: в Java 16+ даётfinal-поля и конструктор без лишнего кода, Jackson их поддерживает;- глубокая неизменяемость:
final List<Item>защищает ссылку, но не содержимое. В компактном конструкторе пишитеitems = List.copyOf(items); - типы:
InstantиLocalDateвместо изменяемогоjava.util.Date,BigDecimalвместоdoubleдля денег.
Добавьте уровень выше: сообщение в топике это факт, который нельзя отредактировать. Исправление отправляют новым событием, а формат держат в Avro или Protobuf со Schema Registry, чтобы изменения схемы проверялись на совместимость.
Где спотыкаются
Считают, что final на поле со списком делает сообщение неизменяемым. Список остаётся изменяемым, и его содержимое правят уже после создания события.
Думают, что Avro или JSON сами решают проблему изменяемости. Сериализация фиксирует байты, но не защищает объект в памяти до неё и после.
Меняют ключ сообщения в обработчике. Ключ определяет партицию, и такая правка ломает порядок событий и работу с состоянием по ключу.