Compartilhar via


Comunicação serviço a serviço

Dica

Esse conteúdo é um trecho do livro eletrônico, para Projetar os Aplicativos .NET nativos de nuvem para o Azure, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

Cloud Native .NET apps for Azure eBook cover thumbnail.

Movendo-se do cliente front-end, agora abordamos microsserviços de back-end que se comunicam entre si.

Ao construir um aplicativo nativo de nuvem, você desejará ser sensível à forma como os serviços de back-end se comunicam entre si. Idealmente, quanto menos comunicação entre serviços, melhor. No entanto, a prevenção nem sempre é possível, pois os serviços de back-end geralmente dependem uns dos outros para concluir uma operação.

Há várias abordagens amplamente aceitas para implementar a comunicação entre serviços. O tipo de interação de comunicação geralmente determinará a melhor abordagem.

Considere os seguintes tipos de interação:

  • Consulta – quando um microsserviço de chamada requer uma resposta de um microsserviço chamado, como: “Ei, me dê as informações do comprador para uma determinada ID do cliente”.

  • Comando – quando o microsserviço de chamada precisa de outro microsserviço para executar uma ação, mas não requer uma resposta, como"Ei, basta enviar essa ordem".

  • Evento – quando um microsserviço, chamado de publicador, gera um evento em que o estado foi alterado ou ocorreu uma ação. Outros microsserviços, chamados assinantes, que estão interessados, podem reagir ao evento adequadamente. O publicador e os assinantes não estão cientes uns dos outros.

Os sistemas de microsserviço normalmente usam uma combinação desses tipos de interação ao executar operações que exigem interação entre serviços. Vamos examinar de perto cada um e como você pode implementá-los.

Consultas

Muitas vezes, um microsserviço pode precisar consultar outro, exigindo uma resposta imediata para concluir uma operação. Um microsserviço de cesta de compras pode precisar de informações do produto e um preço para adicionar um item à sua cesta. Há muitas abordagens para implementar operações de consulta.

Serviço de mensagens de solicitação/resposta

Uma opção para implementar esse cenário é que o microsserviço de back-end de chamada faça solicitações HTTP diretas para os microsserviços necessários para consultar, mostrado na Figura 4-8.

Direct HTTP communication

Figura 4-8. Comunicação por HTTP direta.

Embora as chamadas por HTTP diretas entre microsserviços sejam relativamente simples de serem implementadas, deve-se tomar cuidado para minimizar essa prática. Para iniciar, essas chamadas são sempre síncronas e bloquearão a operação até que um resultado seja retornado ou a solicitação tenha tempos limite. O que antes era autossuficiente, serviços independentes, com possibilidade de evoluir de forma independente e implantar com frequência, agora se tornam acoplados uns aos outros. À medida que o acoplamento entre os microsserviços aumenta, seus benefícios arquitetônicos diminuem.

Executar uma solicitação pouco frequente que faz uma única chamada por HTTP direta para outro microsserviço pode ser aceitável para alguns sistemas. No entanto, chamadas de alto volume que invocam chamadas por HTTP diretas para vários microsserviços não são aconselháveis. Eles podem aumentar a latência e afetar negativamente o desempenho, a escalabilidade e a disponibilidade do sistema. Pior ainda, uma longa série de comunicação por HTTP direta pode levar a cadeias profundas e complexas de chamadas de microsserviços síncronas, mostradas na Figura 4-9:

Chaining HTTP queries

Figura 4-9. Encadeamento de consultas por HTTP

Você certamente pode imaginar o risco no design mostrado na imagem anterior. O que acontece se a Etapa nº 3 falhar? Ou a etapa nº 8 falhar? Como você se recupera? E se a Etapa nº 6 for lenta porque o serviço subjacente está ocupado? Como você continua? Mesmo que tudo funcione corretamente, pense na latência que essa chamada incorreria, que é a soma da latência de cada etapa.

O grande grau de acoplamento na imagem anterior sugere que os serviços não foram modelados de forma ideal. Seria bom que a equipe revisitasse seu design.

Padrão de Exibição Materializada

Uma opção popular para remover o acoplamento de microsserviço é o padrão Exibição Materializada. Com esse padrão, um microsserviço armazena sua própria cópia local desnormalizada de dados pertencente a outros serviços. Em vez do microsserviço do Shopping Basket que consulta o Catálogo de Produtos e os microsserviços de preços, ele mantém sua própria cópia local desses dados. Esse padrão elimina o acoplamento desnecessário e melhora a confiabilidade e o tempo de resposta. Toda a operação é executada dentro de um único processo. Exploramos esse padrão e outras preocupações de dados no Capítulo 5.

Padrão do Agregador de Serviço

Outra opção para eliminar o acoplamento de microsserviço a microsserviço é um microsserviço agregador, mostrado em roxo na Figura 4-10.

Aggregator service

Figura 4-10. Microsserviço agregador

O padrão isola uma operação que faz chamadas para vários microsserviços de back-end, centralizando sua lógica em um microsserviço especializado. O microsserviço agregador de check-out roxo na figura anterior orquestra o fluxo de trabalho para a operação de Check-out. Ele inclui chamadas para vários microsserviços de back-end em uma ordem sequenciada. Os dados do fluxo de trabalho são agregados e retornados ao chamador. Embora ainda implemente chamadas por HTTP diretas, o microsserviço agregador reduz as dependências diretas entre os microsserviços de back-end.

Padrão de solicitação/resposta

Outra abordagem para desacoplar mensagens por HTTP síncronas é um Padrão de Solicitação-Resposta, que usa comunicação de enfileiramento. A comunicação usando uma fila é sempre um canal unidirecional, com um produtor enviando a mensagem e o consumidor recebendo-a. Com esse padrão, uma fila de solicitações e uma fila de resposta são implementadas, mostrada na Figura 4-11.

Request-reply pattern

Figura 4-11. Padrão de solicitação/resposta

Aqui, o produtor de mensagens cria uma mensagem baseada em consulta que contém uma ID de correlação exclusiva e a coloca em uma fila de solicitação. O serviço de consumo desativa as mensagens, processa-as e coloca a resposta na fila de resposta com a mesma ID de correlação. O serviço de produtor desativa a mensagem, corresponde à ID de correlação e continua o processamento. Abordamos as filas em detalhes na próxima seção.

Comandos

Outro tipo de interação de comunicação é um comando. Um microsserviço pode precisar de outro microsserviço para executar uma ação. O microsserviço de Ordenação pode precisar do microsserviço de Envio para criar uma remessa para uma ordem aprovada. Na Figura 4-12, um microsserviço, chamado Produtor, envia uma mensagem para outro microsserviço, o Consumidor, ordenando que ele faça algo.

Command interaction with a queue

Figura 4-12. Interação de comando com uma fila

Na maioria das vezes, o Produtor não requer uma resposta e pode disparar e esquecer a mensagem. Se uma resposta for necessária, o Consumidor enviará uma mensagem separada de volta ao Produtor em outro canal. Uma mensagem de comando é melhor enviada de forma assíncrona com uma fila de mensagens. com suporte de um agente de mensagens leve. No diagrama anterior, observe como uma fila separa e desacopla ambos os serviços.

Uma fila de mensagens é uma construção intermediária por meio da qual um produtor e um consumidor passam uma mensagem. As filas implementam um padrão assíncrono de mensagens ponto a ponto. O Produtor sabe para onde um comando precisa ser enviado e roteia adequadamente. A fila garante que uma mensagem seja processada por exatamente uma das instâncias de consumidor que estão lendo do canal. Nesse cenário, o produtor ou o serviço de consumidor podem escalar horizontalmente sem afetar o outro. Além disso, as tecnologias podem ser diferentes de cada lado, o que significa que podemos ter um microsserviço Java chamando um microsserviço Golang.

No capítulo 1, falamos sobre serviços de backup. Os serviços de backup são recursos auxiliares dos quais os sistemas nativos de nuvem dependem. Filas de mensagens são serviços de backup. A nuvem do Azure dá suporte a dois tipos de filas de mensagens que seus sistemas nativos de nuvem podem consumir para implementar mensagens de comando: Filas de Armazenamento do Microsoft Azure e filas de Barramento de Serviço do Azure.

Filas de Armazenamento do Azure

As Filas de Armazenamento do Microsoft Azure oferecem uma infraestrutura de fila simples que é rápida, acessível e apoiada por contas de armazenamento do Azure.

As Filas de Armazenamento do Microsoft Azure apresentam um mecanismo de fila baseado em REST com mensagens confiáveis e persistentes. Eles fornecem um conjunto de recursos mínimo, mas são baratos e armazenam milhões de mensagens. Sua capacidade varia até 500 TB. Uma única mensagem pode ter tamanho de até 64 KB.

É possível acessar as mensagens em qualquer lugar do mundo por meio de chamadas autenticadas usando o HTTP ou HTTPS. As filas de armazenamento podem ser expandidas para um grande número de clientes simultâneos para lidar com picos de tráfego.

Dito isto, há limitações com o serviço:

  • A ordem da mensagem não é garantida.

  • Uma mensagem só pode persistir por sete dias antes de ser removida automaticamente.

  • O suporte para gerenciamento de estado, detecção duplicada ou transações não está disponível.

A Figura 4-13 mostra a hierarquia de uma Fila de Armazenamento do Microsoft Azure.

Storage queue hierarchy

Figura 4-13. Hierarquia da fila de armazenamento

Na figura anterior, observe como as filas de armazenamento armazenam suas mensagens na conta de Armazenamento do Microsoft Azure subjacente.

Para desenvolvedores, a Microsoft fornece várias bibliotecas do lado do cliente e do servidor para processamento de fila de armazenamento. Há suporte para a maioria das principais plataformas, incluindo .NET, Java, JavaScript, Ruby, Python e Go. Os desenvolvedores nunca devem se comunicar diretamente com essas bibliotecas. Isso associará firmemente seu código de microsserviço ao serviço de Fila de Armazenamento do Microsoft Azure. É uma melhor prática isolar os detalhes de implementação da API. Introduza uma camada de intermediação, ou API intermediária, que expõe operações genéricas e encapsula a biblioteca de concreto. Esse acoplamento solto permite que você troque um serviço de fila por outro sem precisar fazer alterações no código de serviço da linha principal.

As filas de Armazenamento do Microsoft Azure são uma opção econômica para implementar mensagens de comando em seus aplicativos nativos de nuvem. Especialmente quando um tamanho de fila excede 80 GB ou um conjunto de recursos simples é aceitável. Você paga apenas pelo armazenamento das mensagens, não há encargos fixos por hora.

Filas do Barramento de Serviço do Azure

Para requisitos de mensagens mais complexos, considere as filas do Barramento de Serviço do Azure.

Posicionado em cima de uma infraestrutura de mensagens robusta, o Barramento de Serviço do Azure dá suporte a um modelo de mensagens agenciado. As mensagens são armazenadas de forma confiável em um agente (a fila) até serem recebidas pelo consumidor. A fila garante a entrega de mensagens FIFO (First-In/First-Out), respeitando a ordem em que as mensagens foram adicionadas à fila.

O tamanho de uma mensagem pode ser muito maior, até 256 KB. As mensagens são mantidas na fila por um período ilimitado de tempo. O Barramento de Serviço dá suporte não apenas a chamadas baseadas em HTTP, mas também fornece suporte completo para o protocolo AMQP. O AMQP é um padrão aberto entre os fornecedores que dá suporte a um protocolo binário e graus mais altos de confiabilidade.

O Barramento de Serviço fornece um conjunto avançado de recursos, incluindo suporte a transações e um recurso de detecção duplicado. A fila garante “no máximo uma entrega” por mensagem. Ele descarta automaticamente uma mensagem que já foi enviada. Se um produtor estiver em dúvida, ele poderá reenviar a mesma mensagem e o Barramento de Serviço garantirá que apenas uma cópia será processada. A detecção duplicada libera você de ter que compilar uma canalização de infraestrutura adicional.

Mais dois recursos corporativos são partições e sessões. Uma fila Barramento de Serviço convencional é manipulada por um único agente de mensagens e armazenada em um único armazenamento de mensagens. No entanto, o Particionamento do Barramento de Serviço espalha a fila entre vários agentes de mensagens e repositórios de mensagens. A taxa de transferência geral não é mais limitada pelo desempenho de um único agente de mensagens ou de um armazenamento de mensagens. Uma interrupção temporária de um repositório de mensagens não torna uma fila particionada indisponível.

As Sessões do Barramento de Serviço fornecem uma maneira de agrupar mensagens relacionadas. Imagine um cenário de fluxo de trabalho em que as mensagens devem ser processadas juntas e a operação concluída no final. Para aproveitar, as sessões devem ser explicitamente habilitadas para a fila e cada mensagem relacionada deve conter a mesma ID de sessão.

No entanto, há algumas restrições importantes: o tamanho das filas do Barramento de Serviço é limitado a 80 GB, o que é muito menor do que o disponível nas filas da loja. Além disso, as filas do Barramento de Serviço incorrem em um custo base e encargo por operação.

A Figura 4-14 descreve a arquitetura de alto nível de uma fila do Barramento de Serviço.

Service Bus queue

Figura 4-14. Fila do Barramento de Serviço

Na figura anterior, observe a relação ponto a ponto. Duas instâncias do mesmo provedor estão enfileirando mensagens em uma única fila do Barramento de Serviço. Cada mensagem é consumida por apenas uma das três instâncias de consumidor à direita. Em seguida, discutiremos como implementar mensagens em que diferentes consumidores podem estar interessados na mesma mensagem.

Eventos

A enfileiramento de mensagens é uma maneira eficaz de implementar a comunicação em que um produtor pode enviar uma mensagem a um consumidor de forma assíncrona. No entanto, o que acontece quando muitos consumidores diferentes estão interessados na mesma mensagem? Uma fila de mensagens dedicada para cada consumidor não seria bem dimensionada e se tornaria difícil de gerenciar.

Para resolver esse cenário, passamos para o terceiro tipo de interação de mensagem, o evento. Um microsserviço anuncia que uma ação ocorreu. Outros microsserviços, se interessados, reagem à ação ou evento. Também é conhecido como o estilo de arquitetura controlado por eventos.

O evento é um processo de duas etapas. Para uma determinada alteração de estado, um microsserviço publica um evento em um agente de mensagens, disponibilizando-o para qualquer outro microsserviço interessado. O microsserviço interessado é notificado assinando o evento no agente de mensagens. Você usa o padrão Publicar/Assinar para implementar a comunicação baseada em evento.

A Figura 4-15 mostra um microsserviço de cesta de compras publicando um evento com outros dois microsserviços assinando-o.

Event-Driven messaging

Figura 4-15. Mensagens controladas por evento

Observe o componente do barramento de eventos que fica no meio do canal de comunicação. É uma classe personalizada que encapsula o agente de mensagens e o separa do aplicativo subjacente. Os microsserviços de pedido e inventário operam o evento de forma independente, sem conhecimento um do outro, nem do microsserviço de cesta de compras. Quando o evento registrado é publicado no barramento de eventos, eles agem sobre ele.

Com o evento, passamos da tecnologia de enfileiramento para tópicos. Um tópico é semelhante a uma fila, mas dá suporte a um padrão de mensagens um para muitos. Um microsserviço publica uma mensagem. Vários microsserviços de assinatura podem optar por receber e agir sobre essa mensagem. A Figura 4-16 mostra uma arquitetura do tópico.

Topic architecture

Figura 4-16. Arquitetura de tópico

Na figura anterior, os editores enviam mensagens para o tópico. No final, os assinantes recebem mensagens de assinaturas. No meio, o tópico encaminha mensagens para assinaturas com base em um conjunto de regras, mostrado em caixas azuis escuras. As regras atuam como um filtro que encaminha mensagens específicas para uma assinatura. Aqui, um evento "GetPrice" seria enviado para o preço e assinaturas de log, pois a assinatura de log optou por receber todas as mensagens. Um evento "GetInformation" seria enviado para as informações e assinaturas de log.

A nuvem do Azure dá suporte a dois serviços de tópico diferentes: Tópicos do Barramento de Serviço do Azure e Azure EventGrid.

Tópicos do Barramento de Serviço do Azure

Posicionando-se sobre o mesmo modelo de mensagem agenciado robusto das filas do Barramento de Serviço do Azure estão os Tópicos do Barramento de Serviço do Azure. Um tópico pode receber mensagens de vários editores independentes e enviar mensagens para até 2.000 assinantes. As assinaturas podem ser adicionadas ou removidas dinamicamente em tempo de execução sem interromper o sistema ou recriar o tópico.

Muitos recursos avançados de filas de Barramento de Serviço do Azure também estão disponíveis para tópicos, incluindo suporte a Detecção e Transação Duplicadas. Por padrão, os tópicos do Barramento de Serviço são manipulados por um único agente de mensagens e armazenada em um único armazenamento de mensagens. Mas, o Particionamento do Barramento de Serviço escala um tópico espalhando-o entre muitos agentes de mensagens e repositórios de mensagens.

A Entrega de Mensagens Agendada marca uma mensagem com um horário específico para processamento. A mensagem não aparecerá no tópico antes desse horário. O Adiamento da Mensagem permite que você adie a recuperação de uma mensagem para uma hora posterior. Ambos são comumente usados em cenários de processamento de fluxo de trabalho em que as operações são processadas em uma ordem específica. Você pode adiar o processamento de mensagens recebidas até que o trabalho anterior seja concluído.

Os tópicos do Barramento de Serviço são uma tecnologia robusta e comprovada para habilitar a comunicação de publicação/assinatura em seus sistemas nativos de nuvem.

Grade de Eventos do Azure

Embora o Barramento de Serviço do Azure seja um agente de mensagens testado em batalha com um conjunto completo de recursos empresariais, a Grade de Eventos do Azure é a nova garota no bloco.

À primeira vista, a Grade de Eventos pode parecer apenas com outro sistema de mensagens baseado em tópicos. No entanto, é diferente em muitos aspectos. Focada em cargas de trabalho controladas por eventos, ela habilita o processamento de eventos em tempo real, a integração profunda do Azure e uma plataforma aberta. Tudo em infraestrutura sem servidor. Ela foi projetada para aplicativos nativos de nuvem contemporâneos e sem servidor

Como um backplane de eventos centralizado ou pipe, a Grade de Eventos reage a eventos dentro dos recursos do Azure e de seus próprios serviços.

As notificações de evento são publicadas em um Tópico da Grade de Eventos que, por sua vez, roteia cada evento para uma assinatura. Os assinantes mapeiam para assinaturas e consomem os eventos. Assim como o Barramento de Serviço, a Grade de Eventos dá suporte a um modelo de assinante filtrado em que uma assinatura define a regra para os eventos que deseja receber. A Grade de Eventos fornece uma taxa de transferência rápida com uma garantia de 10 milhões de eventos por segundo, permitindo entrega quase em tempo real, muito mais do que o Barramento de Serviço do Azure pode gerar.

Um ponto ideal para a Grade de Eventos é sua profunda integração à malha da infraestrutura do Azure. Um recurso do Azure, como o Cosmos DB, pode publicar eventos internos diretamente em outros recursos do Azure interessados, sem a necessidade de código personalizado. A Grade de Eventos pode publicar eventos de uma Assinatura, Grupo de Recursos ou Serviço do Azure, oferecendo aos desenvolvedores controle refinado sobre o ciclo de vida dos recursos de nuvem. No entanto, a Grade de Eventos não está limitada ao Azure. É uma plataforma aberta que pode consumir eventos de HTTP personalizados publicados de aplicativos ou serviços de terceiros e rotear eventos para assinantes externos.

Ao publicar e assinar eventos nativos de recursos do Azure, nenhuma codificação é necessária. Com uma configuração simples, você pode integrar eventos de um recurso do Azure a outro aproveitando a canalização interna para Tópicos e Assinaturas. A Figura 4-17 mostra a anatomia da Grade de Eventos.

Event Grid anatomy

Figura 4-17. Anatomia da Grade de Eventos

Uma grande diferença entre EventGrid e Barramento de Serviço é o padrão de troca de mensagens subjacente.

O Barramento de Serviço implementa um modelo de pull de estilo mais antigo no qual o assinante downstream sonda ativamente a assinatura do tópico em busca de novas mensagens. Por outro lado, essa abordagem fornece ao assinante controle total do ritmo em que processa mensagens. Ele controla quando e quantas mensagens processar a qualquer momento. As mensagens não lidas permanecem na assinatura até serem processadas. Uma deficiência significativa é a latência entre o momento em que o evento é gerado e a operação de sondagem que puxa essa mensagem para o assinante para processamento. Além disso, a sobrecarga de sondagem constante para o próximo evento consome recursos e dinheiro.

EventGrid, no entanto, é diferente. Ele implementa um modelo de push no qual os eventos são enviados aos EventHandlers como recebidos, proporcionando entrega de eventos quase em tempo real. Ele também reduz o custo à medida que o serviço é disparado somente quando é necessário consumir um evento, não continuamente como na sondagem. Dito isto, um manipulador de eventos deve lidar com a carga de entrada e fornecer mecanismos de limitação para se proteger de ficar sobrecarregado. Muitos serviços do Azure que consomem esses eventos, como p Azure Functions e os Aplicativos Lógicos, fornecem recursos automáticos de dimensionamento automático para lidar com cargas maiores.

A Grade de Eventos é um serviço de nuvem sem servidor totalmente gerenciado. Ele é dimensionado dinamicamente com base no tráfego e cobra apenas pelo uso real, não pela capacidade pré-comprada. As primeiras 100.000 operações por mês são gratuitas, operações que estão sendo definidas como entrada de evento (notificações de eventos de entrada), tentativas de entrega de assinatura, chamadas de gerenciamento e filtragem por assunto. Com 99,99% de disponibilidade, o EventGrid garante a entrega de um evento dentro de um período de 24 horas, com funcionalidade de repetição interna para entrega malsucedida. Mensagens não entregues podem ser movidas para uma fila de “mensagens mortas” para resolução. Ao contrário do Barramento de Serviço do Azure, a Grade de Eventos é ajustada para desempenho rápido e não dá suporte a recursos como mensagens ordenadas, transações e sessões.

Transmitir mensagens na nuvem do Azure

O Barramento de Serviço do Azure e a Grade de Eventos oferecem um ótimo suporte para aplicativos que expõem eventos únicos e discretos, como um novo documento, foram inseridos em um Cosmos DB. Mas e se seu sistema nativo de nuvem precisar processar um fluxo de eventos relacionados? Os fluxos de eventos são mais complexos. Normalmente, elas são ordenadas por tempo, inter-relacionados e devem ser processados como um grupo.

O Hub de Eventos do Azure é uma plataforma de streaming de dados e um serviço de ingestão de eventos que coleta, transforma e armazena eventos. É ajustado para capturar dados de streaming, como notificações de eventos contínuas emitidas de um contexto de telemetria. O serviço é altamente escalonável e pode armazenar e processar milhões de eventos por segundo. Mostrado na Figura 4-18, geralmente é uma porta da frente para um pipeline de eventos, separando o fluxo de ingestão do consumo de eventos.

Azure Event Hub

Figura 4-18. Hub de Eventos do Azure

O Hub de Eventos dá suporte à baixa latência e à retenção de tempo configurável. Ao contrário de filas e tópicos, os Hubs de Eventos mantêm os dados do evento depois de serem lidos por um consumidor. Esse recurso permite que outros serviços de análise de dados, internos e externos, reproduzam os dados para análise adicional. Os eventos armazenados no hub de eventos são excluídos somente após a expiração do período de retenção, que é um dia por padrão, mas configurável.

O Hub de Eventos dá suporte a protocolos comuns de publicação de eventos, incluindo HTTPS e AMQP. Ele também dá suporte ao Kafka 1.0. Os aplicativos Kafka existentes podem se comunicar com o Hub de Eventos usando o protocolo Kafka, fornecendo uma alternativa ao gerenciamento de clusters de Kafka grandes. Muitos sistemas nativos de nuvem de software de código aberto adotam o Kafka.

Os Hubs de Eventos implementam o streaming de mensagens por meio de um modelo de consumidor particionado no qual cada consumidor lê apenas um subconjunto específico, ou partição, do fluxo de mensagens. Esse padrão permite a enorme escala horizontal para processamento de eventos e fornece outros recursos centrados no fluxo que não estão disponíveis em filas e tópicos. Uma partição é uma sequência ordenada de eventos que é mantida em um hub de eventos. À medida que novos eventos chegam, eles são adicionados ao final dessa sequência. A Figura 4-19 mostra o particionamento em um Hub de Eventos.

Event Hub partitioning

Figura 4-19. Particionamento do Hub de Eventos

Em vez de ler do mesmo recurso, cada grupo de consumidores lê em um subconjunto ou partição do fluxo de mensagens.

Para aplicativos nativos de nuvem que devem transmitir um grande número de eventos, o Hub de Eventos do Azure pode ser uma solução robusta e acessível.