Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Dica
Esse conteúdo é um trecho do eBook, arquitetura de microsserviços do .NET para aplicativos .NET em contêineres, disponível em do .NET Docs ou como um PDF para download gratuito que pode ser lido offline.
Conforme descrito anteriormente, quando você usa a comunicação baseada em eventos, um microsserviço publica um evento quando algo notável acontece, como quando atualiza uma entidade de negócios. Outros microsserviços assinam esses eventos. Quando um microsserviço recebe um evento, ele pode atualizar suas próprias entidades comerciais, o que pode levar a mais eventos sendo publicados. Essa é a essência do conceito de consistência eventual. Esse sistema de publicação/assinatura geralmente é executado usando uma implementação de um barramento de eventos. O barramento de evento pode ser criado como uma interface com a API necessária para assinar e cancelar a assinatura de eventos e eventos de publicação. Ele também pode ter uma ou mais implementações com base em qualquer comunicação entre processos ou mensagens, como uma fila de mensagens ou um barramento de serviço que dá suporte à comunicação assíncrona e a um modelo de publicação/assinatura.
Você pode usar eventos para implementar transações comerciais que abrangem vários serviços, o que oferece consistência eventual entre esses serviços. Uma transação eventualmente consistente consiste em uma série de ações distribuídas. Em cada ação, o microsserviço atualiza uma entidade de negócios e publica um evento que dispara a próxima ação. Lembre-se de que a transação não abrange a persistência subjacente e o barramento de eventos, portanto , a idempotência precisa ser tratada. Figura 6-18 abaixo, mostra um evento PriceUpdated publicado por meio de um barramento de eventos, de modo que a atualização de preço é propagada para a Cesta e outros microsserviços.
Figura 6-18. Comunicação controlada por evento com base em um barramento de evento
Esta seção descreve como você pode implementar esse tipo de comunicação com o .NET usando uma interface de barramento de eventos genérica, conforme mostrado na Figura 6-18. Há várias implementações potenciais, cada uma usando uma tecnologia ou infraestrutura diferente, como RabbitMQ, Barramento de Serviço do Azure ou qualquer outro barramento de serviço de software livre ou comercial de terceiros.
Usar agentes de mensagem e barramentos de serviços para sistemas de produção
Conforme observado na seção de arquitetura, você pode escolher entre várias tecnologias de mensagens para implementar seu barramento de eventos abstrato. Mas essas tecnologias estão em níveis diferentes. Por exemplo, RabbitMQ, um transporte de agente de mensagens, está em um nível inferior a produtos comerciais, como o Barramento de Serviço do Azure, o NServiceBus, o MassTransit ou o Brighter. A maioria desses produtos pode operar sobre RabbitMQ ou Barramento de Serviço do Azure. Sua escolha de produto depende de quantos recursos e quanta escalabilidade pronta para uso você precisa para seu aplicativo.
Para implementar apenas uma prova de conceito de barramento de evento para seu ambiente de desenvolvimento, como fizemos no exemplo de eShopOnContainers, pode ser suficiente uma implementação simples sobre RabbitMQ em execução como um contêiner. Mas para sistemas de produção e críticos que precisam de alta escalabilidade, talvez você queira avaliar e usar o Barramento de Serviço do Azure.
Se você precisar de abstrações de alto nível e recursos mais robustos, como Sagas, para processos de longa execução que tornam mais fácil o desenvolvimento distribuído, vale a pena avaliar outros barramentos de serviço comerciais e de código aberto, como NServiceBus, MassTransit e Brighter. Nesse caso, as abstrações e a API a serem usadas em geral serão seriam diretamente aquelas fornecidas por esses barramentos de serviço de alto nível, em vez das suas próprias abstrações (como abstrações de barramento de evento simples fornecidas no eShopOnContainers). Para isso, você pode pesquisar o eShopOnContainers bifurcado usando NServiceBus (amostra derivada adicional implementada pelo Software Específico).
É claro que você sempre pode criar seus próprios recursos de barramento de serviço sobre tecnologias de nível inferior, como RabbitMQ e Docker, mas o trabalho necessário para "reinventar a roda" pode ser muito caro para um aplicativo empresarial personalizado.
Para reiterar: as abstrações do barramento de evento de exemplo e a implementação apresentada no exemplo do eShopOnContainers devem ser usados apenas como uma prova de conceito. Quando decidir que deseja ter comunicação assíncrona e controlada por evento, conforme explicado na seção atual, você deve escolher o produto de barramento de serviço que melhor atenda às suas necessidades de produção.
Eventos de integração
Os eventos de integração são usados para colocar o estado do domínio em sincronia entre vários microsserviços ou sistemas externos. Essa funcionalidade é feita publicando eventos de integração fora do microsserviço. Quando um evento é publicado em vários microsserviços receptores (com tantos microsserviços quanto inscritos no evento de integração), o manipulador de eventos apropriado em cada microsserviço receptor manipula o evento.
Um evento de integração é basicamente uma classe que contém dados, como no exemplo a seguir:
public class ProductPriceChangedIntegrationEvent : IntegrationEvent
{
public int ProductId { get; private set; }
public decimal NewPrice { get; private set; }
public decimal OldPrice { get; private set; }
public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice,
decimal oldPrice)
{
ProductId = productId;
NewPrice = newPrice;
OldPrice = oldPrice;
}
}
Os eventos de integração podem ser definidos no nível do aplicativo de cada microsserviço, para que sejam dissociados de outros microsserviços, de forma comparável à forma como os ViewModels são definidos no servidor e no cliente. O que não é recomendado é compartilhar uma biblioteca de eventos de integração comum em vários microsserviços; fazer isso seria acoplar esses microsserviços com uma única biblioteca de dados de definição de evento. Você não deseja fazer isso pelos mesmos motivos pelos quais não deseja compartilhar um modelo de domínio comum em vários microsserviços: os microsserviços devem ser completamente autônomos. Para obter mais informações, consulte esta postagem no blog sobre a quantidade de dados a serem colocados em eventos. Tenha cuidado para não levar isso longe demais, pois esta outra postagem no blog descreve o problema que mensagens deficientes de dados podem produzir. Seu design de eventos deve ser adequado às necessidades de seus consumidores.
Há apenas alguns tipos de bibliotecas que você deve compartilhar entre microsserviços. Um são as bibliotecas que são blocos de aplicativo finais, como API cliente do Barramento de Evento, conforme mostrado em eShopOnContainers. Outra é bibliotecas que constituem ferramentas que também podem ser compartilhadas como componentes do NuGet, como serializadores JSON.
O barramento de evento
Um barramento de eventos permite a comunicação no estilo de publicação/assinatura entre microsserviços sem exigir que os componentes estejam explicitamente cientes uns dos outros, conforme mostrado na Figura 6-19.
Figura 6-19. Noções básicas sobre publicação/assinatura com um barramento de evento
O diagrama acima mostra que o microsserviço A publica no Barramento de Evento, que distribui para assinantes os microsserviços B e C, sem que o publicador saiba quem são os assinantes. O barramento de evento está relacionado ao padrão Observador e ao padrão de publicação/assinatura.
Padrão de observador
No padrão Observer, seu objeto primário (conhecido como Observável) notifica outros objetos interessados (conhecidos como Observadores) com informações relevantes (eventos).
Padrão de Publicação/Assinatura (Pub/Sub)
A finalidade do padrão Publicar/Assinar é a mesma que o padrão observador: você deseja notificar outros serviços quando determinados eventos ocorrerem. Mas há uma diferença importante entre os padrões Observer e Pub/Sub. No padrão de observador, a transmissão é executada diretamente do observável para os observadores, para que eles "se conheçam". No entanto, ao usar um padrão Pub/Sub, há um terceiro componente, conhecido como corretor de mensagens ou barramento de eventos, que é conhecido tanto pelo editor quanto pelo assinante. Portanto, ao usar o padrão Pub/Sub, o publicador e os assinantes são precisamente desacoplados graças ao agente de mensagem ou barramento de evento mencionado.
O barramento de evento ou intermediário
Como você obtém o anonimato entre o publicador e o assinante? Uma maneira fácil é deixar um intermediário cuidar de toda a comunicação. Um ônibus de evento é um desses intermediários.
Um barramento de evento normalmente é composto por duas partes:
A abstração ou interface.
Uma ou mais implementações.
Na Figura 6-19, você pode ver como, de um ponto de vista de aplicativo, o barramento de evento é nada mais que um canal Pub/Sub. A maneira como você implementa essa comunicação assíncrona pode variar. Ele pode ter várias implementações para que você possa alternar entre elas, dependendo dos requisitos de ambiente (por exemplo, produção versus ambientes de desenvolvimento).
Na Figura 6-20, você pode ver uma abstração de um barramento de eventos com várias implementações baseadas em tecnologias de mensagens de infraestrutura, como RabbitMQ, Barramento de Serviço do Azure ou outro agente de eventos/mensagens.
Figura 6 a 20. Várias implementações de um barramento de evento
É bom ter o barramento de eventos definido por meio de uma interface para que ele possa ser implementado com várias tecnologias, como RabbitMQ, barramento de Serviço do Azure ou outras. No entanto, e conforme mencionado anteriormente, usar suas próprias abstrações (a interface do barramento de eventos) só será bom se você precisar de recursos básicos do barramento de eventos compatíveis com suas abstrações. Se você precisar de recursos mais avançados do barramento de serviço, provavelmente deverá usar a API e as abstrações fornecidas pelo barramento de serviço comercial preferido em vez de suas próprias abstrações.
Definir uma interface de barramento de evento
Vamos começar com algum código de implementação para a interface de barramento de evento e possíveis implementações para fins de exploração. A interface deve ser genérica e simples, como na interface a seguir.
public interface IEventBus
{
void Publish(IntegrationEvent @event);
void Subscribe<T, TH>()
where T : IntegrationEvent
where TH : IIntegrationEventHandler<T>;
void SubscribeDynamic<TH>(string eventName)
where TH : IDynamicIntegrationEventHandler;
void UnsubscribeDynamic<TH>(string eventName)
where TH : IDynamicIntegrationEventHandler;
void Unsubscribe<T, TH>()
where TH : IIntegrationEventHandler<T>
where T : IntegrationEvent;
}
O Publish método é simples. O barramento de evento difundirá o evento de integração passado a ele para qualquer microsserviço ou até mesmo um aplicativo externo, que assine esse evento. Esse método é usado pelo microsserviço que está publicando o evento.
Os Subscribe métodos (você pode ter várias implementações dependendo dos argumentos) são usados pelos microsserviços que desejam receber eventos. Esse método tem dois argumentos. O primeiro é o evento de integração ao qual assinar (IntegrationEvent). O segundo argumento é o manipulador de eventos de integração (ou método de retorno de chamada), nomeado IIntegrationEventHandler<T>, a ser executado quando o microsserviço receptor obtém essa mensagem de evento de integração.
Recursos adicionais
Algumas soluções de mensagens prontas para produção:
Barramento de Serviço do Azure
https://learn.microsoft.com/azure/service-bus-messaging/NServiceBus
https://particular.net/nservicebusMassTransit
https://masstransit-project.com/