Article image
Roni Carvalho
Roni Carvalho03/09/2026 23:19
Compartilhe

A Saga do Ingresso Perfeito: Parte 3 (O Desafio da Consistência)

    O Mistério da Transação Perdida

    Como garantir que o Lucas não fique sem o dinheiro E sem o ingresso no mundo distribuído.

    No episódio anterior, vimos que para salvar a bilheteria virtual do colapso, a equipe de engenharia quebrou o monolito em três microserviços independentes e especialistas: Ingressos (Tickets), Pagamentos e Notificações. Ao adotar a comunicação assíncrona, Lucas não precisa mais ficar travado esperando o processamento do banco; ele recebe um aviso de "Processando..." instantaneamente e pode continuar navegando.

    Mas agora, surge o maior pesadelo de qualquer pessoa que desenvolve sistemas distribuídos: como garantir a consistência dos dados quando tudo está separado?

    O Cenário de Horror: O que acontece quando o sistema falha?

    Imagine a seguinte sequência de eventos no celular do Lucas:

    1. Lucas clica em "Comprar".

    O Serviço de Ingressos reserva temporariamente o assento "A-12" no seu próprio banco de dados e envia uma mensagem assíncrona dizendo: ReservaCriada.

    1. O Serviço de Pagamentos recebe a mensagem e tenta cobrar o cartão do Lucas.
    2. Tragédia: O cartão do Lucas é recusado por falta de limite, ou a conexão com a operadora de cartão cai no meio do caminho.

    Se estivéssemos em um monolito antigo, resolver isso seria incrivelmente simples. O monolito usaria uma transação tradicional ACID (Atomicidade, Consistência, Isolamento e Durabilidade) no banco de dados centralizado. O código executaria algo como:

    BEGIN TRANSACTION;
    -- Reserva o ingresso
    -- Cobra o cartão
    COMMIT; -- Ou aborta tudo com ROLLBACK se a cobrança falhar!
    

    Com o ROLLBACK, se o pagamento falhasse, o banco desfazia a reserva do ingresso automaticamente. Tudo ou nada. É o poder da Atomicidade.

    Mas no mundo dos microserviços, nós seguimos a regra de ouro do Shared-Nothing (Banco de Dados Isolado): cada serviço possui o seu próprio banco de dados físico e independente. O banco de dados de Ingressos não sabe que o banco de dados de Pagamentos existe, e vice-versa.

    image

    Figura 4: Arquitetura de bancos de dados isolados por serviço (Shared-Nothing).


    Não existe um botão de ROLLBACK mágico que consiga cruzar a rede e desfazer uma linha escrita no banco de outro serviço. Se o pagamento do Lucas falhar, como avisamos o Serviço de Ingressos para liberar o assento "A-12" para outros fãs comprarem?

    Por que não usar Transações Distribuídas (2PC)?

    Alguns iniciantes sugerem usar um protocolo chamado Two-Phase Commit (2PC) ou transação distribuída, onde um coordenador central pergunta a todos os bancos se eles podem confirmar a escrita antes de finalizá-la.

    Embora funcione na teoria, na prática o 2PC é um enorme gargalo. Ele bloqueia as tabelas dos bancos de dados através da rede enquanto espera a resposta de todos. Se o Serviço de Pagamento demorar 5 segundos para responder, o Serviço de Ingressos ficará travado, incapaz de vender outros ingressos. Isso destrói a escalabilidade e a alta disponibilidade que tanto lutamos para construir.

    A Solução: Eventual Consistency e o modelo BASE

    Para escalar de verdade, os sistemas distribuídos modernos desistem da consistência imediata e abraçam a Consistência Eventual.

    Em vez de seguir o modelo rígido ACID, seguimos o modelo BASE:

    • Basically Available (Basicamente Disponível): O sistema prioriza estar sempre online para receber requisições, mesmo que algumas partes estejam temporariamente desatualizadas.
    • Soft-State (Estado Fluido): Os dados podem mudar ao longo do tempo sem a intervenção direta do usuário, à medida que as mensagens são entregues.
    • Eventual Consistency (Consistência Eventual): Se nenhuma nova atualização for feita, eventualmente todos os bancos de dados do sistema chegarão ao mesmo estado de acordo.

    Isso significa que, durante alguns segundos, o sistema do Lucas estará em um estado inconsistente: o ingresso dele está "Reservado", mas o pagamento ainda não foi confirmado. Para o negócio de shows, essa pequena janela de tempo em que as coisas estão desalinhadas é um preço aceitável a se pagar para que o site aguente milhões de acessos sem cair.

    Como resolver o erro? Rolando para Frente!

    Se não podemos dar um "desfazer" (rollback) físico no banco de dados, como corrigimos o problema do pagamento recusado do Lucas?

    Nós usamos uma estratégia chamada Roll-Forward (Rolar para Frente): em vez de tentar voltar no tempo, nós criamos uma nova transação que corrige o estado do sistema. Se o pagamento falhar, nós publicamos um novo evento de falha na rede. O Serviço de Ingressos escuta esse evento e, de forma proativa, executa uma ação para cancelar a reserva e liberar a cadeira.

    Essa dança coordenada de eventos e reações para garantir a consistência eventual tem um nome muito famoso na arquitetura de software: o Padrão SAGA.

    No próximo episódio, veremos como desenhar a coreografia perfeita dessa SAGA para garantir que o Lucas consiga seu ingresso de forma segura — ou seja avisado do erro sem bagunçar os bancos de dados do sistema.

    Compartilhe
    Comentários (0)