Descentralize a lógica do fluxo de trabalho e distribua as responsabilidades para outros componentes dentro de um sistema.
Contexto e problema
Um aplicativo baseado em nuvem geralmente é dividido em vários pequenos serviços que trabalham juntos para processar uma transação comercial de ponta a ponta. Mesmo uma única operação (dentro de uma transação) pode resultar em várias chamadas ponto-a-ponto entre todos os serviços. Idealmente, esses serviços devem ser acoplados de forma flexível. É desafiador projetar um fluxo de trabalho distribuído, eficiente e escalável porque geralmente envolve comunicação interserviços complexa.
Um padrão comum de comunicação é usar um serviço centralizado ou um orquestrador. As solicitações recebidas fluem através do orquestrador à medida que ele delega operações aos respetivos serviços. Cada serviço apenas completa sua responsabilidade e não está ciente do fluxo de trabalho geral.
O padrão orchestrator é normalmente implementado como software personalizado e tem conhecimento de domínio sobre as responsabilidades desses serviços. Uma vantagem é que o orquestrador pode consolidar o status de uma transação com base nos resultados de operações individuais conduzidas pelos serviços a jusante.
No entanto, existem alguns inconvenientes. Adicionar ou remover serviços pode quebrar a lógica existente porque você precisa reconectar partes do caminho de comunicação. Essa dependência torna a implementação do orchestrator complexa e difícil de manter. O orquestrador pode ter um impacto negativo na confiabilidade da carga de trabalho. Sob carga, ele pode introduzir gargalo de desempenho e ser o único ponto de falha. Também pode causar falhas em cascata nos serviços a jusante.
Solução
Delegue a lógica de manipulação de transações entre os serviços. Permita que cada serviço decida e participe do fluxo de trabalho de comunicação para uma operação comercial.
O padrão é uma maneira de minimizar a dependência de software personalizado que centraliza o fluxo de trabalho de comunicação. Os componentes implementam uma lógica comum à medida que coreografam o fluxo de trabalho entre si sem terem comunicação direta entre si.
Uma maneira comum de implementar coreografias é usar um agente de mensagens que armazena solicitações em buffer até que os componentes downstream as reivindiquem e processem. A imagem mostra o tratamento de solicitações por meio de um modelo de editor-assinante.
As solicitações de um cliente são enfileiradas como mensagens em um agente de mensagens.
Os serviços ou o assinante pesquisam o corretor para determinar se eles podem processar essa mensagem com base em sua lógica de negócios implementada. O corretor também pode enviar mensagens para os assinantes que estão interessados nessa mensagem.
Cada serviço subscrito faz a sua operação conforme indicado pela mensagem e responde ao corretor com sucesso ou falha da operação.
Se for bem-sucedido, o serviço pode enviar uma mensagem de volta para a mesma fila ou para uma fila de mensagens diferente para que outro serviço possa continuar o fluxo de trabalho, se necessário. Se a operação falhar, o agente de mensagens trabalha com outros serviços para compensar essa operação ou toda a transação.
Problemas e considerações
Descentralizar o orquestrador pode causar problemas ao gerenciar o fluxo de trabalho.
Lidar com falhas pode ser um desafio. Os componentes de um aplicativo podem conduzir tarefas atômicas, mas ainda podem ter um nível de dependência. Uma falha em um componente pode afetar outros, o que pode causar atrasos na conclusão da solicitação geral.
Para lidar com falhas normalmente, a implementação de transações de compensação pode introduzir complexidade. A lógica de tratamento de falhas, como a compensação de transações, também é propensa a falhas.
O padrão é adequado para um fluxo de trabalho onde as operações comerciais independentes são processadas em paralelo. O fluxo de trabalho pode se tornar complicado quando a coreografia precisa ocorrer em uma sequência. Por exemplo, o Serviço D só pode iniciar a sua operação depois de o Serviço B e o Serviço C terem concluído as suas operações com êxito.
O padrão torna-se um desafio se o número de serviços crescer rapidamente. Dado o elevado número de peças móveis independentes, o fluxo de trabalho entre serviços tende a tornar-se complexo. Além disso, o rastreamento distribuído torna-se difícil, embora ferramentas como o ServiceInsight, juntamente com o NServiceBus, possam ajudar a reduzir esses desafios.
Em um design liderado por orquestrador, o componente central pode participar parcialmente e delegar a lógica de resiliência a outro componente que repete falhas transitórias, não transitórias e de tempo limite, de forma consistente. Com a dissolução do orquestrador no padrão coreográfico, os componentes a jusante não devem captar essas tarefas de resiliência. Esses ainda devem ser manipulados pelo manipulador de resiliência. Mas agora, os componentes downstream devem se comunicar diretamente com o manipulador de resiliência, aumentando a comunicação ponto-a-ponto.
Quando utilizar este padrão
Utilize este padrão quando:
Os componentes a jusante lidam com operações atómicas de forma independente. Pense nisso como um mecanismo de "fogo e esquecimento". Um componente é responsável por uma tarefa que não precisa ser gerenciada ativamente. Quando a tarefa é concluída, ele envia uma notificação para os outros componentes.
Espera-se que os componentes sejam atualizados e substituídos com frequência. O padrão permite que o aplicativo seja modificado com menos esforço e interrupção mínima nos serviços existentes.
O padrão é um ajuste natural para arquiteturas sem servidor que são apropriadas para fluxos de trabalho simples. Os componentes podem ser de curta duração e orientados por eventos. Quando ocorre um evento, os componentes são girados, executam suas tarefas e são removidos assim que a tarefa é concluída.
Este padrão pode ser uma boa escolha para comunicações entre contextos limitados. Para comunicações dentro de um contexto individual limitado, um padrão orquestrador pode ser considerado.
Há um gargalo de performance introduzido pelo orquestrador central.
Este padrão poderá não ser prático quando:
O aplicativo é complexo e requer um componente central para lidar com a lógica compartilhada para manter os componentes a jusante leves.
Há situações em que a comunicação ponto-a-ponto entre os componentes é inevitável.
Você precisa consolidar todas as operações tratadas por componentes downstream, usando a lógica de negócios.
Design da carga de trabalho
Um arquiteto deve avaliar como o padrão de coreografia pode ser usado no design de sua carga de trabalho para abordar as metas e os princípios abordados nos pilares do Azure Well-Architected Framework. Por exemplo:
Pilar | Como esse padrão suporta os objetivos do pilar |
---|---|
A Excelência Operacional ajuda a fornecer qualidade de carga de trabalho por meio de processos padronizados e coesão da equipe. | Como os componentes distribuídos nesse padrão são autônomos e projetados para serem substituíveis, você pode modificar a carga de trabalho com menos alterações gerais no sistema. - OE:04 Ferramentas e processos |
A Eficiência de Desempenho ajuda sua carga de trabalho a atender às demandas de forma eficiente por meio de otimizações em escala, dados e código. | Esse padrão fornece uma alternativa quando gargalos de desempenho ocorrem em uma topologia de orquestração centralizada. - PE:02 Planeamento da capacidade - PE:05 Dimensionamento e particionamento |
Como em qualquer decisão de design, considere quaisquer compensações em relação aos objetivos dos outros pilares que possam ser introduzidos com esse padrão.
Exemplo
Este exemplo mostra o padrão de coreografia criando uma carga de trabalho nativa da nuvem orientada por eventos executando funções junto com microsserviços. Quando um cliente solicita que um pacote seja enviado, a carga de trabalho atribui um drone. Assim que o pacote estiver pronto para ser retirado pelo drone agendado, o processo de entrega é iniciado. Durante o trânsito, a carga de trabalho lida com a entrega até que ela ganhe o status de remessa.
Este exemplo é uma refatoração da implementação do Drone Delivery que substitui o padrão Orchestrator pelo padrão Coreografia.
O serviço Ingestão lida com as solicitações do cliente e as converte em mensagens, incluindo os detalhes da entrega. As transações comerciais são iniciadas após o consumo dessas novas mensagens.
Uma transação comercial de um único cliente requer três operações comerciais distintas:
- Criar ou atualizar um pacote
- Atribua um drone para entregar o pacote
- Lidar com a entrega que consiste em verificar e, eventualmente, aumentar a conscientização quando enviada.
Três microsserviços realizam o processamento do negócio: Pacote, Agendador de Drone e Serviços de Entrega. Em vez de um orquestrador central, os serviços usam mensagens para se comunicar entre si. Cada serviço seria responsável por implementar antecipadamente um protocolo que coordena de forma descentralizada o fluxo de trabalho do negócio.
Estruturar
A transação comercial é processada em uma sequência através de vários saltos. Cada salto está compartilhando um único barramento de mensagem entre todos os serviços empresariais.
Quando um cliente envia uma solicitação de entrega por meio de um ponto de extremidade HTTP, o serviço Ingestão a recebe, converte essa solicitação em uma mensagem e, em seguida, publica a mensagem no barramento de mensagens compartilhadas. Os serviços empresariais subscritos vão consumir novas mensagens adicionadas ao autocarro. Ao receber a mensagem, os serviços empresariais podem concluir a operação com êxito, falha ou o tempo limite da solicitação pode expirar. Se for bem-sucedido, os serviços respondem ao barramento com o código de status Ok, geram uma nova mensagem de operação e a enviam para o barramento de mensagens. Se houver uma falha ou tempo limite, o serviço relata a falha enviando o código de motivo para o barramento de mensagens. Além disso, a mensagem é adicionada a uma fila de mensagens mortas. As mensagens que não puderam ser recebidas ou processadas dentro de um período de tempo razoável e apropriado também são movidas para o DLQ.
O design usa vários barramentos de mensagens para processar toda a transação comercial. O Barramento de Serviço do Microsoft Azure e a Grade de Eventos do Microsoft Azure são compostos para fornecer a plataforma de serviço de mensagens para esse design. A carga de trabalho é implantada em Aplicativos de Contêiner do Azure que hospedam o Azure Functions para ingestão e aplicativos que manipulam processamento controlado por eventos que executa a lógica de negócios.
O design garante que a coreografia ocorra em sequência. Um único namespace do Barramento de Serviço do Azure contém um tópico com duas assinaturas e uma fila com reconhecimento de sessão. O serviço Ingestão publica mensagens sobre o tema. O serviço Package e o serviço Drone Scheduler subscrevem o tópico e publicam mensagens comunicando o sucesso à fila. Incluindo um identificador de sessão comum que um GUID associado ao identificador de entrega, permite o tratamento ordenado de sequências não limitadas de mensagens relacionadas. O serviço de Entrega aguarda duas mensagens relacionadas por transação. A primeira mensagem indica que o pacote está pronto para ser enviado e a segunda indica que um drone está programado.
Esse design usa o Barramento de Serviço do Azure para lidar com mensagens de alto valor que não podem ser perdidas ou duplicadas durante todo o processo de entrega. Quando o pacote é enviado, também é publicada uma alteração de estado para a Grade de Eventos do Azure. Neste design, o remetente do evento não tem nenhuma expectativa sobre como a mudança de estado é tratada. Os serviços de organização downstream que não estão incluídos como parte desse design podem estar ouvindo esse tipo de evento e reagir executando uma lógica de propósito comercial específica (ou seja, enviar por e-mail o status do pedido enviado para o usuário).
Se você estiver planejando implantar isso em outro serviço de computação, como o padrão pub-sub do AKS , o clichê de aplicação pode ser implementado com dois contêineres no mesmo pod. Um contêiner executa o embaixador que interage com seu barramento de mensagens de preferência, enquanto o outro executa a lógica de negócios. A abordagem com dois contêineres no mesmo pod melhora o desempenho e a escalabilidade. O embaixador e o serviço de negócios compartilham a mesma rede, permitindo baixa latência e alta taxa de transferência.
Para evitar operações de repetição em cascata que podem levar a vários esforços, os serviços empresariais devem sinalizar imediatamente mensagens inaceitáveis. É possível enriquecer essas mensagens usando códigos de motivo bem conhecidos ou um código de aplicativo definido, para que possam ser movidos para uma fila de letra morta (DLQ). Considere gerenciar problemas de consistência implementando o Saga a partir de serviços downstream. Por exemplo, outro serviço poderia lidar com mensagens com letras mortas para fins de correção apenas executando uma compensação, nova tentativa ou transação dinâmica.
Os serviços empresariais são idempotentes para garantir que as operações de repetição não resultem em recursos duplicados. Por exemplo, o serviço de pacote usa operações upsert para adicionar dados ao armazenamento de dados.
Recursos relacionados
Considere esses padrões em seu design para coreografia.
Modularize o serviço empresarial usando o padrão de design ambassador.
Implemente o padrão de nivelamento de carga baseado em fila para lidar com picos da carga de trabalho.
Use mensagens distribuídas assíncronas por meio do padrão editor-assinante.
Use transações de compensação para desfazer uma série de operações bem-sucedidas no caso de uma ou mais operações relacionadas falharem.
Para obter informações sobre como usar um agente de mensagens em uma infraestrutura de mensagens, consulte Opções de mensagens assíncronas no Azure.