Transações Distribuídas
Introdução
Uma transação distribuída, no contexto de microsserviços, é determinada quando uma transação de negócio envolver dois ou mais microsserviços que realizam transação local em nível de seu banco de dados. Por exemplo, é um caso de transação distribuída a transação de negócio “Confirmar Compra” que envolve uma transação local (alteração de dados) no microsserviço de “Pedidos” e outra no microsserviço de “Estoque”.
É importante garantir que transações distribuídas sejam executadas de forma consistente, mesmo que ocorram falhas em um ou mais dos microsserviços participantes do processo.
Aplicar técnicas no sentido de garantir a consistência de dados em transações distribuídas é realizar o gerenciamento de transação distribuída, ou DTM (Distributed Transaction Management).
O gerenciamento de transação distribuída pode ser implementado utilizando diferentes técnicas e protocolos, como 2PC (Two-Phase Commit), 3PC (Three-Phase Commit) e Saga.
Orienta-se no sentido da adoção do padrão Saga, a seguir descrito.
Padrão Saga
O padrão Saga estabelece que uma transação distribuída é uma sequência de transações locais. Cada transação local é uma etapa do fluxo Saga que ocorre no escopo de um determinado microsserviço. Se uma etapa falhar, o Saga executará transações locais compensatórias para reverter as etapas anteriores. As transações locais devem ser ACID (atômicas, consistentes, isoladas e duráveis).
Há duas abordagens para implementação de Saga:
-
Por coreografia, em que os microsserviços participantes trocam eventos sem um ponto centralizado de coordenação. Nesse caso, os microsserviços se comunicam, por exemplo, via webservices ou broker de mensageria.
-
Por orquestração, em que um controlador centralizado informa aos microsserviços participantes qual operação executar (transação local ou transação compensatória).
Considerações sobre o Saga:
-
O sistema deverá ser capaz de lidar com falhas transitórias, enquanto o Saga executa as operações compensatórias. Ou seja, o sistema deve ser capaz de saber que determinada informação presente no banco de dados pode não estar confirmada e ser desfeita posteriormente.
-
Com uso de orquestração, torna-se mais fácil implementar observabilidade e monitorar os processos Saga em andamento.
-
Algumas medidas são importantes para reduzir anomalias, como por exemplo marcar os registros envolvidos como “em processamento” até que o fluxo Saga seja concluído.
Orquestração
Orienta-se considerar a orquestração quando:
-
O fluxo envolver vários microsserviços.
-
A equipe de desenvolvimento tem expertise em algum motor de orquestração, a citar o software Camunda (se configurado para esta finalidade) ou o framework Apache Camel (que implementa Saga e outros padrões EIP - Enterprise Integration Patterns).
-
A equipe de operação, bem como a infraestrutura, tem capacidade para manter o serviço adicional de orquestração no ambiente computacional.
Observação: No caso orquestrado, o endpoint webservice que inicia a transação distribuída é por natureza assíncrono, o que traz maior complexidade para o lado cliente ou frontend. É possível criar uma camada adicional no backend para conversão de assíncrono para síncrono, porém isso não é trivial e pode implicar custos computacionais adicionais.
Coreografia
A coreografia é alternativa simplificada de implantação do Saga. Orienta-se considerá-la quando:
-
O fluxo envolver poucos microsserviços.
-
O endpoint webservice invocado pelo cliente ou frontend precisa ser síncrono.
-
Há restrição de equipe e/ou de infraestrutura para manutenção de software adicional para orquestração Saga, que requer, normalmente, utilização de cluster.
Observação: Se a coreografia for baseada em barramento de mensageria, o processo será tipicamente assíncrono.
Modelo Proposto
A seguir apresenta-se um esquema técnico para implementação de coreografia que envolve dois microsserviços, com as seguintes vantagens:
-
É síncrono.
-
Não requer softwares adicionais.
-
Não é intrusivo quanto ao segundo microsserviço, podendo ele ser, inclusive, um serviço externo (ex: um gateway de cartão de crédito contratado).
-
Suporta compensação imediata, que evitar lapsos maiores de tempo em que o processo ficaria na situação “em processamento”.
O objetivo desse esquema é servir de base para resolver os casos mais comuns de transação distribuída.
Definições gerais do modelo proposto:
-
O microsserviço “A” contém o webservice principal, utilizado pelo cliente ou frontend.
-
O microsserviço “A”, durante seu fluxo, consome um webservice do microsserviço “B”.
-
O microsserviço “A”, apenas, coordena o fluxo Saga.
-
Em caso de falha no microsserviço “B”, o microsserviço “A” tenta realizar uma compensação imediata (online), de maneira síncrona.
-
Caso a compensação online falhar, o microsserviço “A” retorna erro e uma rotina periódica (job), implementada em “A”, fará a compensação em um futuro breve.
-
Se a rotina de compensação periódica falhar após N tentativas, será necessária atuação manual para correção dos dados. Ressalta-se que fluxos orquestrados também incorrem neste risco.
Para implementação do fluxo proposto, quatro funcionalidades são necessárias:
-
Webservice no microsserviço “A”, utilizado pelo cliente ou frontend, responsável pela transação local em “A” e pela coreografia Saga. Exemplo: “confirmarCompra”. Deve ser tolerável a concorrência, de forma a não permitir fluxos paralelos da mesma transação negocial. Por exemplo: não permitir dois processos simultâneos de confirmação de uma mesma compra.
-
Webservice no microsserviço “B”, responsável pela transação local em “B”. Exemplo: “consumirEstoque”.
-
Webservice de compensação no microsserviço “B”, responsável pelo desfazimento da transação local de “B”. Exemplo: “estornarConsumoEstoque”. Deve ser idempotente e retornar sucesso caso não exista algo a compensar ou caso a compensação já tenha sido realizada.
-
Job no microsserviço “A”, responsável pelo fluxo compensatório em background. Exemplo: “desfazerConfirmacaoCompra”.
Abaixo é o diagrama de sequência da interação webservice entre os dois microsserviços, representando o fluxo principal do Saga. Note que o microsserviço “A” detém a lógica do padrão Saga, buscando fazer a compensação em caso de falha no microsserviço “B”.
A transação preliminar indicada no diagrama objetiva evitar concorrência do mesmo processo negocial. Ela pode ser implementada, por exemplo, via “lock de aplicação”, conforme explando em Bloqueios Exclusivos via SGBD.
Em dois momentos o diagrama de sequência ilustra que o processo fica órfão. Tratam-se de cenários de falha em que o microsserviço “A” termina sua execução deixando o processo negocial na situação “em andamento”. O primeiro caso ilustrado ocorre quando há um erro inesperado no microsserviço “B”, como por exemplo um timeout de rede, de forma que não se sabe se a transação local em “B” foi persistida ou não. O segundo caso ocorre quando a transação local em “A” falha e não foi possível confirmar a compensação em “B”.
Além dos dois casos supracitados, existem outros momentos do fluxo em que o processo negocial poderia ser deixado na situação “em andamento”, tais como:
-
Falhas no banco transacional de “A” em quaisquer das vezes em que o microsserviço tenta atualizar a situação do processo para finalizado (seja finalizado com erro ou finalizado com sucesso).
-
Deployment ou falhas no ambiente computacional, em que o microsserviço “A” é interrompido abruptamente.
Os processos negociais órfãos são tratados por uma rotina de compensação, conforme o diagrama de sequência abaixo:
O critério para determinação de processo órfão dependerá do negócio. Exemplo: “É órfão todo processo na situação ‘em andamento’ há mais de 5 min”.
O job pode sofrer interrupção ou falha em qualquer momento de sua lógica. Nestes casos, os processos negociais órfãos serão tratados nas próximas iterações. Assim, o sistema distribuído recuperar-se-á automaticamente tão logo possível.
Os dois diagramas de sequência apresentados acima compõem o modelo Saga simplificado proposto nesta seção do manual. Esse modelo visa reduzir substancialmente os problemas de inconsistência, bem como permitir que o sistema seja auto recuperável. Ocasionalmente haverá a necessidade de atuação humana, quando o job não conseguir resolver a compensação.
Próximos Passos
A próxima leitura sugerida é a seção Configuração, que mostra como configurar a arquitetura na aplicação.