Сериализация и Schema Registry
Урок про контракт данных в Kafka: как договориться о форме событий, чтобы продюсеры и консьюмеры не ломали друг друга.
Schema Registry — сервис, хранящий схемы сообщений (Avro, Protobuf, JSON Schema) и проверяющий их совместимость при изменениях, чтобы эволюция формата не ломала потребителей.
Зачем это нужно
Для Kafka сообщение — это просто байты. Если продюсер шлёт сырой JSON, а консьюмер ждёт определённые поля, то стоит продюсеру переименовать поле или сменить тип — консьюмеры падают, и узнаёте вы об этом в проде. Нужен контракт: формальная схема событий, которую обе стороны разделяют и которую нельзя сломать незаметно.
Бинарные форматы со схемой
Avro и Protobuf сериализуют данные по схеме: схема описывает поля и типы, а на проводе летит компактный бинарный код, а не многословный JSON с повторяющимися именами полей. Это и меньше байт, и строгая типизация.
{
"type": "record",
"name": "Order",
"fields": [
{"name": "order_id", "type": "string"},
{"name": "amount", "type": "double"},
{"name": "currency", "type": "string", "default": "RUB"}
]
}
Как работает Registry
Продюсер -> регистрирует/находит схему в Registry -> получает schema id В сообщение пишется: [magic][schema id][бинарные данные] Консьюмер -> читает schema id -> тянет схему из Registry -> декодирует
В сам топик летит не схема, а её короткий id. Консьюмер по id получает точную схему, которой данные были закодированы, и корректно их разбирает — даже если у него «своя» версия схемы.
Эволюция схем и совместимость
| Тип совместимости | Правило |
| BACKWARD | новый консьюмер читает старые данные (можно удалять поля / добавлять с default) |
| FORWARD | старый консьюмер читает новые данные (можно добавлять поля) |
| FULL | и то, и другое одновременно |
Registry при регистрации новой версии схемы проверяет её совместимость со старой по выбранному правилу и отклоняет несовместимое изменение. Так ломающее изменение не попадёт в прод: его завернут на этапе деплоя продюсера.
Как работает под капотом
Поле с default — ключ к совместимости: если новый консьюмер встречает старое сообщение без поля currency, он подставит "RUB" из схемы; если старый консьюмер встречает новое поле, которого не знает, он его проигнорирует. Avro кодирует данные позиционно по схеме, без имён полей в каждом сообщении, поэтому совпадение схем критично — именно schema id на проводе связывает байты с правильной схемой. Registry хранит версии схем под «subject» (обычно имя-топика-value) и ведёт их историю.
Частые ошибки
- Сырой JSON без схемы в прод-топиках. Любое изменение формата — мина под потребителей.
- Добавить поле без default. Ломает BACKWARD-совместимость: старые данные не прочитать новой схемой.
- Менять тип поля. Смена
int -> stringпочти всегда несовместима; вводите новое поле.
Итоги
- Схема — это контракт данных; Avro/Protobuf дают компактность и строгую типизацию.
- В топик пишется schema id, по нему консьюмер берёт точную схему из Registry.
- Registry проверяет совместимость (BACKWARD/FORWARD/FULL) и отклоняет ломающие изменения.