могу рассказать как в Apache Avro предлагается решать вопросы версионирования.
допустим есть схема
User {
Int64 id,
String name
}
мы схему опубликовали в schema registry и к каждому сообщению заголовком добавляем имя и ID схемы в schema registry. все потребители у себя её включили, скачивают схему со schema registry по id, кешируют и декодируют что мы им присылаем этой схемой. Понаписали своих Java классов с полями id и name.
мы решили ужать id до Int32 (не спрашивайте) и добавить поле surname
User {
Int64 id,
String name,
String surname
}
опубликовали новую версию в Schema registry - она получила новый ID. Мы теперь его пристёгиваем к сообщениям.
Клиент при получении сообщения с новой версией скачивает новую схему и декодирует ей. Видит что там Int32 и кастит его в int64. Видит surname и просто игнорирует его.
С удалением сложнее. Удалять поля просто так нельзя. Поле должно иметь default значение или быть nullable.
Менять тип например с int на string тоже нельзя. Создаешь рядом поле типа string и какое-то время пишешь сообщения с обоими полями пока все не обновятся. Есть набор правил по которым схема "писателя" может быть проверена на обратную совместимость со схемой "читателя"
https://avro.apache.org/docs/1.9.2/spec.html#Schema+Resolution