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')
}
}
Храните .avsc/.proto файлы в отдельном Git-репозитории (schema repo), а не внутри сервиса. Это позволяет проверять совместимость независимо от деплоя конкретного сервиса и делать cross-team review изменений.
CI Pipeline: GitHub Actions / GitLab CI
PR: изменение схемы
Разработчик меняет .avsc/.proto файл в schema-репозитории или сервисном репо и открывает Pull RequestCI: 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/**
CI должен проверять совместимость против staging Registry (или dedicated CI Registry), а не production. Production Registry обновляется только через CD pipeline после merge.
Стратегии именования subjects
Subject — это “контейнер версий” в Registry. Как именно маппятся Kafka topics на subjects — определяет SubjectNameStrategy. Выбор стратегии влияет на то, сколько subjects будет создано и какие проверки совместимости применяются.
Конфигурация на 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");
Стратегия именования — producer-side конфигурация. Consumer должен знать, какую стратегию использовал producer, чтобы запросить правильный subject из Registry. Рассогласование → consumer не найдёт схему.
Паттерны обновления: In-place vs Dual Schema
Как обновить схему, если у вас десятки producers и consumers, и не все обновляются одновременно?
Register v2 → deploy producers → consumers auto-resolve
Регистрируем schema v2 (backward compatible с v1). Новые producers начинают писать v2. Старые consumers продолжают читать — ResolvingDecoder обрабатывает v2 данные по правилам v1.- Новый topic + schema
- Bridge / dual-write
- Миграция consumers
- Decommission
Когда какой паттерн
In-place — для backward/forward-совместимых изменений:
- Добавление опционального поля с default
- Удаление поля (при FORWARD)
- Type promotion (int → long)
Dual schema — для breaking changes, которые нельзя сделать совместимыми:
- Переименование поля без alias (Avro) или без сохранения field number (Protobuf)
- Изменение типа поля на несовместимый
- Смена формата сериализации (Avro → Protobuf)
Dual schema — дорогой паттерн (два топика, bridge, координация). Если breaking change можно разбить на серию backward-compatible шагов — это почти всегда дешевле. Пример: переименование поля в Avro = добавить новое поле + alias на старое → deprecate старое → через N релизов удалить.
Governance 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 — на семантику.- Schema ownership — каждый subject привязан к команде. Только owner может менять схему.
- Approval process — PR в schema repo требует approval от schema owner И от affected consumers.
- Compatibility level per subject — критичные subjects (payments, orders) на FULL_TRANSITIVE, internal events — на BACKWARD.
- Schema review checklist:
- Поле имеет документацию (doc в Avro, comment в Protobuf)
- Default values для всех новых полей
- Нет переиспользования удалённых field numbers (Protobuf
reserved) - Naming convention соблюдён (snake_case / camelCase)
- 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.