O padrão de design Saga ajuda a manter a consistência dos dados em sistemas distribuídos, coordenando transações em vários serviços. Uma saga é uma sequência de transações locais onde cada serviço executa sua operação e inicia a próxima etapa através de eventos ou mensagens. Se uma etapa da sequência falhar, a saga executa transações de compensação para desfazer as etapas concluídas, mantendo a consistência dos dados.
Contexto e problema
Uma transação representa uma unidade de trabalho, que pode incluir várias operações. Dentro de uma transação, um evento refere-se a uma alteração de estado que afeta uma entidade. Um comando encapsula todas as informações necessárias para executar uma ação ou acionar um evento subsequente.
As transações devem aderir aos princípios de atomicidade, consistência, isolamento e durabilidade (ACID).
- Atomicidade: Todas as operações são bem-sucedidas ou nenhuma é bem-sucedida.
- Consistência: Transições de dados de um estado válido para outro.
- Isolamento: As transações simultâneas produzem os mesmos resultados que as sequenciais.
- Durabilidade: Uma vez comprometidas, as mudanças persistem mesmo em falhas.
Em um único serviço, as transações seguem os princípios ACID porque operam dentro de um único banco de dados. No entanto, alcançar a conformidade ACID em vários serviços é mais complexo.
Desafios em arquiteturas de microsserviços
As arquiteturas de microsserviços normalmente atribuem um banco de dados dedicado a cadade microsserviços, o que oferece vários benefícios:
- Cada serviço encapsula seus próprios dados.
- Cada serviço pode usar a tecnologia de banco de dados mais adequada e esquema para suas necessidades específicas.
- Dimensionamento independente de bancos de dados para cada serviço.
- As falhas em um serviço são isoladas dos outros.
Apesar dessas vantagens, essa arquitetura complica a consistência de dados entre serviços. Garantias de banco de dados tradicionais, como o ACID, não são diretamente aplicáveis a vários armazenamentos de dados gerenciados independentemente. Devido a essas limitações, arquiteturas que dependem de comunicação entre processos (IPC) ou modelos de transação tradicionais, como o protocolo de confirmação bifásica (2PC), geralmente são mais adequadas para o padrão Saga.
Solução
O padrão Saga gerencia as transações dividindo-as em uma sequência de transações locais (ver figura 1).
Figura 1. Uma saga com três serviços.
Cada transação local:
- Conclui seu trabalho atomicamente dentro de um único serviço.
- Atualiza o banco de dados do serviço.
- Inicia a próxima transação através de um evento ou mensagem.
- Se uma transação local falhar, a saga executa uma série de transações de compensação para reverter as alterações feitas pelas transações locais anteriores.
Conceitos-chave no padrão Saga
Operações compensáveis: Transações que outras transações podem desfazer ou compensar com o efeito contrário. Se uma etapa da saga falhar, as transações compensatórias desfazem as alterações que as transações compensáveis fizeram.
Transação Pivot: A transação Pivot serve como o "ponto de não retorno" na saga. Uma vez que a transação pivot seja bem-sucedida, as transações compensáveis (que podem ser desfeitas) não são mais relevantes. Todas as ações subsequentes devem ser concluídas para que o sistema atinja um estado final consistente. Uma transação de pivô pode se enquadrar em diferentes funções, dependendo do fluxo da saga:
irreversível (não compensável): Não pode ser desfeito ou repetido.
Limite entrereversível e comprometido: Pode ser a última transação inviável (compensável), ou pode ser a primeira operação reprovável na saga.
Transações retryable: Essas transações seguem a transação pivot. As transações retryable são idempotentes e garantem que a saga possa atingir seu estado final, mesmo que ocorram falhas temporárias. Isso garante que a saga atinja um estado consistente eventualmente.
Abordagens de implementação da Saga
Existem duas abordagens comuns de implementação da saga, coreografia e orquestração . Cada abordagem tem seu próprio conjunto de desafios e tecnologias para coordenar o fluxo de trabalho.
Coreografia
Na coreografia, os serviços trocam eventos sem um controlador centralizado. Com coreografia, cada transação local publica eventos de domínio que acionam transações locais em outros serviços (ver figura 2).
Figura 2. Uma saga que usa coreografia.
Benefícios da coreografia | Desvantagens da coreografia |
---|---|
Bom para fluxos de trabalho simples com poucos serviços e não precisam de uma lógica de coordenação. | O fluxo de trabalho pode se tornar confuso ao adicionar novas etapas. É difícil rastrear quais participantes da saga ouvem quais comandos. |
Nenhum outro serviço é necessário para a coordenação. | Há um risco de dependência cíclica entre os participantes da saga porque eles têm que consumir os comandos uns dos outros. |
Não introduz um único ponto de falha, uma vez que as responsabilidades estão distribuídas pelos participantes da saga. | O teste de integração é difícil porque todos os serviços devem estar em execução para simular uma transação. |
Orquestração
Na orquestração, um controlador centralizado (orquestrador) lida com todas as transações e diz aos participantes qual operação executar com base nos eventos. O orquestrador executa solicitações de saga, armazena e interpreta os estados de cada tarefa e lida com a recuperação de falhas com transações de compensação (ver figura 3).
Figura 3. Uma saga que usa orquestração.
Benefícios da orquestração | Desvantagens da orquestração |
---|---|
Mais adequado para fluxos de trabalho complexos ou ao adicionar novos serviços. | Outra complexidade de projeto requer a implementação de uma lógica de coordenação. |
Evita dependências cíclicas, uma vez que o orquestrador gere o fluxo. | Introduz um ponto de falha porque o orquestrador gerencia o fluxo de trabalho completo. |
Uma separação clara das responsabilidades simplifica a lógica do serviço. |
Questões e considerações
Considere os seguintes pontos ao implementar o padrão Saga:
Mudança no design thinking: Adotar o padrão Saga requer uma mentalidade diferente, concentrando-se na coordenação de transações e garantindo a consistência dos dados em vários microsserviços.
Complexidade das sagas de depuração: As sagas de depuração podem ser complexas, especialmente à medida que o número de serviços participantes aumenta.
Alterações irreversíveis no banco de dados local: Os dados não podem ser revertidos porque os participantes da saga confirmam alterações em seus respetivos bancos de dados.
Tratamento de falhas transitórias ede idempotência: O sistema deve lidar com falhas transitórias de forma eficaz e garantir a idempotência, onde repetir a mesma operação não altera o resultado. Para obter mais informações, consulte Idempotent message processing.
Necessidade de monitoramento e rastreamento de sagas: Monitorar e acompanhar o fluxo de trabalho de uma saga são essenciais para manter a supervisão operacional.
Limitações das operações de compensação: As operações de compensação podem nem sempre ter êxito, deixando potencialmente o sistema num estado incoerente.
Potenciais anomalias de dados em sagas
As anomalias de dados são inconsistências que podem ocorrer quando sagas são executadas em vários serviços. Como cada serviço gerencia seus próprios dados (dados dos participantes), não há isolamento interno entre os serviços. Essa configuração pode resultar em inconsistências de dados ou problemas de durabilidade, como atualizações parcialmente aplicadas ou conflitos entre serviços. Os problemas comuns incluem:
Atualizações perdidas: Quando uma saga modifica dados sem considerar alterações feitas por outra saga, isso leva a atualizações substituídas ou ausentes.
Dirty lê: Quando uma saga ou transação lê dados que outra saga modificou, mas ainda não foi concluída.
Fuzzy (não repetível) lê: Quando diferentes etapas de uma saga leem dados inconsistentes porque ocorrem atualizações entre as leituras.
Estratégias para resolver anomalias de dados
Para reduzir ou prevenir estas anomalias, considere estas contramedidas:
Bloqueio semântico: Use bloqueios no nível do aplicativo onde a transação compensável de uma saga usa um semáforo para indicar que uma atualização está em andamento.
Atualizações comutativas: Projete atualizações para que possam ser aplicadas em qualquer ordem, produzindo o mesmo resultado, reduzindo conflitos entre sagas.
Visão pessimista: Reordene a sequência da saga para que as atualizações de dados ocorram em transações repetidas para eliminar leituras sujas. Caso contrário, uma saga pode ler dados sujos (alterações não confirmadas) enquanto outra saga está executando simultaneamente uma transação compensável para reverter suas atualizações.
Relendo valores: Valide se os dados permanecem inalterados antes de fazer atualizações. Se os dados forem alterados, anule a etapa atual e reinicie a saga conforme necessário.
Arquivos de versão: Mantenha um registro de todas as operações em um registro e certifique-se de que elas sejam executadas na sequência correta para evitar conflitos.
Simultaneidade baseada no risco (por valor): Escolha dinamicamente o mecanismo de simultaneidade apropriado com base no risco potencial do negócio. Por exemplo, use sagas para atualizações de baixo risco e transações distribuídas para atualizações de alto risco.
Quando usar este padrão
Use o padrão Saga quando precisar:
- Garanta a consistência dos dados em um sistema distribuído sem acoplamento rígido.
- Reverter ou compensar se uma das operações na sequência falhar.
O padrão Saga é menos adequado para:
- Transações fortemente acopladas.
- Operações de compensação que ocorrem em participantes anteriores.
- Dependências cíclicas.
Próximos passos
- Dados distribuídos
- Richardson, Chris. 2018: Padrões de Microsserviços. Manning Publicações.
Recursos relacionados
Os seguintes padrões também podem ser úteis ao implementar esse padrão:
- coreográfica faz com que cada componente do sistema participe do processo de tomada de decisão sobre o fluxo de trabalho de uma transação comercial, em vez de depender de um ponto central de controle.
- Operações de compensação desfazer o trabalho realizado por uma série de etapas e, eventualmente, definir uma operação consistente se uma ou mais etapas falharem. Os aplicativos hospedados na nuvem que implementam processos de negócios e fluxos de trabalho complexos geralmente seguem esse modelo eventual consistência.
- de repetição permite que um aplicativo lide com falhas transitórias quando tenta se conectar a um serviço ou recurso de rede, repetindo de forma transparente a operação com falha. Repetir pode melhorar a estabilidade do aplicativo.
- Disjuntor lida com falhas que levam um tempo variável para serem recuperadas, ao se conectar a um serviço ou recurso remoto. O disjuntor pode melhorar a estabilidade e a resiliência de uma aplicação.
- de monitoramento de pontos finais de integridade implementa verificações funcionais em um aplicativo que ferramentas externas podem acessar por meio de pontos de extremidade expostos em intervalos regulares. O monitoramento de pontos finais de integridade pode ajudar a verificar se os aplicativos e serviços estão funcionando corretamente.