Marcio Cunha

Implementação de Outbox Transacional com Debezium e Kafka em Microsserviços

Descubra como garantir a consistência de dados entre microsserviços usando o padrão Outbox Transacional, capturando alterações de banco de dados com Debezium e publicando eventos no Apache Kafka de forma confiável.

Marcio Cunha•4 min
Também disponível em:EspañolEnglish
Resumo
  • O padrão Outbox Transacional resolve o problema clássico da dupla escrita entre bancos de dados relacionais e sistemas de mensageria.
  • O Debezium lê diretamente o log de transações do banco de dados, eliminando a necessidade de consultas periódicas ou chamadas manuais.
  • O Apache Kafka atua como o sistema central de mensageria distribuída, garantindo a entrega ordenada de eventos para outros microsserviços.
  • Falhas de rede ou quedas de infraestrutura não causam perda de dados devido à persistência prévia dos eventos na tabela de outbox.
  • A abordagem baseada em Change Data Capture reduz o acoplamento entre a lógica de negócio e a infraestrutura de publicação de eventos.

O Desafio da Consistência de Dados em Microsserviços

Quando dividimos um sistema monolítico grande em vários microsserviços menores, cada pedaço do sistema passa a ter o seu próprio banco de dados isolado. Na prática, isso significa que uma única operação de negócio, como cadastrar um novo cliente e emitir a fatura correspondente, agora precisa atualizar dois ou mais bancos de dados diferentes que não conversam diretamente entre si.

O problema central surge quando ocorre uma falha na metade do caminho. Se o serviço de cadastro consegue salvar o cliente no banco, mas a rede cai antes de avisar o serviço de faturamento, os sistemas ficam dessincronizados. Em engenharia de software, chamamos esse dilema de o problema da dupla escrita, onde tentar salvar dados em dois lugares distintos ao mesmo tempo quase sempre resulta em inconsistências graves.

Entendendo o Padrão Outbox Transacional

Para resolver esse impasse sem perder a performance, a arquitetura moderna recorre ao padrão Outbox Transacional, uma técnica que funciona de forma muito parecida com uma caixa de saída de e-mails tradicional. Na prática, quando um microsserviço precisa alterar dados e avisar o restante do sistema, ele grava todas essas informações dentro da mesma transação do banco de dados principal.

Isso significa que a alteração do registro de negócio e o registro do evento que será publicado acontecem no mesmo bloco atômico. Ou os dois são salvos com sucesso, ou nada é alterado. A grande vantagem é que garantimos que nenhum evento de comunicação se perca, mesmo que a aplicação sofra uma pane logo em seguida, pois a intenção de comunicar já está gravada de forma segura no disco do banco de dados.

O Papel do Debezium e o Change Data Capture

Salvar os eventos na tabela de outbox é apenas a primeira etapa, pois ainda precisamos enviá-los para o resto da arquitetura. É aqui que entra o Change Data Capture, uma tecnologia que monitora e extrai em tempo real todas as alterações feitas nas tabelas de um banco de dados relacional sem sobrecarregar a aplicação principal.

O Debezium é a ferramenta de código aberto mais popular para essa tarefa, agindo como um observador silencioso que escuta diretamente o log de transações do banco de dados. Na prática, cada vez que uma linha é inserida na tabela de outbox, o Debezium lê essa alteração instantaneamente e a transforma em um evento estruturado, pronto para ser encaminhado para a infraestrutura de mensageria.

Integrando com o Apache Kafka para Entrega Confiável

Depois que o Debezium captura a alteração no banco de dados, o próximo passo é publicá-la em um barramento de mensagens centralizado. O Apache Kafka desempenha esse papel com maestria, funcionando como uma fila de alta capacidade que organiza, armazena e distribui os eventos para todos os microsserviços interessados.

Na prática, o Kafka garante que os dados cheguem aos consumidores na mesma ordem em que foram gerados, além de permitir que microsserviços fiquem temporariamente fora do ar sem perder as mensagens acumuladas. Quando o serviço consumidor volta a funcionar, ele simplesmente retoma a leitura de onde parou, garantindo a resiliência de todo o ecossistema distribuído.

Implementação Prática com Código e Configuração

Para colocar essa arquitetura em funcionamento, precisamos estruturar a tabela de outbox no banco de dados relacional e configurar o conector do Debezium. A tabela armazena o identificador único do evento, o tipo de evento correspondente e o payload contendo os dados em formato JSON que serão transmitidos para o barramento de mensagens.

CREATE TABLE outbox_events (
id UUID PRIMARY KEY,
aggregate_type VARCHAR(255) NOT NULL,
aggregate_id VARCHAR(255) NOT NULL,
event_type VARCHAR(255) NOT NULL,
payload JSONB NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

Em seguida, configuramos o conector do Debezium para monitorar essa tabela específica. O arquivo de configuração define qual banco de dados será vigiado, quais credenciais de acesso utilizar e para qual tópico do Kafka os dados coletados devem ser encaminhados automaticamente.

{
"name": "outbox-connector",
"config": {
"connector.class": "io.debezium.connector.postgresql.PostgresConnector",
"database.hostname": "postgres",
"database.port": "5432",
"database.user": "db_user",
"database.password": "db_password",
"database.dbname": "shop_db",
"table.include.list": "public.outbox_events",
"tombstones.on.delete": "false"
}
}

Considerações Finais sobre Confiabilidade e Arquitetura

A adoção do padrão Outbox Transacional combinado com Debezium e Apache Kafka elimina os gargalos de consistência comuns em sistemas distribuídos modernos. Ao delegar a leitura de logs para uma ferramenta especializada, removemos a complexidade de mensageria da regra de negócio da aplicação, mantendo o código mais limpo e fácil de manter.

Embora essa abordagem exija uma infraestrutura mais robusta e um esforço inicial de configuração maior, os benefícios superam em muito os custos. Sistemas que operam com alta volumetria de transações passam a contar com uma garantia matemática de que nenhum dado será perdido, assegurando a integridade operacional e a tranquilidade das equipes de engenharia.