Two-phase commit (2PC) é um protocolo que garante atomicidade em transações distribuídas, ou seja, que uma operação que envolve vários bancos ou serviços seja confirmada (commit) ou desfeita (rollback) por completo, sem estados intermediários. Na prática, ele coordena os nós participantes em duas fases: prepare e commit. Mas atenção: ele não é a solução universal para consistência distribuída. Em cenários de alta disponibilidade ou com participantes lentos, o 2PC pode trazer mais dor de cabeça do que benefício.
Como funciona o two-phase commit?
O protocolo two-phase commit tem um coordenador (geralmente o nó que inicia a transação) e vários participantes (os bancos ou serviços envolvidos). O processo é dividido em duas fases:
- Fase prepare: o coordenador envia uma mensagem de prepare para todos os participantes, perguntando se cada um consegue confirmar sua parte da transação. Cada participante executa as operações locais, bloqueia os recursos e responde com um voto: "sim, estou pronto" ou "não, não posso". Nenhum participante confirma definitivamente ainda.
- Fase commit ou rollback: se todos responderem "sim", o coordenador envia a ordem de commit para todos, e cada um aplica as mudanças de forma definitiva. Se algum responder "não" ou se o coordenador não receber resposta, ele envia a ordem de rollback, e todos desfazem as operações locais.
O ponto-chave é que, após a fase prepare, nenhum participante pode mudar seu voto. Isso garante que, se o coordenador decidir pelo commit, todos os nós estarão prontos para aplicar a mudança.
Quando o two-phase commit é útil?
O 2PC brilha em cenários onde a consistência imediata é crítica e o número de participantes é pequeno e confiável. Um exemplo clássico é uma transferência bancária entre duas contas em bancos diferentes. Se o débito em um banco for confirmado e o crédito no outro falhar, o dinheiro some. Com o 2PC, as duas operações são preparadas juntas e confirmadas ou desfeitas juntas, como descreve a documentação da IBM sobre transações federadas.
Outro caso comum é quando você precisa atualizar dois bancos de dados relacionais que não compartilham o mesmo servidor, mas a aplicação exige que ambos reflitam a mesma mudança ao mesmo tempo. O protocolo também aparece em sistemas de mensageria que precisam publicar uma mensagem e atualizar um banco de forma atômica.
Por que o two-phase commit não é recomendado em sistemas distribuídos de larga escala?
O 2PC tem um calcanhar de Aquiles: o bloqueio dos recursos durante a fase prepare. Se um participante ficar lento ou indisponível, todos os outros ficam segurando recursos (linhas, tabelas, locks) sem saber se vão precisar desfazer ou confirmar. Isso pode travar o sistema inteiro.
Além disso, o protocolo depende de um coordenador. Se ele falhar após a fase prepare, os participantes podem ficar em um estado incerto, aguardando uma decisão que nunca chega. Sistemas modernos preferem abordagens como o saga pattern, que permite transações distribuídas sem locks globais, ou o protocolo Paxos/Raft para replicação, que foca em disponibilidade mesmo com falhas.
Outro problema é a latência. Cada fase exige comunicação com todos os nós, então o tempo de resposta cresce com o número de participantes. Em sistemas com dezenas de microsserviços, o 2PC se torna impraticável.
Quando evitar o two-phase commit?
Evite o 2PC quando:
- Você tem muitos participantes: quanto mais nós, maior a chance de um deles falhar ou atrasar, e maior o tempo de bloqueio.
- Seus serviços são geograficamente distribuídos: a latência de rede entre data centers torna as duas fases muito lentas.
- Você precisa de alta disponibilidade: se o coordenador cair, todo o sistema de transações para.
- As operações são de longa duração: o bloqueio prolongado de recursos pode causar deadlocks e degradação de performance.
- Você aceita consistência eventual: muitos sistemas modernos (como e-commerce de alta escala) preferem o saga pattern, onde cada etapa tem uma compensação.
Nesses casos, alternativas como o saga pattern, a replicação assíncrona ou a consistência eventual costumam ser mais adequadas, mesmo que exijam lógica de compensação no código.
Resumo
Two-phase commit é uma solução clássica para garantir atomicidade em transações distribuídas, útil em cenários com poucos participantes e necessidade de consistência imediata. Mas ele não escala bem e pode virar um gargalo em sistemas modernos. Antes de adotar o 2PC, avalie o número de nós, a tolerância a falhas e a aceitação de consistência eventual. Se a resposta for "não" para o 2PC, estude o saga pattern.
Perguntas frequentes
O que é a fase prepare no two-phase commit?
Na fase prepare, o coordenador solicita que cada participante execute as operações locais e bloqueie os recursos necessários, sem confirmar a transação. Cada nó responde com um voto "sim" ou "não". Se todos votarem "sim", a transação pode ser confirmada. Se algum votar "não", a transação será desfeita.
O que acontece se o coordenador falhar durante o two-phase commit?
Se o coordenador falhar após a fase prepare, os participantes ficam em um estado incerto, aguardando uma decisão. Eles não podem desfazer nem confirmar sozinhos, pois não sabem se os outros nós votaram "sim". Isso pode exigir um protocolo de recuperação ou intervenção manual.
Qual a diferença entre two-phase commit e saga pattern?
O two-phase commit exige que todos os participantes confirmem juntos, mantendo locks até a decisão final. O saga pattern divide a transação em etapas locais com compensações: se uma etapa falha, as anteriores são desfeitas com ações de rollback. Sagas não bloqueiam recursos globalmente e são mais adequadas para microsserviços.
two-phase commit funciona com microsserviços?
Funciona em teoria, mas é raramente recomendado. Microsserviços costumam ter muitos nós, latência variável e necessidade de alta disponibilidade. O 2PC tende a criar gargalos e aumentar o acoplamento. Para transações entre microsserviços, o saga pattern é a abordagem mais comum.
O que é uma transação distribuída?
Uma transação distribuída é uma operação que envolve mais de um recurso ou banco de dados, possivelmente em servidores diferentes. O objetivo é manter a consistência entre todos os recursos, como se fossem uma única operação atômica. O two-phase commit é um dos protocolos usados para gerenciar essas transações.
Quais as desvantagens do two-phase commit?
As principais desvantagens são o bloqueio prolongado de recursos, a dependência de um coordenador central e a latência elevada em sistemas distribuídos. Além disso, ele não lida bem com falhas parciais do coordenador, podendo deixar o sistema em estado incerto.