Обновление схем и совместимость схем#

Важным аспектом управления данными является обновление схемы. После определения исходной схемы приложениям, возможно, потребуется со временем ее изменить. Когда это происходит, для последующих потребителей критически важно иметь возможность беспрепятственно обрабатывать данные, закодированные как со старой, так и с новой схемой. Если не продумать решение этого вопроса в начале работы, в будущем это потребует значительных затрат.

Обновление схем#

При использовании таких форматов сериализации/десериализации, как Avro и JSON Schema, следует помнить о важности управления схемами и учитывать, как эти схемы должны обновляться. Schema Registry создан именно для этой цели. Проверка совместимости схем реализована в Schema Registry путем версионирования каждой отдельной схемы. Тип совместимости определяет, как Schema Registry сравнивает новую схему с предыдущими версиями схемы для данного субъекта. Когда схема впервые создается для субъекта, она получает уникальный идентификатор и номер версии, например, версия 1. Когда схема обновляется (если она проходит проверку на совместимость), она получает новый уникальный идентификатор и увеличенный номер версии, например, версию 2.

Совместимость схем#

Режимы совместимости#

В таблице представлены типы изменений схемы, допустимые для различных типов совместимости для конкретного субъекта. Тип совместимости Schema Registry по умолчанию — BACKWARD. Все типы совместимости более подробно описаны в следующих разделах.

Режим совместимости

Описание

Разрешенные операции

С какой версией схемы сравнивается

Обновляются в первую очередь

BACKWARD

Сообщения, сгенерированные предыдущей схемой, могут быть прочитаны новой

DELETE_REQUIRED_FIELD
DELETE_OPTIONAL_FIELD
ADD_OPTIONAL_FIELD
BECOME_OPTIONAL

Предыдущая версия

Потребители

BACKWARD_TRANSITIVE

Сообщения, сгенерированные любой предыдущей схемой, могут быть прочитаны новой

DELETE_REQUIRED_FIELD
DELETE_OPTIONAL_FIELD
ADD_OPTIONAL_FIELD
BECOME_OPTIONAL

Все предыдущие версии

Потребители

FORWARD

Сообщения, сгенерированные новой схемой, могут быть прочитаны предыдущей

ADD_REQUIRED_FIELD
ADD_OPTIONAL_FIELD
DELETE_OPTIONAL_FIELD
BECOME_REQUIRED

Предыдущая версия

Производители

FORWARD_TRANSITIVE

Сообщения, сгенерированные новой схемой, могут быть прочитаны предыдущей

ADD_REQUIRED_FIELD
ADD_OPTIONAL_FIELD
DELETE_OPTIONAL_FIELD
BECOME_REQUIRED

Все предыдущие версии

Производители

FULL

Сообщения, сгенерированные предыдущей версией схемы, могут быть прочитаны текущей, а сообщения, сгенерированные новой версией, могут быть прочитаны любой предыдущей

ADD_OPTIONAL_FIELD
DELETE_OPTIONAL_FIELD

Предыдущая версия

В любом порядке

FULL_TRANSITIVE

Сообщения, сгенерированные предыдущей версией схемы, могут быть прочитаны текущей, а сообщения, сгенерированные новой версией, могут быть прочитаны предыдущей

ADD_OPTIONAL_FIELD
DELETE_OPTIONAL_FIELD

Все предыдущие версии

В любом порядке

NONE

Все изменения принимаются

Проверка совместимости не выполняется

Проверка совместимости не выполняется

В любом порядке

Внимание

Вызов режима совместимости в REST API является глобальным, то есть он отменяет любые параметры совместимости, установленные в файлах свойств Schema Registry.

Различие в правилах совместимости для Avro и JSON Schema#

Обновление схем и правила совместимости отличаются в зависимости от формата схемы. Сценарии и примеры исходного кода, приведенные в этом разделе, предназначены для формата Avro, который был первым сериализатором/десериализатором, поддерживаемым Schema Registry. Avro был разработан с учетом обновления схем, и в его спецификации четко прописаны правила обратной совместимости; в то время как правила и грамматика для JSON Schema могут иметь больше нюансов.

Хотя общие понятия применимы ко всем форматам, детали реализации совместимости будут отличаться в зависимости от того, какой формат схем используется — Avro, JSON Schema или Protobuf. Более подробные объяснения и конкретные примеры по новым форматам можно найти в следующих статьях блога и документации:

Обратная совместимость BACKWARD#

Совместимость BACKWARD означает, что потребители, использующие новую схему, могут читать данные, созданные с помощью предыдущей схемы.

Предположим, что для субъекта существует три схемы, которые изменяются в порядке X-2, X-1 и X. Тогда совместимость BACKWARD гарантирует, что потребители, использующие новую схему X, смогут обрабатывать данные, записанные производителями, использующими схему X или X-1, но не обязательно X-2.

Если потребитель, использующий новую схему, должен иметь возможность обрабатывать данные, записанные всеми зарегистрированными схемами, а не только двумя последними, используйте совместимость BACKWARD_TRANSITIVE.

Режимы совместимости:

  • BACKWARD: потребитель, использующий схему X, может обрабатывать данные, созданные с помощью схемы X или X-1;

  • BACKWARD_TRANSITIVE: потребитель, использующий схему X, может обрабатывать данные, созданные с помощью схемы X, X-1 или X-2.

Примечание

Тип совместимости Schema Registry по умолчанию — BACKWARD. Основная причина, по которой режим совместимости BACKWARD является стандартным и предпочтительным для Kafka, заключается в том, что можно «перемотать» потребителей к началу топика. При использовании режима совместимости FORWARD не гарантируется возможность чтения старых сообщений. Кроме того, с режимом совместимости FORWARD сложнее работать из-за необходимости предвидеть все будущие изменения. Например, в режиме совместимости FORWARD с Protobuf нельзя добавлять новые типы сообщений в схему.

Пример изменения с обратной совместимостью BACKWARD — удаление поля. Потребитель, который был разработан для обработки событий без этого поля, сможет обрабатывать события, написанные по старой схеме и содержащие это поле. В таком случае потребитель просто проигнорирует это поле.

Рассмотрим случай, когда все данные из Kafka также загружены в файловую систему HDFS, и требуется выполнить SQL-запросы (например, с помощью Apache Hive) ко всем данным. Здесь важно, чтобы одни и те же SQL-запросы продолжали работать, даже если данные претерпевают изменения с течением времени. Чтобы поддержать такой вариант использования, можно изменить схемы таким образом, чтобы они были обратно совместимы. Все форматы, сериализаторы и десериализаторы имеют правила относительно того, какие изменения допускаются в новой схеме, чтобы она была обратно совместима. Например, правила совместимости Avro. Если все схемы обновляются обратно совместимым образом, всегда можно использовать последнюю схему для единообразного запроса всех данных.

Пример добавления нового поля favorite_color в схему:

{"namespace": "example.avro",
"type": "record",
"name": "user",
"fields": [
     {"name": "name", "type": "string"},
     {"name": "favorite_number",  "type": "int"},
     {"name": "favorite_color", "type": "string", "default": "green"}
]
}

Обратите внимание, что новое поле favorite_color имеет значение по умолчанию green. Это позволяет читать по новой схеме данные, закодированные по старой схеме. Значение по умолчанию, указанное в новой схеме, будет использоваться для отсутствующего поля при десериализации данных, закодированных по старой схеме. Если бы значение по умолчанию в новом поле было опущено, новая схема не была бы обратно совместима со старой, поскольку было бы непонятно, какое значение должно быть присвоено новому полю, отсутствующему в старых данных.

Прямая совместимость FORWARD#

Совместимость FORWARD означает, что данные, созданные по новой схеме, могут быть прочитаны потребителями, использующими предыдущую схему, даже если они не могут использовать все возможности новой схемы.

Предположим, что для субъекта существуют три схемы, которые изменяются в порядке X-2, X-1 и X. Тогда совместимость FORWARD гарантирует, что данные, записанные производителями с использованием новой схемы X, могут быть обработаны потребителями, использующими схему X или X-1, но не обязательно X-2.

Если данные, созданные по новой схеме, должны быть прочитаны потребителями, использующими все зарегистрированные схемы, а не только две последние, используйте совместимость FORWARD_TRANSITIVE.

Режимы совместимости:

  • FORWARD: данные, созданные с использованием схемы X, могут быть прочитаны потребителями со схемой X или X-1;

  • FORWARD_TRANSITIVE: данные, созданные с использованием схемы X, могут быть прочитаны потребителями со схемами X, X-1 или X-2.

Пример модификации схемы с прямой совместимостью – добавление нового поля. В большинстве форматов данных потребители, которые были написаны для обработки событий без нового поля, смогут продолжать это делать даже при получении новых событий, содержащих новое поле.

Рассмотрим случай, когда потребитель имеет логику приложения, привязанную к определенной версии схемы. Когда схема изменяется, логика приложения может быть обновлена не сразу. Поэтому необходимо иметь возможность проецировать данные с более новыми схемами на более старую схему, которую понимает приложение. Чтобы поддержать этот вариант использования, можно обновить схемы совместимым образом: данные, закодированные в новой схеме, могут быть прочитаны с помощью старой схемы. Например, новая схема пользователя, показанная в разделе об обратной совместимости, также совместима со старой. При проецировании данных, записанных по новой схеме, на старую схему, новое поле просто отбрасывается. Если бы новая схема отказалась от исходного поля favorite_number, она не была бы совместима с исходной схемой пользователя, поскольку потребители не знали бы, как заполнить значение favorite_number для новых данных, так как в исходной схеме не было указано значение по умолчанию для этого поля.

Полная совместимость FULL#

Полная совместимость FULL означает, что схемы совместимы как в обратном, так и в прямом направлении в пределах новой и текущей версий. Схемы обновляются полностью совместимым образом: старые данные могут быть прочитаны с помощью новой схемы, а новые данные также могут быть прочитаны с помощью последней схемы.

Предположим, что для субъекта существуют три схемы, которые изменяются в порядке X-2, X-1 и X. Тогда совместимость FULL гарантирует, что:

  • потребители, использующие новую схему X, могут обрабатывать данные, написанные производителями, использующими схему X или X-1, но не обязательно X-2;

  • данные, написанные производителями, использующими новую схему X, могут быть обработаны потребителями, использующими схему X или X-1, но не обязательно X-2.

Если новая схема должна быть совместима в прямом и обратном направлении со всеми зарегистрированными схемами, а не только с двумя последними, используйте совместимость FULL_TRANSITIVE.

Режимы совместимости:

  • FULL: совместимость между схемами X и X-1 в прямом и обратном направлении;

  • FULL_TRANSITIVE: совместимость схем X, X-1 и X-2 в прямом и обратном направлении.

В формате Avro можно определить поля со значениями по умолчанию. В этом случае добавление или удаление поля со значением по умолчанию является полностью совместимым изменением.

Правила совместимости для поддерживаемых типов схем описаны в разделе «Проверка совместимости форматов» .

JSON Schema не определяет правила совместимости в явном виде.

Примечание

В качестве описание того, как работает совместимость JSON Schema, включая полную совместимость, приводится статья. Статья не является проверенным или официальным источником технических сведений. Данные могут быть искажены, неполны или не актуальны. Ссылка приведена в справочных целях.

Проверка совместимости отключена#

При режиме совместимости NONE проверки совместимости схем не выполняются.

В случае, если вносятся несовместимые изменения (например изменение типа поля с number на string), выполните одно из двух действий:

  • одновременно обновите всех производителей и потребителей до новой версии схемы;

  • создайте совершенно новый топик и начните перенос приложений для использования нового топика и новой схемы, избегая необходимости обрабатывать две несовместимые версии в одном топике (предпочтительный вариант).

Переходная совместимость TRANSITIVE#

Проверка переходной совместимости важна, когда существует более двух версий схемы для данного субъекта. Если совместимость настроена как переходная, то проверяется совместимость новой схемы со всеми ранее зарегистрированными схемами. В противном случае проверяется совместимость новой схемы только с самой последней схемой.

Например, если для субъекта существует три схемы, которые изменяются в порядке X-2, X-1 и X, то:

  • TRANSITIVE: обеспечивает совместимость между X-2 <==> X-1 и X-1 <==> X и X-2 <==> X;

  • не-TRANSITIVE: обеспечивает совместимость между X-2 <==> X-1 и X-1 <==> X, но не обязательно X-2 <==> X.

В Schema Registry глобальный режим совместимости — BACKWARD , который не является переходным. При нем новые схемы проверяются на совместимость только с последней схемой.

Порядок обновления клиентов#

Настроенный режим совместимости влияет на порядок обновления клиентских приложений: производителей, использующих схемы для записи событий в Kafka, и потребителей, использующих схемы для чтения событий из Kafka. В зависимости от режима совместимости:

  • BACKWARD или BACKWARD_TRANSITIVE: не гарантируется, что потребители, использующие старые схемы, смогут читать данные, созданные с использованием новой схемы. Сначала обновите потребителей, затем производителей.

  • FORWARD или FORWARD_TRANSITIVE: не гарантируется, что потребители, использующие новую схему, смогут читать данные, созданные с использованием старых схем. Сначала переведите всех производителей на новую схему и убедитесь, что данные, созданные с использованием старых схем, недоступны потребителям, а затем переведите потребителей. Сначала обновите производителей, затем потребителей.

  • FULL или FULL_TRANSITIVE: гарантируется, что потребители, использующие старые схемы, могут читать данные, созданные с помощью новой схемы, и что потребители, использующие новую схему, могут читать данные, созданные с помощью старых схем. Можно обновлять производителей и потребителей независимо друг от друга.

  • NONE: проверки совместимости отключены. Порядок обновления не важен.

Внимание

В любом не-TRANSITIVE режиме одновременно могут работать приложения, которые используют версии схемы, различающиеся не более чем на 1.

Порядок обновления схем для Kafka Streams#

Порядок обновления:

  1. Обновите приложение Kafka Streams.

  2. Безопасно обновите вышестоящий производитель, который пишет во входной топик.

Внимание

Для Kafka Streams поддерживается совместимость только с FULL, TRANSITIVE и BACKWARD.

Для простого потребителя безопасно обновлять его до новой схемы после обновления производителя, поскольку простой потребитель читает данные только из входного топика. Для Kafka Streams сценарий другой. Когда обновляется Kafka Streams, он также может читать из входного топика (который теперь содержит данные с новой схемой). Однако, в отличие от обычного потребителя, Kafka Streams также должен уметь читать старую схему (из состояния/логов изменений), поэтому поддерживается только совместимость BACKWARD.

Для Kafka Streams всегда поддерживается FULL и TRANSITIVE совместимость, поскольку они включают обратную совместимость и, по сути, являются более строгими настройками, чем BACKWARD.

Указание требований совместимости для каждого субъекта#

Настройки совместимости схем можно указать отдельно для каждого субъекта или глобально.