Schema Registry не просто хранит схемы — он контролирует их эволюцию. При регистрации новой версии схемы Schema Registry проверяет её совместимость с существующими версиями согласно настроенному режиму. Если проверка не пройдена, HTTP 409 Conflict: новая версия отклонена.
Понимание режимов совместимости — это понимание того, какие изменения вы можете делать со схемой без нарушения контракта.
Зачем нужны режимы совместимости
Без проверки совместимости любой разработчик может опубликовать любую схему. Команда потребителей узнаёт о breaking change только когда начинаются ошибки десериализации в production.
Schema Registry решает это через явную политику совместимости: перед приёмом новой версии схемы он проверяет, выполняются ли условия совместимости. Проверка происходит на стороне Schema Registry, до того как продюсер начнёт использовать новую схему.
Тест совместимости можно выполнить вручную через REST API, не регистрируя схему:
POST /compatibility/subjects/{subject}/versions/latestContent-Type: application/vnd.schemaregistry.v1+json{"schema": "...", "schemaType": "AVRO"}# Ответ: {"is_compatible": true} или {"is_compatible": false, "messages": [...]}
BACKWARD (режим по умолчанию)
Определение: Новая схема может читать данные, написанные со старой схемой.
Направление читаемости: новый читатель — старые данные. Потребители обновляются первыми, до обновления продюсера.
Разрешённые изменения:
Добавить поле с default (или с union ["null", type] + "default": null) — старые данные не содержат поле, но новый reader возьмёт default.
Удалить поле, которое имеет default в новой схеме — reader просто не будет использовать это поле.
Запрещённые изменения:
Добавить обязательное поле без default — новый reader не может прочитать старые данные, в которых поля нет.
Переименовать поле (без alias) — новый reader не найдёт поле по имени.
Изменить тип несовместимым образом — binary encoding не совпадёт.
Типичный use case: Микросервисная команда обновляет Consumer перед тем, как Producer начнёт отправлять новые поля. Consumer готов к новому формату заранее.
FORWARD
Определение: Старая схема может читать данные, написанные с новой схемой.
Направление читаемости: старый читатель — новые данные. Продюсеры обновляются первыми, до обновления потребителей.
Разрешённые изменения:
Удалить поле — старый reader просто не знает об этом поле, использует default если есть.
Добавить поле с default в новой схеме — старый reader игнорирует неизвестные поля (в Avro — unknown fields). Default в старой схеме не нужен.
Запрещённые изменения:
Добавить обязательное поле без default в новой схеме — старый reader, читающий новые данные, не знает как обработать поле, которое есть в данных, но отсутствует в его схеме.
Типичный use case: CI/CD pipeline где продюсер деплоится независимо. Старые потребители должны продолжать работать с новым форматом данных.
FULL
Определение: Новая схема BACKWARD-совместима со старой И FORWARD-совместима со старой одновременно.
FULL — это пересечение условий BACKWARD и FORWARD. Это наиболее ограничительный режим из трёх.
Разрешённые изменения:
Добавить поле с default — разрешено: удовлетворяет BACKWARD (новый reader читает старые данные, использует default) и FORWARD (старый reader игнорирует новое поле в новых данных).
Удалить поле, если default присутствует в старой схеме — разрешено: BACKWARD (новый reader, читая старые данные, не видит поля, не нужен); FORWARD (старый reader, читая новые данные без удалённого поля, берёт default из своей схемы).
Запрещённые изменения:
Добавить обязательное поле без default.
Удалить поле без default.
Любое изменение типа, кроме допустимых promotions.
Типичный use case: Rolling upgrade, когда старые и новые версии Producer и Consumer работают одновременно. Каждый должен уметь читать данные, написанные другой версией.
NONE
Определение: Никакая проверка совместимости не выполняется. Любая схема принимается.
NONE полностью отключает защиту Schema Registry от breaking changes.
Разрешено всё: Добавление обязательных полей, удаление любых полей, изменение типов, переименование — Schema Registry принимает любую схему.
Запрещено ничего: NONE = отсутствие контракта.
WARNING
NONE mode отключает все проверки совместимости. Используйте только в development или при первоначальном создании subject. В production минимальный рекомендуемый уровень — BACKWARD. Установка NONE в production фактически означает отказ от Schema Registry как инструмента защиты контракта.
TRANSITIVE варианты
По умолчанию BACKWARD, FORWARD и FULL проверяют совместимость только с последней версией схемы (latest). Если у вас версии V1, V2, V3 — Schema Registry при регистрации V3 проверит только совместимость V3 с V2.
Это создаёт проблему: V3 совместима с V2, V2 совместима с V1, но V3 может быть несовместима с V1 напрямую. Потребитель, который по какой-то причине пропустил V2, получит данные V3, которые он не может прочитать.
TRANSITIVE-варианты решают это: проверка ведётся против всех предыдущих версий, не только последней.
Mode
Проверяет против
BACKWARD
Только предыдущей версии (latest)
BACKWARD_TRANSITIVE
Всех предыдущих версий
FORWARD
Только предыдущей версии (latest)
FORWARD_TRANSITIVE
Всех предыдущих версий
FULL
Только предыдущей версии (latest)
FULL_TRANSITIVE
Всех предыдущих версий
Практическое значение FULL_TRANSITIVE: Гарантирует, что любой потребитель с любой предыдущей версией схемы сможет читать данные, написанные с любой версией схемы. Максимальная гарантия совместимости в системах с долгим retention.
Настройка режима совместимости
Глобально (для всех новых subjects):
PUT /config{"compatibility": "FULL_TRANSITIVE"}
Переопределение для конкретного subject:
PUT /config/orders-value{"compatibility": "BACKWARD"}
Читать текущую настройку:
GET /config/orders-value# {"compatibilityLevel": "BACKWARD"}GET /config# {"compatibilityLevel": "FULL_TRANSITIVE"}
Если у subject нет собственной настройки, он наследует глобальную. Это позволяет установить строгий режим глобально (FULL_TRANSITIVE) и ослабить его для отдельных subjects, где это обосновано (например, development-only topics с NONE).
Таблица разрешённых изменений
Изменение
BACKWARD
FORWARD
FULL
NONE
Добавить поле с default
Да
Нет
Да
Да
Удалить поле с default
Нет
Да
Да
Да
Добавить обязательное поле
Нет
Нет
Нет
Да
Удалить обязательное поле
Нет
Нет
Нет
Да
Допустимое изменение типа (int→long)
Да
Да
Да
Да
Недопустимое изменение типа
Нет
Нет
Нет
Да
Переименовать поле (без alias)
Нет
Нет
Нет
Да
Визуализация режимов
Schema Registry: режимы совместимости
Режим
Добавить поле
Удалить поле
Изменить тип
BACKWARDBACKWARD: новая схема может читать данные, записанные старой схемой. Потребители могут обновляться до новой схемы, не дожидаясь обновления производителей. Режим по умолчанию в Confluent Schema Registry. Пример: добавление нового optional-поля с default — безопасно, потому что старые данные не содержат этого поля, и Avro подставит значение по умолчанию.
~Допустимо с условием: новое поле должно иметь значение default. Avro использует default при чтении старых записей, у которых этого поля нет. Добавление обязательного поля (без default) запрещено — старые данные нельзя прочитать новой схемой.
xЗапрещено в BACKWARD: если новая схема не содержит поля, которое есть в старых данных, Avro не знает, куда его поместить при десериализации. Исключение: если поле было optional с default в старой схеме и отсутствие его в новой не нарушает чтение — это граничный кейс.
xЗапрещено в BACKWARD: изменение типа поля (например, int -> long или string -> bytes) несовместимо с бинарной кодировкой Avro. Avro Reader Schema использует тип из новой схемы для декодирования байт, закодированных старой схемой — несовпадение типов приводит к ошибке десериализации.
FORWARDFORWARD: старая схема может читать данные, записанные новой схемой. Производители могут обновляться до новой схемы, не дожидаясь обновления потребителей. Удобно при rolling upgrade производителей. Пример: удаление поля из новой схемы — старые потребители просто игнорируют отсутствующее поле (Avro reader schema resolution).
~Допустимо с условием: в новой схеме новое поле должно иметь default. Старые потребители, читающие данные новой схемы, не знают об этом поле и игнорируют его. Без default это допустимо для Avro (unknown fields dropped), но нарушает семантическую целостность — поле появится без значения.
+Разрешено в FORWARD: новая схема не содержит поля, которое есть в старой. При чтении новых данных старой схемой (старый потребитель) — Avro reader schema resolution подставляет значение default из старой схемы для отсутствующего поля. Если поле в старой схеме было required (без default) — FORWARD нарушается.
xЗапрещено в FORWARD: изменение типа несовместимо бинарно. Старые потребители используют старую схему для чтения байт, закодированных новой схемой с другим типом — декодирование завершится ошибкой или некорректными данными.
FULLFULL: оба направления совместимости одновременно (BACKWARD + FORWARD). Самый строгий режим без отключения проверок. Производители и потребители могут обновляться в любом порядке. Рекомендован для production-систем с несколькими командами. Ограничение: можно только добавлять/удалять optional-поля с default в обеих схемах.
~Допустимо с условием: поле должно быть optional с default в новой схеме (BACKWARD требование) И желательно с default в старой схеме (для полной предсказуемости). Фактически FULL = пересечение BACKWARD и FORWARD — только изменения, удовлетворяющие обоим, проходят проверку.
~Допустимо с условием: поле должно иметь default в старой схеме (BACKWARD: новая схема читает старые данные — подставляет default для отсутствующего поля) И в новой схеме не нужно это поле (FORWARD: старая схема читает новые данные — игнорирует отсутствующее поле). Обязательные поля без default удалять нельзя.
xЗапрещено в FULL: изменение типа нарушает как BACKWARD, так и FORWARD совместимость. Ни новые потребители со старыми данными, ни старые потребители с новыми данными не смогут корректно декодировать записи с несовместимым типом.
NONENONE: совместимость не проверяется. Schema Registry принимает любую схему. Опасен в production: сломает десериализацию у consumer при любом несовместимом изменении. Допустим только в разработке, тестировании или для топиков с одним продюсером и одним консьюмером под полным контролем одной команды.
+Разрешено в NONE: Schema Registry не проверяет ни одно изменение. Любое поле можно добавить без ограничений. Предупреждение: если производитель добавляет обязательное поле без default, старые потребители получат ошибку десериализации. Отсутствие проверки != отсутствие риска.
+Разрешено в NONE: любое поле можно удалить. Schema Registry не блокирует изменение. Предупреждение: потребители, ожидающие это поле, получат ошибку или null при десериализации. В NONE вся ответственность за совместимость лежит на команде разработки.
+Разрешено в NONE: любое изменение типа принимается Schema Registry. Предупреждение: изменение типа (например, int на string) несовместимо бинарно в Avro — старые потребители упадут с ошибкой DecodeException при попытке прочитать новые данные. NONE не защищает от production-инцидентов.
Legenda
Допустимо+Разрешено: операция совместима с данным режимом проверки. Schema Registry примет новую версию схемы без ошибки.
ЗапрещеноxЗапрещено: операция нарушает совместимость. Schema Registry вернёт HTTP 409 Conflict при попытке зарегистрировать несовместимую схему. Проверить заранее можно через POST /compatibility/subjects/{subject}/versions/latest.
Условно~Условно допустимо: операция разрешена только при соблюдении дополнительных требований (например, наличие default-значения). Наведите курсор на ячейку для деталей.
Транзитивные режимы
BACKWARD_TRANSITIVEBACKWARD_TRANSITIVE: новая схема совместима со ВСЕМИ предыдущими версиями (не только с последней). BACKWARD проверяет только против latest. BACKWARD_TRANSITIVE проверяет против v1, v2, v3, ..., latest. Используйте когда у вас долгоживущие потребители, читающие данные с разными версиями схемы из одного топика.
FORWARD_TRANSITIVEFORWARD_TRANSITIVE: все предыдущие версии схемы могут читать данные, записанные новой схемой. Строже обычного FORWARD — гарантирует совместимость не только с последней версией, но со всей историей схем. Актуально при долгосрочной поддержке нескольких версий API.
FULL_TRANSITIVEFULL_TRANSITIVE: самый строгий режим. Новая схема BACKWARD_TRANSITIVE-совместима со всеми предыдущими И FORWARD_TRANSITIVE-совместима со всеми предыдущими одновременно. Подходит для публичных API с долгим жизненным циклом и требованием обратной совместимости в обоих направлениях.
Проверка знанийKnowledge check
Команда хочет зарегистрировать новую версию схемы, которая добавляет обязательное поле без значения по умолчанию. При каком режиме совместимости Schema Registry примет эту регистрацию?
ОтветAnswer
Только при режиме NONE. Все остальные режимы (BACKWARD, FORWARD, FULL и их TRANSITIVE-варианты) отклоняют добавление обязательного поля без default: BACKWARD — потому что новый reader не может прочитать старые данные без этого поля; FORWARD — потому что старый reader не знает как обработать обязательное поле, которого нет в его схеме; FULL — нарушает оба условия. NONE единственный режим без проверок.