Контентные модели и проблемы эволюции 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 см. в инструкции.