Quando a conversa chega em JSON vs Avro, muita gente reduz a discussão a uma pergunta:

qual dos dois é mais rápido?

Essa pergunta importa, mas ela costuma esconder a parte mais relevante.

No Kafka, a diferença prática entre JSON e Avro não está apenas no tamanho da mensagem ou no custo de serialização. Está no jeito como o contrato de dados passa a ser tratado.

JSON tende a começar simples porque é legível, familiar e fácil de publicar. Avro tende a exigir mais disciplina porque depende de schema, tooling e compatibilidade.

Só que essa disciplina muda bastante a operação do sistema quando vários consumidores dependem do mesmo evento.

JSON funciona bem até o dia em que você precisa evoluir o contrato sem quebrar ninguém.

Nos posts anteriores, falamos sobre JSON flexível demais, schema como contrato, evolução de schema e tipos de compatibilidade. Agora a pergunta fica mais concreta:

o que muda quando o evento deixa de ser JSON puro e passa a usar Avro?


JSON é simples porque carrega a estrutura visível

Um evento em JSON é fácil de entender olhando para a mensagem.

Você abre o payload e vê os campos:

{
  "orderId": "123",
  "customerId": "456",
  "total": 199.90,
  "status": "PAID"
}

Isso é muito confortável no começo.

O produtor publica um texto estruturado. O consumidor desserializa esse texto para um objeto. Se chegar um campo novo, muitas bibliotecas conseguem ignorar. Se faltar um campo, talvez o objeto receba null. Se o tipo mudar, talvez quebre na leitura, talvez quebre depois, talvez nem quebre de forma explícita.

Essa é a força e a fraqueza do JSON.

Ele facilita começar, debugar e integrar rapidamente. Mas, sozinho, não obriga o sistema a respeitar um contrato formal.

É possível usar JSON com JSON Schema, validação e registry. O problema não é o formato em si.

O problema é o uso mais comum em muitos sistemas: JSON como combinado informal entre produtor e consumidores.

Enquanto o evento quase não muda, isso parece suficiente.

Quando o contrato precisa evoluir com consumidores em ritmos diferentes, a flexibilidade começa a cobrar seu preço.


Avro muda o jogo porque o schema vira parte do fluxo

Avro não é apenas outro jeito de escrever o mesmo payload.

Avro é um formato de serialização que trabalha com schema.

Em vez de a mensagem carregar nomes de campos e valores em texto, o payload normalmente circula em formato binário, e a interpretação depende do schema usado para escrever e ler aqueles dados.

Um schema Avro poderia representar o evento assim:

{
  "type": "record",
  "name": "OrderPaid",
  "fields": [
    { "name": "orderId", "type": "string" },
    { "name": "customerId", "type": "string" },
    { "name": "total", "type": "double" },
    { "name": "status", "type": "string" }
  ]
}

Na prática, isso muda a conversa.

O produtor não publica qualquer estrutura por acidente. Ele precisa escrever dados compatíveis com um schema.

O consumidor não precisa adivinhar o formato. Ele lê o evento a partir de uma definição conhecida.

E quando existe um Schema Registry no meio, o sistema consegue validar compatibilidade antes de uma nova versão do contrato começar a circular.

Essa é a grande diferença operacional.

Com JSON puro, o contrato costuma ser conferido tarde demais, quando o consumer recebe a mensagem.

Com Avro e registry, o contrato pode ser controlado antes do deploy ou no momento em que o schema é registrado.

Na prática, os benefícios aparecem em conjunto:

  • o payload fica menor porque a mensagem não precisa carregar toda a estrutura em texto
  • os campos passam a ter tipos definidos no schema
  • a validação deixa de depender apenas do comportamento do consumer
  • a evolução do contrato passa a seguir regras explícitas
  • produtores e consumidores conseguem conviver com versões diferentes quando a mudança é compatível

O que muda na mensagem

Com JSON, a mensagem é autodescritiva em certa medida.

Os nomes dos campos estão dentro do payload. Isso facilita inspeção manual, logs e troubleshooting rápido.

Com Avro, a mensagem é mais compacta, mas não é feita para ser lida diretamente por uma pessoa.

O payload binário precisa do schema correto para ser interpretado.

Em ambientes que usam Schema Registry, a mensagem normalmente carrega uma referência para o schema, como um identificador. O consumidor usa essa referência para buscar ou resolver a versão correta do contrato.

Isso traz uma troca clara:

  • JSON favorece leitura humana imediata
  • Avro favorece contrato formal e payload mais compacto
  • JSON é simples de inspecionar
  • Avro exige tooling para leitura e diagnóstico
  • JSON tolera informalidade com facilidade
  • Avro força disciplina mais cedo

Essa troca não é boa ou ruim por si só.

Ela precisa ser avaliada pelo tipo de sistema que você está construindo.


O que muda na evolução do contrato

Aqui está a diferença que mais pesa em produção.

Em JSON puro, nada impede alguém de remover um campo, mudar um tipo ou alterar o significado de um atributo.

O sistema só descobre o impacto quando algum consumidor tenta processar o evento.

E, como vimos nos posts anteriores, nem toda quebra aparece como exceção. Às vezes o consumidor continua de pé, mas passa a gravar informação incompleta ou interpretar o evento errado.

Com Avro, a evolução tende a ser mais controlada.

Adicionar um campo novo, por exemplo, exige pensar em compatibilidade. Se consumidores antigos ainda precisam ler eventos novos, esse campo provavelmente precisa ter um default ou ser modelado de forma compatível.

Remover campo, mudar tipo ou renomear atributo deixa de ser uma alteração "inocente" no payload.

Essas mudanças passam a ser avaliadas contra uma regra de compatibilidade.

É aqui que entram BACKWARD, FORWARD e FULL, que discutimos no post anterior.

Avro não elimina decisão arquitetural.

Ele apenas tira essa decisão do improviso.


O que muda no producer

Com JSON, o producer muitas vezes monta um objeto, serializa e publica.

Se o objeto mudou, o payload muda junto.

Isso é rápido, mas também perigoso quando o evento acaba refletindo uma classe interna do serviço.

Com Avro, o producer precisa respeitar o schema.

Dependendo da abordagem, o time pode trabalhar com classes geradas a partir do schema ou com estruturas genéricas. Em ambos os casos, existe uma camada mais explícita entre o modelo interno da aplicação e o contrato publicado.

Isso reduz a chance de o evento mudar apenas porque alguém refatorou uma classe local.

Também melhora a revisão técnica.

Uma alteração no evento deixa rastros mais claros: mudou o schema, mudou o contrato, precisa avaliar compatibilidade.

Essa fricção é saudável quando o evento já é consumido por outros serviços.


O que muda no consumer

No consumer, a diferença aparece em dois pontos: leitura e tolerância à evolução.

Com JSON, o consumer costuma depender da desserialização para uma classe local.

Se o payload vier com campos extras, talvez funcione. Se vier sem campos esperados, talvez gere null. Se vier com tipo diferente, talvez quebre. O comportamento depende bastante da biblioteca, da configuração e do cuidado do time.

Com Avro, a leitura considera a relação entre o schema usado para escrever o dado e o schema usado para ler o dado.

Esse ponto é importante.

Avro não exige que producer e consumer estejam sempre com a mesma versão exata do schema. O objetivo é permitir convivência entre versões, desde que a evolução seja compatível.

Na prática, isso ajuda a reduzir deploy coordenado.

O producer pode evoluir de forma planejada. Consumers podem acompanhar em ritmos diferentes. O registry pode bloquear mudanças incompatíveis antes que elas cheguem no tópico.

Isso não resolve todos os problemas, especialmente os problemas de semântica.

Mas reduz bastante a chance de uma mudança estrutural quebrar consumidores sem aviso.


O que muda no debug e na operação

JSON ganha muitos pontos em diagnóstico manual.

Se uma mensagem cai em uma DLQ, aparece em um log ou é copiada de uma ferramenta, alguém consegue ler o conteúdo rapidamente.

Com Avro, você precisa de ferramenta que saiba resolver o schema.

Isso pode parecer uma desvantagem forte, e em alguns cenários é mesmo.

Se o time não tem tooling, observabilidade e processo para lidar com Avro, o formato pode virar uma caixa preta operacional.

Por outro lado, Avro melhora outro tipo de operação: a governança do contrato.

Você perde a leitura manual imediata, mas ganha uma forma mais consistente de validar evolução, bloquear mudanças perigosas e entender versões do evento.

De novo, a troca é prática.

JSON facilita olhar a mensagem.

Avro facilita controlar a mudança.


Então quando usar JSON?

JSON continua fazendo sentido em muitos casos.

Ele pode ser uma boa escolha quando:

  • o volume é baixo ou moderado
  • os consumidores são poucos e bem conhecidos
  • a integração é simples
  • o time precisa de máxima facilidade de inspeção manual
  • existe validação de contrato mesmo usando JSON

O ponto é não confundir simplicidade com ausência de disciplina.

Se JSON for usado em eventos importantes, ele também precisa de contrato, versionamento e regra clara de evolução.

JSON puro e informal pode funcionar no começo.

Mas quanto mais consumidores dependem daquele tópico, mais caro fica descobrir incompatibilidade apenas em runtime.


Então quando usar Avro?

Avro tende a fazer mais sentido quando:

  • o evento é consumido por vários serviços
  • o payload precisa evoluir sem deploy coordenado
  • compatibilidade precisa ser validada de forma automática
  • volume e eficiência de serialização importam
  • o time aceita tratar schema como parte do ciclo de desenvolvimento

Avro costuma ser uma escolha forte quando Kafka deixa de ser apenas transporte e passa a ser uma base de integração entre sistemas.

Mas ele também cobra maturidade.

Não basta trocar o serializer.

É preciso cuidar de Schema Registry, compatibilidade, versionamento, observabilidade e processo de evolução.

Sem isso, o time pode ganhar complexidade sem ganhar segurança real.


O ponto que vale fixar

JSON vs Avro não é uma disputa entre "simples" e "sofisticado".

É uma diferença de responsabilidade.

JSON deixa muita responsabilidade para a disciplina do time e para o comportamento dos consumers.

Avro puxa parte dessa responsabilidade para o contrato, para o schema e para a validação de compatibilidade.

Na prática, a pergunta não deveria ser apenas qual formato é mais rápido.

A pergunta mais importante é:

quanto risco você aceita deixar implícito no contrato dos seus eventos?

Se o evento é simples, pouco compartilhado e bem controlado, JSON pode ser suficiente.

Se o evento sustenta integração entre vários serviços e precisa evoluir com segurança, Avro começa a fazer muito mais sentido.