Контентные модели и проблемы эволюции JSON-схем
Yandex Schema Registry поддерживает работу со схемами Avro
Например, добавление опционального параметра в схему Avro или Protobuf считается совместимым изменением схемы, а в JSON-схеме это же действие может как нарушить, так и не нарушить совместимость схем, в зависимости от используемой контентной модели.
Чтобы сохранить совместимость при эволюции JSON-схем, применяются проверки совместимости, правила которых задаются политиками проверки совместимости. В Schema Registry реализованы следующие политики для JSON-схем:
-
Confluent — не позволяет добавлять и удалять опциональные параметры в полях типа
object
. Иногда это ограничение может быть избыточным, например при работе с очередями. -
Optional Friendly — позволяет добавлять и удалять опциональные параметры в полях типа
object
, сохраняя полную транзитивную совместимость.
В этой статье описываются теоретические основы и реализация политики Optional-friendly
.
Совет
Если вы хотите использовать в Data Transfer JSON-схему с политикой проверки совместимости Optional-friendly
:
-
Задайте в пространстве имен политику проверки совместимости
Optional-friendly
. -
Задайте в настройках сериализации эндпоинта-приемника Yandex Managed Service for Apache Kafka® следующие настройки Debezium:
- Для ключа схемы:
key.converter.dt.json.generate.closed.content.schema
—true
. - Для значения схемы:
value.converter.dt.json.generate.closed.content.schema
—true
.
- Для ключа схемы:
Контентные модели JSON-схем
Контентная модель — это совокупность правил, по которым может изменяться поле типа object
в схеме. У разных полей в одной схеме могут быть разные контентные модели.
В JSON Schema существуют следующие контентные модели:
Открытая контентная модель
В открытой контентной модели можно использовать параметры, заданные в схеме, а также добавлять новые параметры любого типа. Эта модель используется по умолчанию.
Описание схемы в открытой контентной модели выглядит так:
{
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
},
"additionalProperties": true
}
Где additionalProperties
— возможность добавления параметров, true
или false
. По умолчанию параметр имеет значение true
, поэтому при описании схем в открытой контентной модели он часто опускается.
Закрытая контентная модель
В закрытой контентной модели можно использовать только параметры, заданные в схеме. Добавлять новые параметры нельзя.
Описание схемы в закрытой контентной модели выглядит так:
{
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
},
"additionalProperties": false
}
Частично открытая контентная модель
Частично открытая контентная модель позволяет добавлять новые параметры, если они соответствуют заданным ограничениям. Задать ограничения можно следующими способами:
- Разрешить добавление параметров только определенного типа, указав тип параметра в
additionalProperties
. - Разрешить добавление параметров определенных типов с именем заданного вида, перечислив регулярные выражения для имен и соответствующие им типы параметров в объекте
patternProperties
.
Ограничение по типу добавляемого параметра
Допустимые типы новых параметров описываются в параметре additionalProperties
. Добавлять параметры другого типа нельзя.
Описание схемы выглядит так:
{
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
},
"additionalProperties": {"type": "string"}
}
Эта схема разрешает добавлять только новые параметры типа string
.
Ограничение по типу добавляемого параметра на основе префикса имени параметра
Параметр additionalProperties
имеет значение false
, как в закрытой схеме. Допустимые новые параметры описываются в объекте patternProperties
, при этом имени каждого параметра присваивается префикс, указывающий на тип параметра. Имена параметров в схеме описываются регулярными выражениями. Нельзя добавлять параметры, не описанные в patternProperties
.
Описание схемы выглядит так:
{
"type": "object",
"properties": {
"s_name": {"type": "string"},
"i_age": {"type": "integer"}
},
"patternProperties": {
"^s_": {"type": "string"},
"^i_": {"type": "integer"}
},
"additionalProperties": false
}
Эта схема разрешает добавлять только:
- Параметры типа
string
, имена которых начинаются сs_
. - Параметры типа
integer
, имена которых начинаются сi_
.
Особенности эволюции JSON-схем в контентных моделях
Эволюция схемы — это изменение одного или нескольких параметров схемы или их свойств. В JSON-схеме возможны следующие изменения:
- добавление нового обязательного параметра;
- добавление нового опционального параметра;
- удаление обязательного параметра;
- удаление опционального параметра;
- изменение типа параметра с опционального на обязательный;
- изменение типа параметра с обязательного на опциональный.
Открытая и закрытая контентные модели по-разному ограничивают возможности эволюции схемы при сохранении совместимости с предыдущими схемами. Конкретные ограничения зависят от модели.
Открытая контентная модель
Изменение схемы | Прямая совместимость | Обратная совместимость | Полная совместимость |
---|---|---|---|
Добавление обязательного параметра | |||
Добавление опционального параметра | |||
Удаление обязательного параметра | |||
Удаление опционального параметра | |||
Изменение опционального параметра на обязательный | |||
Изменение обязательного параметра на опциональный |
Закрытая контентная модель
Изменение схемы | Прямая совместимость | Обратная совместимость | Полная совместимость |
---|---|---|---|
Добавление обязательного параметра | |||
Добавление опционального параметра | |||
Удаление обязательного параметра | |||
Удаление опционального параметра | |||
Изменение опционального параметра на обязательный | |||
Изменение обязательного параметра на опциональный |
Частично открытая контентная модель
Частично открытая контентная модель позволяет добавлять новые параметры с сохранением совместимости, указывая тип параметра в additionalProperties
. Однако таким способом можно добавлять в модель только параметры одного типа.
Чтобы добавить параметры сразу нескольких типов, перечислите в patternProperties
типы параметров, присвоив именам параметров соответствующий префикс. Необходимо описать все возможные параметры, включая объекты object
и массивы array
.
Такая реализация имеет следующие недостатки:
- Схема становится громоздкой и трудноподдерживаемой.
- Возможную ошибку в
patternProperties
нельзя исправить без потери совместимости. - Нельзя использовать новые типы параметров, если такие будут добавлены в спецификацию JSON, потому что они не описаны в
patternProperties
. - Схема работает, только если имена всех параметров строго соответствуют описанным шаблонам. Это возможно, только если вы контролируете производителя данных.
Сохранение совместимости при эволюции опциональных параметров
Используя открытые и закрытые контентные модели JSON-схем, невозможно обеспечить полную совместимость при добавлении или удалении опциональных параметров. Это приводит к возникновению ошибок PROPERTY_ADDED_TO_OPEN_CONTENT_MODEL
и PROPERTY_REMOVED_FROM_CLOSED_CONTENT_MODEL
при операциях с опциональными параметрами. Частично открытая контентная модель обеспечивает совместимость в этих случаях, но имеет существенные недостатки.
Альтернатива применению конкретной модели — использовать разные контентные модели для производителей и потребителей данных:
- Производитель должен использовать закрытую контентную модель, потому что на стороне производителя всегда известен точный набор параметров.
- Потребитель должен использовать открытую контентную модель, потому что потребители получают набор параметров только из поступающих данных, а неизвестные параметры игнорируются.
При этом в реестре схем регистрируется только схема данных производителя. Схема для потребителя генерируется по необходимости на основе схемы производителя, но не регистрируется в реестре. Единственным отличием схем производителя и потребителя становится использование разных контентных моделей. Это сводит проверку совместимости схем к конвертации схемы потребителя из открытой контентной модели в закрытую и проверке схем в реестре производителя. Если аналогичная схема зарегистрирована в реестре для производителя, то проверка на совместимость пройдена. В то же время схема потребителя может содержать дополнительные параметры из других зарегистрированных схем производителя. Для поддержки полной транзитивной совместимости требуется, чтобы схема потребителя была совместима хотя бы с одной зарегистрированной схемой производителя. Подробнее о теоретическом обосновании
Schema Registry поддерживает проверку совместимости схем через конвертацию открытой схемы потребителя в закрытую. Для этого задайте в пространстве имен для JSON-схем политику проверки совместимости Optional-friendly
. Вы можете задать политику для нового пространства имен или изменить ее для существующего пространства. Чтобы политика Optional-friendly
работала корректно, схемы в пространстве имен должны создаваться по закрытой контентной модели.
Вы также можете использовать это решение для сохранения совместимости JSON-схем при поставке данных в Yandex Managed Service for Apache Kafka® через Yandex Data Streams Yandex Data Transfer. Подробнее о требуемых настройках эндпоинта Data Transfer см. в инструкции.