Na postagem anteriorNo artigo anterior, vimos alguns dos desafios da implementação de transações distribuídas e como implementar o padrão da Saga usando a abordagem Event/Choreography. Neste artigo, vamos falar sobre como resolver alguns de seus problemas, como transações complexas ou dependências cíclicas de eventos, usando outro tipo de implementação do Saga chamado Comando ou Orquestração.
Lógica de sequenciamento de comando/arquestração da Saga
Na abordagem de orquestração, definimos um novo serviço com a responsabilidade exclusiva de dizer a cada participante o que fazer e quando. O serviço padrão de saga O orquestrador se comunica com cada serviço em um estilo de comando/resposta, informando a eles qual operação deve ser executada.
Vamos ver como fica usando nosso exemplo anterior de comércio eletrônico:
- Serviço de pedidos salva uma ordem pendente e solicita ao Order Saga Orchestrator (OSO) que inicie uma ordem pendente. criar transação de pedido.
- OSO envia um Executar pagamento comando para Serviço de pagamentoe ele responde com um Pagamento executado mensagem
- OSO envia um Preparar pedido para o Stock Service e ele responde com um comando Pedido preparado mensagem
- OSO envia um Entregar pedido para o Delivery Service, e ele responde com um comando Pedido entregue mensagem
No caso acima, o Order Saga Orchestrator sabe qual é o fluxo necessário para executar uma transação de "criação de pedido". Se algo falhar, ele também é responsável por coordenar a reversão, enviando comandos a cada participante para desfazer a operação anterior.
Uma maneira padrão de modelar um orquestrador de saga é uma máquina de estado em que cada transformação corresponde a um comando ou mensagem. As máquinas de estado são um excelente padrão para estruturar um comportamento bem definido, pois são fáceis de implementar e particularmente ótimas para testes.
Retrocesso no Comando/Orquestração da Saga
As reversões são muito mais fáceis quando você tem um orquestrador para coordenar tudo:
- Serviço de estoque responde à OSO com um Fora de estoque mensagem;
- O OSO reconhece que a transação falhou e inicia a reversão
- Nesse caso, apenas uma única operação foi executada com êxito antes da falha, portanto OSO envia um Cliente de reembolso comando para Serviço de pagamento e definir o estado da ordem como falha
Vantagens e desvantagens do uso da Saga Projeto de comando/rquestração
As sagas baseadas em orquestração têm uma variedade de benefícios:
- Evite dependências cíclicas entre serviços, pois o O orquestrador da saga invoca os participantes da saga, mas os participantes não invocam o orquestrador
- Centralize a orquestração da transação distribuída
- Reduzir a complexidade dos participantes, pois eles só precisam executar/responder comandos.
- Mais fácil de ser implementado e testado
- A complexidade da transação permanece linear quando novas etapas são adicionadas
- As reversões são mais fáceis de gerenciar
- Se você tiver uma segunda transação disposta a alterar o mesmo objeto de destino, poderá facilmente colocá-la em espera no orquestrador até que a primeira transação termine.
No entanto, essa abordagem ainda tem algumas desvantagens, uma delas é o risco de concentrar muita lógica no orquestrador e acabar com uma arquitetura em que o orquestrador inteligente diz aos serviços burros o que fazer.
Outra desvantagem do Saga baseado em orquestração é que ele aumenta um pouco a complexidade da sua infraestrutura, pois você precisará gerenciar um serviço extra.
Dicas do padrão Saga
Criar um ID exclusivo por transação
Ter um identificador exclusivo para cada transação é uma técnica comum de rastreabilidade, mas também ajuda os participantes a ter uma maneira padrão de solicitar dados uns dos outros. Ao usar um ID de transação, por exemplo, o Serviço de Entrega pode perguntar ao Serviço de Estoque onde retirar os produtos e verificar com o Serviço de Pagamento se o pedido foi pago.
Adicionar o endereço de resposta no comando
Em vez de projetar seus participantes para responder a um endereço fixo, considere a possibilidade de enviar o endereço de resposta dentro da mensagem, dessa forma você permite que seus participantes respondam a vários orquestradores.
Operações idempotentes
Se você estiver usando filas para comunicação entre serviços (como SQS, Kafka, RabbitMQ etc.), recomendo pessoalmente que torne suas operações idempotentes. A maioria dessas filas pode entregar a mesma mensagem duas vezes.
Isso também pode aumentar a tolerância a falhas de seu serviço. Muitas vezes, um bug em um cliente pode acionar/reproduzir mensagens indesejadas e bagunçar o seu banco de dados.
Evitando comunicações síncronas
À medida que a transação avança, não se esqueça de adicionar à mensagem todos os dados necessários para que cada operação seja executada. O objetivo é evitar chamadas síncronas entre os serviços apenas para solicitar mais dados. Isso permitirá que seus serviços executem suas transações locais mesmo quando outros serviços estiverem off-line.
A desvantagem é que seu orquestrador será um pouco mais complexo, pois você precisará manipular as solicitações/respostas de cada etapa, portanto, esteja ciente das compensações.
Se você tiver alguma dúvida, sinta-se à vontade para me perguntar em @deniswsrosa
Muito bom!
Existe uma implementação?
Aqui está uma alternativa para uma máquina de estado como implementação: https://github.com/bertilmuth/requirementsascode. Ficarei feliz se você me disser o que pensa.
Olá, em sua visualização você usou o Message Broker e os canais. Portanto, parece que o Sage publica no canal do intermediário. E, por exemplo, o Payment Subscriber (Assinante de pagamento) usa esse canal e recebe a mensagem. Depois disso, ele deve enviar o resultado para outro canal do Saga. Portanto, é PUB/SUB MQ. Portanto, se o serviço de pagamento estiver off-line, o Saga deverá fornecer alguma lógica com tempo limite para resposta. Então, por que não usamos para esse caso o REQ/REP (modelo MQ de solicitação/resposta) ou a solicitação direta ao serviço de pagamento? Assim, saberemos imediatamente a resposta e a disponibilidade do serviço?