Schema registry: governança de contratos de eventos

1. Fundamentos do Schema Registry na Arquitetura Orientada a Eventos

1.1. O problema da evolução descontrolada de contratos entre produtores e consumidores

Em arquiteturas orientadas a eventos, produtores e consumidores evoluem de forma independente. Sem governança, um produtor pode alterar o formato de um evento sem aviso, quebrando consumidores downstream. O cenário típico de falha:

  • Produtor adiciona um campo obrigatório userId em um evento OrderCreated
  • Consumidor antigo espera apenas orderId e amount
  • O consumidor falha ao desserializar o evento, gerando erros silenciosos ou perda de dados

Esse problema se agrava com dezenas de microsserviços e centenas de tipos de eventos.

1.2. Definição e papel central do Schema Registry como catálogo de contratos

O Schema Registry é um serviço centralizado que armazena, valida e versiona schemas de eventos. Funciona como um catálogo de contratos, garantindo que:

  • Todo evento publicado siga um schema registrado
  • Mudanças sejam compatíveis com consumidores existentes
  • Haja rastreabilidade de versões e evolução

Exemplo de schema registrado (Avro):

{
  "type": "record",
  "name": "OrderCreated",
  "namespace": "com.exemplo.pedidos",
  "fields": [
    {"name": "orderId", "type": "string"},
    {"name": "amount", "type": "double"},
    {"name": "userId", "type": ["null", "string"], "default": null}
  ]
}

1.3. Diferença entre schema registry e message broker

O message broker (Kafka, RabbitMQ, Pulsar) é responsável pelo transporte e armazenamento de mensagens. O Schema Registry é responsável pela governança de formato e evolução dos dados. Eles têm responsabilidades distintas:

  • Broker: roteamento, persistência, entrega
  • Registry: validação, versionamento, compatibilidade

Um broker pode operar sem schema registry, mas perde a capacidade de garantir contratos entre serviços.

2. Modelos de Compatibilidade e Estratégias de Evolução

2.1. Compatibilidade backward, forward e full

  • Backward: novos schemas podem ler dados escritos com schemas antigos. Permite adicionar campos com default.
  • Forward: schemas antigos podem ler dados escritos com schemas novos. Permite remover campos ou adicionar campos opcionais.
  • Full: combina backward e forward. Mais restritivo, mas seguro para evolução bidirecional.

Exemplo de configuração no Confluent Schema Registry:

# backward compatibility
compatibility.level=backward

# forward compatibility  
compatibility.level=forward

# full compatibility
compatibility.level=full

2.2. Regras de validação de schemas

  • Adição de campo opcional: permitido em backward (com default)
  • Remoção de campo: permitido em forward (se consumidor antigo ignora)
  • Renomeação de campo: geralmente proibido, pois quebra referência por nome
  • Mudança de tipo: proibido, exceto ampliações seguras (int para long)

2.3. Versionamento semântico vs. versionamento baseado em compatibilidade

  • Versionamento semântico: 1.0.0, 1.1.0, 2.0.0 — baseado em impacto da mudança
  • Versionamento por compatibilidade: versão 1, 2, 3 — cada nova versão deve passar nas regras de compatibilidade configuradas

O Schema Registry geralmente usa o segundo modelo, onde o registry atribui IDs numéricos automaticamente.

3. Arquitetura e Integração do Schema Registry com o Ecossistema

3.1. Fluxo de registro e validação

  1. Produtor define schema e envia para o registry
  2. Registry valida compatibilidade com versões anteriores
  3. Se compatível, registry armazena e retorna um ID único
  4. Produtor serializa o evento usando o schema referenciado pelo ID
  5. Consumidor obtém o schema pelo ID e desserializa

Exemplo de fluxo com serializador Kafka Avro:

// Produtor
ProducerRecord<String, Order> record = new ProducerRecord<>("orders", order);
producer.send(record);
// O serializador automaticamente registra o schema e inclui o ID

// Consumidor
ConsumerRecords<String, Order> records = consumer.poll(Duration.ofMillis(100));
// O desserializador obtém o schema pelo ID e converte

3.2. Mecanismos de cache e latência

Consumidores e produtores mantêm cache local de schemas para evitar chamadas frequentes ao registry. O cache reduz latência e evita sobrecarga:

  • Cache local com TTL configurável (ex: 5 minutos)
  • Fallback para registry se cache expirar
  • Estratégia de cache-first para leitura

3.3. Integração com serializadores

  • Avro: mais maduro, suporte nativo no Confluent Schema Registry, esquemas binários compactos
  • Protobuf: popular em ambientes gRPC, suporte via Apicurio Registry
  • JSON Schema: mais legível, mas maior overhead de serialização

Diferenças práticas:

Avro: schema evolution robusta, compressão nativa, tipos complexos
Protobuf: velocidade, integração com gRPC, definição de serviços
JSON Schema: simplicidade, compatibilidade com REST, maior payload

4. Governança e Ciclo de Vida dos Contratos

4.1. Políticas de retenção e expiração de versões antigas

  • Manter versões compatíveis por período mínimo (ex: 30 dias)
  • Remover versões que nenhum consumidor utiliza (com base em telemetria)
  • Backup de schemas antigos para auditoria

4.2. Controle de acesso e RBAC

  • Quem pode registrar novo schema (admin, líder técnico)
  • Quem pode modificar compatibilidade (apenas admin)
  • Quem pode excluir (quase ninguém, exceto em limpeza controlada)

Exemplo de política RBAC:

Role: schema-admin
  - registrar, modificar, excluir schemas
  - alterar nível de compatibilidade

Role: schema-developer
  - registrar novas versões compatíveis
  - consultar schemas existentes

Role: schema-reader
  - apenas consultar schemas

4.3. Estratégias de depreciação e migração de schemas obsoletos

  • Marcar schema como deprecated, mas manter ativo por X dias
  • Notificar consumidores sobre depreciação via header de evento
  • Remover apenas quando todos os consumidores migrarem

5. Tratamento de Falhas e Resiliência no Schema Registry

5.1. Lidando com schemas incompatíveis

  • Rejeição no produtor: registry retorna erro 409 Conflict, produtor não publica
  • Fallback no consumidor: consumidor tenta desserializar com schema antigo, ignora campos novos

5.2. Alta disponibilidade do schema registry

  • Múltiplas instâncias ativas com balanceamento de carga
  • Replicação entre data centers (Kafka MirrorMaker + schema sync)
  • Consistência eventual: registry pode ficar inconsistente por segundos, mas dados não são perdidos

5.3. Impacto de falhas no registry

  • Produtores com cache conseguem publicar por horas sem registry
  • Consumidores com cache conseguem consumir schemas conhecidos
  • Degradação graciosa: se registry cai, usar schema local em cache e registrar quando voltar

6. Casos de Uso e Padrões Avançados

6.1. Schema evolution em pipelines de dados com múltiplos consumidores heterogêneos

Um evento UserUpdated pode ser consumido por:
- Serviço de email (precisa de email, name)
- Serviço de analytics (precisa de userId, eventType)
- Data lake (precisa de todos os campos)

O schema registry garante que todas as versões sejam compatíveis com todos os consumidores.

6.2. Uso do schema registry para documentação viva e descoberta de domínio

O registry funciona como documentação viva da API de eventos. Times podem consultar schemas para entender:

  • Quais eventos existem
  • Quais campos cada evento contém
  • Qual versão está em produção

6.3. Integração com event versioning e idempotent consumers

  • Schema version + event version: schema evolui, evento pode ter versão semântica no payload
  • Idempotent consumers usam schema para validar estrutura antes de processar
  • Alinhamento de contratos evita duplicatas por mau entendimento de formato

7. Trade-offs e Considerações Finais

7.1. Overhead operacional vs. benefícios

  • Overhead: gerenciar registry, configurar compatibilidade, treinar times
  • Benefícios: zero quebras silenciosas por mudança de schema, rastreabilidade, documentação viva

7.2. Quando evitar schema registry

  • Sistemas com menos de 5 microsserviços
  • Prototipação rápida sem necessidade de evolução controlada
  • Eventos efêmeros com vida útil de minutos

7.3. Relação com outros temas da série

  • Outbox pattern: schema registry garante que eventos no outbox sigam contratos
  • Event storming: schemas documentam os eventos identificados
  • Consistência de contratos: schema registry é a ferramenta central para manter consistência entre serviços

Referências