Learning Platform
Глоссарий Troubleshooting
Урок 11.04 · 25 мин
Средний
Schema GovernanceCI/CDMaven PluginGradle PluginSubject NamingTopicNameStrategyRecordNameStrategyUpgrade PatternsGitHub Actions

Governance и CI/CD интеграция

В предыдущем уроке мы разобрали, как Schema Registry хранит схемы, выбирает leader, раздаёт ID. Но Registry — это runtime-инструмент. Он проверяет совместимость в момент регистрации, а значит — уже после того, как разработчик написал код, собрал артефакт и запустил producer.

Проблема: если несовместимое изменение дошло до staging/production, producer получит HTTP 409 и не сможет писать данные. В лучшем случае — задержка на пару часов. В худшем — инцидент.

Governance — это перенос проверки совместимости влево по pipeline: из runtime в build-time, из production в CI/CD. Чем раньше сломанная схема обнаружена — тем дешевле починка.

Build-time проверка: Maven и Gradle плагины

Confluent Maven Plugin

Confluent предоставляет kafka-schema-registry-maven-plugin — проверяет локальные .avsc/.proto/.json файлы против текущего состояния Registry ещё на этапе mvn compile:

<plugin>
 <groupId>io.confluent</groupId>
 <artifactId>kafka-schema-registry-maven-plugin</artifactId>
 <version>7.9.0</version>
 <configuration>
 <schemaRegistryUrls>
 <param>http://schema-registry:8081</param>
 </schemaRegistryUrls>
 <subjects>
 <payments-value>src/main/avro/Payment.avsc</payments-value>
 </subjects>
 </configuration>
 <goals>
 <goal>test-compatibility</goal>
 </goals>
</plugin>

Плагин поддерживает три цели:

  • test-compatibility — проверяет совместимость локальной схемы с последней зарегистрированной версией
  • register — регистрирует схему (обычно в CD, не в CI)
  • download — скачивает текущие схемы из Registry (для code generation)

Gradle Plugin

Для Gradle — io.confluent.schema-registry плагин или community-альтернативы (com.github.imflog.kafka-schema-registry-gradle-plugin):

schemaRegistry {
 url = 'http://schema-registry:8081'
 compatibility {
 subject('payments-value', 'src/main/avro/Payment.avsc', 'AVRO')
 }
}
TIP

Храните .avsc/.proto файлы в отдельном Git-репозитории (schema repo), а не внутри сервиса. Это позволяет проверять совместимость независимо от деплоя конкретного сервиса и делать cross-team review изменений.

CI Pipeline: GitHub Actions / GitLab CI

Schema Governance Pipeline: от PR до Production

PR: изменение схемы

Разработчик меняет .avsc/.proto файл в schema-репозитории или сервисном репо и открывает Pull Request

CI: test-compatibility

CI запускает kafka-schema-registry-maven-plugin:test-compatibility или аналогичный Gradle таск. Требует доступ к staging Registry.

Совместима?

Если совместимость нарушена — CI красный, PR не мержится. Если ОК — переход к code review.

Code Review

Тимлид или schema owner ревьюит изменение. Проверяет: семантику полей, naming conventions, документацию. Automated checks не заменяют human review.

CD: register schema

После merge в main — CD pipeline регистрирует новую версию схемы в production Registry. Обычно через maven-plugin:register или REST API.

Schema в Registry

Схема зарегистрирована, получает глобальный ID. Producers могут начать использовать новую версию. Consumers с BACKWARD — уже готовы.

GitHub Actions пример

name: Schema Compatibility Check
on:
 pull_request:
 paths: ['schemas/**']

jobs:
 check:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - name: Test compatibility
 run: |
 mvn kafka-schema-registry:test-compatibility \
 -Dschema.registry.url=$STAGING_REGISTRY_URL
 env:
 STAGING_REGISTRY_URL: ${{ secrets.SCHEMA_REGISTRY_URL }}

GitLab CI пример

schema-check:
 stage: test
 script:
 - mvn kafka-schema-registry:test-compatibility
 -Dschema.registry.url=$STAGING_REGISTRY_URL
 rules:
 - changes:
 - schemas/**
WARNING

CI должен проверять совместимость против staging Registry (или dedicated CI Registry), а не production. Production Registry обновляется только через CD pipeline после merge.

Стратегии именования subjects

Subject — это “контейнер версий” в Registry. Как именно маппятся Kafka topics на subjects — определяет SubjectNameStrategy. Выбор стратегии влияет на то, сколько subjects будет создано и какие проверки совместимости применяются.

Три стратегии именования subjects
СтратегияSubjectNameStrategy определяет, как формируется имя subject в Registry из метаданных Kafka record
Формат subjectШаблон имени subject, где topic — имя Kafka topic, а record — полное имя типа из схемы (namespace.name)
Когда использоватьТипичный сценарий, в котором данная стратегия оптимальна
ОсобенностьКлючевое ограничение или преимущество стратегии
TopicNameStrategyСтратегия по умолчанию. Один subject на topic+direction. Все записи в топике должны иметь одну и ту же схему (или её backward-совместимую версию).
topic-value / topic-keyПример: payments-value, orders-key. Суффикс -value для value schema, -key для key schema.
1 тип на 1 топикСамый простой и распространённый случай: один Kafka topic содержит записи одного типа. Подходит для 90% сценариев.
Один subject на топикВсе версии схемы для данного топика проверяются на совместимость друг с другом. Нельзя иметь несовместимые типы в одном топике.
RecordNameStrategySubject формируется из полного имени типа (namespace + name). Позволяет нескольким типам записей жить в одном топике, каждый со своей линией совместимости.
namespace.RecordNameПример: com.company.Payment, com.company.Refund. Топик не участвует в имени subject.
Несколько типов в 1 топикеEvent sourcing, CQRS: один топик orders содержит OrderCreated, OrderShipped, OrderCancelled — каждый со своей эволюцией.
Совместимость per-typeКаждый тип эволюционирует независимо. Но: нет привязки к топику — один тип в разных топиках разделяет subject.
TopicRecordNameStrategyКомбинация: subject = topic + полное имя типа. Один и тот же тип в разных топиках — разные subjects, разные линии совместимости.
topic-namespace.RecordПример: orders-com.company.OrderCreated. Максимально гранулярно: per-topic, per-type.
Multi-type + изоляцияНесколько типов в топике + каждый топик имеет свою линию совместимости. Самая гибкая, но и самая verbose стратегия.
Взрыв subjectsПри N топиков × M типов = N×M subjects. В крупных системах может создать тысячи subjects. Мониторинг и governance усложняются.

Конфигурация на producer/consumer

// TopicNameStrategy (default)
props.put("value.subject.name.strategy",
 "io.confluent.kafka.serializers.subject.TopicNameStrategy");

// RecordNameStrategy
props.put("value.subject.name.strategy",
 "io.confluent.kafka.serializers.subject.RecordNameStrategy");

// TopicRecordNameStrategy
props.put("value.subject.name.strategy",
 "io.confluent.kafka.serializers.subject.TopicRecordNameStrategy");
NOTE

Стратегия именования — producer-side конфигурация. Consumer должен знать, какую стратегию использовал producer, чтобы запросить правильный subject из Registry. Рассогласование → consumer не найдёт схему.

Паттерны обновления: In-place vs Dual Schema

Как обновить схему, если у вас десятки producers и consumers, и не все обновляются одновременно?

In-place Evolution vs Dual Schema Upgrade
Паттерн 1: In-place Evolution (BACKWARD compatible)

Register v2 → deploy producers → consumers auto-resolve

Регистрируем schema v2 (backward compatible с v1). Новые producers начинают писать v2. Старые consumers продолжают читать — ResolvingDecoder обрабатывает v2 данные по правилам v1.
Паттерн 2: Dual Schema Upgrade (breaking change)
  1. Новый topic + schema
Шаг 1: Создаём новый топик с новой схемой. Старый топик продолжает работать. Оба топика активны одновременно.
  1. Bridge / dual-write
Шаг 2: Запускаем bridge-consumer: читает из старого топика, трансформирует данные, пишет в новый. Или: producers пишут в оба топика.
  1. Миграция consumers
Шаг 3: Мигрируем consumers на новый топик по одному. Каждый consumer переключается на новый topic, когда готов.
  1. Decommission
Шаг 4: Когда все consumers мигрировали — отключаем старый топик и bridge. Удаляем старый subject из Registry.

Когда какой паттерн

In-place — для backward/forward-совместимых изменений:

  • Добавление опционального поля с default
  • Удаление поля (при FORWARD)
  • Type promotion (int → long)

Dual schema — для breaking changes, которые нельзя сделать совместимыми:

  • Переименование поля без alias (Avro) или без сохранения field number (Protobuf)
  • Изменение типа поля на несовместимый
  • Смена формата сериализации (Avro → Protobuf)
TIP

Dual schema — дорогой паттерн (два топика, bridge, координация). Если breaking change можно разбить на серию backward-compatible шагов — это почти всегда дешевле. Пример: переименование поля в Avro = добавить новое поле + alias на старое → deprecate старое → через N релизов удалить.

Governance Workflow: кто владеет схемой?

В организации с десятками команд нужны чёткие правила:

Schema Governance: роли и ответственности
Schema Owner (Team)Команда-владелец subject. Только она имеет право менять схему через PR. Определяет compatibility level и naming conventions для своих subjects.
Affected ConsumersКоманды, чьи consumers читают данный subject. Должны быть нотифицированы и дать approval на изменения. Их consumer-код может потребовать обновления.
Platform / Schema AdminCentral governance team. Устанавливает глобальные правила (минимальный compatibility level, naming conventions), управляет CI pipeline, обеспечивает Registry доступность.
Workflow

PR → CI check → Owner review → Consumer review → Merge → CD register

PR в schema-репозиторий → CI проверяет compatibility + lint → Owner review → Consumers review → Merge → CD register. Весь процесс автоматизирован, human review — на семантику.
  1. Schema ownership — каждый subject привязан к команде. Только owner может менять схему.
  2. Approval process — PR в schema repo требует approval от schema owner И от affected consumers.
  3. Compatibility level per subject — критичные subjects (payments, orders) на FULL_TRANSITIVE, internal events — на BACKWARD.
  4. Schema review checklist:
  • Поле имеет документацию (doc в Avro, comment в Protobuf)
  • Default values для всех новых полей
  • Нет переиспользования удалённых field numbers (Protobuf reserved)
  • Naming convention соблюдён (snake_case / camelCase)
  1. Automated enforcement — CI проверяет совместимость + linting правила (naming, documentation, reserved).

buf для Protobuf governance

Для Protobuf-first команд buf предоставляет мощный governance-инструмент:

# buf.yaml
version: v2
lint:
 use:
 - STANDARD
breaking:
 use:
 - WIRE_JSON
# CI: проверка breaking changes
buf breaking --against '.git#branch=main'

# CI: lint
buf lint

buf breaking проверяет wire-совместимость (аналог test-compatibility, но без Registry), а buf lint — naming conventions, documentation, package structure.

Итоги

Schema governance — это не бюрократия, а инженерная дисциплина:

  • Build-time checks ловят несовместимые изменения до того, как они попадут в Registry
  • CI/CD pipeline автоматизирует проверку: PR → test-compatibility → review → register
  • Subject naming strategy определяет granularity совместимости — от per-topic до per-topic-per-type
  • In-place vs dual schema — два паттерна обновления для совместимых и breaking изменений
  • Ownership + review — человеческий контроль поверх автоматического

В следующем уроке — альтернативные реализации Schema Registry: Apicurio, AWS Glue, Karapace, buf BSR.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. CI pipeline проверяет совместимость схемы через maven kafka-schema-registry-maven-plugin:test-compatibility. Против какого Registry должен работать CI?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 6