Marcio Cunha

Sistemas acoplados? Como migrar para eventos com Kafka

Descubra como desacoplar microsserviços legados usando mensageria assíncrona com Apache Kafka, eliminando dependências diretas e gargalos operacionais.

Marcio Cunha•4 min
Também disponível em:EnglishEspañol
Resumo
  • Sistemas fortemente acoplados travam entregas quando um único serviço fora do ar paralisa todo o fluxo de requisições.
  • O Apache Kafka funciona como uma central de recados digital de alta performance que guarda mensagens em ordem cronológica.
  • O padrão Transactional Outbox resolve o desafio de salvar dados no banco local e avisar o Kafka sem perder atualizações.
  • Consumidores independentes processam dados no próprio ritmo, absorvendo picos de tráfego sem derrubar os sistemas antigos.
  • Monitorar o atraso das filas com métricas de lag garante a saúde da arquitetura orientada a eventos em produção.

O problema invisível dos sistemas fortemente acoplados

Quando construímos aplicações crescendo de forma orgânica, é comum criarmos dependências diretas entre os blocos de código. Na prática, isso significa que o sistema de pagamentos precisa chamar diretamente a API de envios e a de faturamento de forma síncrona. Se uma dessas pontas travar por instabilidade de rede ou lentidão no banco, a requisição inteira falha e o cliente percebe a lentidão na tela.

Esse modelo em que um programa grita por socorro esperando a resposta imediata do outro é conhecido como acoplamento estrito. À medida que a empresa cresce, qualquer alteração minúscula em um contrato de API pode derrubar serviços inteiros. Para mitigar falhas em cascata semelhantes às que tratamos quando analisamos gargalos em transações lentas e locks mortos no banco, precisamos repensar como os dados trafegam entre as aplicações.

O que é o Apache Kafka e como ele muda o jogo

Para curar essa dependência crônica, a engenharia moderna recorre à mensageria assíncrona usando o Apache Kafka. Na prática, o Kafka funciona como um mural de recados digital extremamente organizado, veloz e persistente. Em vez de um microsserviço conversar diretamente com outro, ele simplesmente publica um aviso dizendo que algo aconteceu, como 'um pedido foi pago', e vai cuidar de outra tarefa.

Do outro lado, os serviços interessados nessa informação leem o mural no seu próprio ritmo, sem pressa e sem sobrecarregar a origem. Essa troca de figurinhas baseada em eventos transforma fluxos rígidos em redes flexíveis. Se a integração de comunicação que você usa hoje sofre com atrasos estruturais, vale a pena conhecer estratégias complementares, como a otimização de chamadas síncronas usando gRPC para fluxos que ainda exigem resposta imediata.

Planejando a retirada gradual dos serviços legados

Migrar um monstro legado para uma arquitetura de eventos não acontece da noite para o dia. Tentar reescrever tudo de uma vez é a receita perfeita para o fracasso e para prejuízos financeiros colossais. O segredo reside na abordagem cirúrgica: identificar uma funcionalidade isolada, como a emissão de notas fiscais, e transformá-la em um consumidor de eventos do Kafka, mantendo o restante do sistema funcionando inalterado.

Nessa jornada de transição, a maior armadilha é a perda de mensagens entre a alteração do banco de dados local e o envio do aviso para o Kafka. Se o servidor cair logo após salvar a compra, mas antes de avisar o mensageiro, o evento some para sempre. É exatamente aqui que entra um dos conceitos arquiteturais mais importantes para garantir consistência operacional sem dor de cabeça.

Como usar o padrão Outbox para evitar perdas de dados

Para garantir que nenhum evento seja perdido no meio do caminho, utilizamos uma estratégia chamada Transactional Outbox. Na prática, criamos uma tabela dentro do próprio banco de dados relacional legado chamada outbox, onde guardamos o evento no exato milissegundo em que salvamos a alteração principal da regra de negócio.

Um processo auxiliar separado lê essa tabela de recados pendentes, empurra os dados para o Kafka com segurança e marca o registro como processado. Dessa forma, garantimos que banco de dados e mensageria caminhem sempre em perfeita harmonia. Caso o sistema precise de validações estritas de payload antes de injetar esses eventos nos tópicos, a adoção de salvaguardas semelhantes às que usamos para criar guardrails de validação estrita em dados complexos previne corrupções catastróficas.

Escrevendo o primeiro produtor e consumidor em código

Para ilustrar a simplicidade da integração, vamos ver um exemplo prático utilizando Python e a biblioteca kafka-python. No código abaixo, simulamos um serviço legado que publica um evento de alteração de cadastro de usuário sempre que uma transação é concluída no sistema antigo.

from kafka import KafkaProducerimport jsonproducer = KafkaProducer(    bootstrap_servers=['localhost:9092'],    value_serializer=lambda v: json.dumps(v).encode('utf-8'))evento = {    "evento_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",    "tipo": "USUARIO_ATUALIZADO",    "email": "[email protected]"}producer.send('usuarios-topico', value=evento)producer.flush()print("Evento publicado com sucesso no Kafka!")

No lado receptor, o microsserviço independente escuta esse mesmo tópico de forma contínua, processando o e-mail do usuário sem travar nenhuma outra thread da aplicação principal.

from kafka import KafkaConsumerimport jsonconsumer = KafkaConsumer(    'usuarios-topico',    bootstrap_servers=['localhost:9092'],    auto_offset_reset='earliest',    enable_auto_commit=True,    group_id='grupo-processa-email',    value_deserializer=lambda x: json.loads(x.decode('utf-8')))for mensagem in consumer:    dados = mensagem.value    print(f"Processando usuario: {dados['email']}")

Monitorando a saúde e medindo o atraso das filas

Colocar o Kafka para rodar em produção exige atenção constante a um indicador crítico conhecido como consumer lag. Na prática, o lag mede a diferença entre o evento mais recente que entrou no tópico e o último evento que o seu microsserviço conseguiu processar. Se o número de mensagens acumuladas começar a subir sem parar, significa que seus consumidores estão lentos ou que o volume superou a capacidade atual de processamento.

Ferramentas de observabilidade como Prometheus e Grafana devem ser configuradas para disparar alertas sempre que o atraso ultrapassar limites seguros. Além disso, dimensionar corretamente o número de partições dentro de cada tópico permite que múltiplos servidores leiam os dados em paralelo, multiplicando a vazão do sistema sem exigir mudanças complexas de código.

Considerações finais sobre a jornada orientada a eventos

Migrar sistemas acoplados para uma arquitetura baseada em eventos com Kafka exige planejamento estratégico, paciência operacional e rigor na consistência dos dados. Quando bem executada, essa transição elimina pontos únicos de falha, devolve a agilidade aos times de desenvolvimento e prepara a empresa para absorver picos massivos de acesso sem derrubar o legado. O segredo está em avançar por etapas, garantindo segurança na entrega e monitoramento constante em cada virada de chave.