Estou fazendo um projeto de pesquisa em que estou pesquisando as opções para lidar com alterações em uma arquitetura de microsserviço orientada a eventos.
Então, digamos que temos um aplicativo em que temos quatro serviços diferentes. Cada um desses serviços possui um banco de dados próprio para armazenar dados locais.
Nesta configuração, os quatro serviços se comunicam usando um barramento de eventos. Então, quando algo acontece em um serviço, ele publica um evento. Todos os outros serviços interessados nesse evento irão processá-lo à sua maneira.
Nesse caso, os diferentes serviços na arquitetura precisam ter "contratos" sobre o conteúdo desses eventos (atributos etc.). Portanto, os serviços têm "dependências fracamente acopladas" a esses eventos
Minha pergunta é: como podemos lidar com as mudanças nesses eventos?
Então, digamos que o serviço A registre novos usuários no aplicativo. Por isso, ele envia um evento "" UserRegistered ". O serviço B pega esse evento e o processa. Mas alguns desenvolvedores da equipe do serviço C decidiram que também precisam do sexo de um usuário registrado. Portanto, o evento é alterado e o atributo gender é adicionado ao evento "UserRegistered".
Como podemos garantir que o Serviço B ainda possa capturar o mesmo evento com esse atributo extra sem reimplementar?
E existem outras maneiras de abordar esse problema e depois fazer a versão desses eventos?
Respostas:
Eventos não são sobre o que mudou. Eles são sobre quando algo mudou.
Eu posso criar um sistema de eventos completamente dissociado do conteúdo que foi alterado. Dessa forma, tudo que eu aprendo com um evento é que um objeto foi atualizado. Se eu me importar que o objeto tenha sido atualizado, direi ao que sabe falar com esse objeto para perguntar o que mudou.
Isso não resolve o problema de comunicar essas mudanças. Apenas impede que se torne parte do sistema de eventos.
Um exemplo de uma maneira de resolver o problema de diferentes versões de dados é fazer com que o observador crie e entregue ao objeto observado uma coleção. O objeto observado preenche a coleção com seus dados mais recentes e quando o controle retorna você (o observador) tem o que precisa. Se há algo extra com o qual você não se importa, porque nunca ouviu falar, simplesmente o ignora.
Muitas outras maneiras de esfolar esse gato, mas essa é uma que eu fiz funcionar exatamente nesse caso.
fonte
UserRegistered
evento, se houvesse um evento que não contivesse informações sobre o usuário, haveria 1 mensagem publicada no barramento e, em seguida, {número de serviços interessados} solicitações ao serviço do usuário ou mensagens publicadas para o ônibus. Então, haveria {número de serviços interessados} mensagens de vários tamanhos. Embora eu ache que esse provavelmente seja um design mais limpo no papel, se o desempenho for uma preocupação, ele falha em qualquer sistema não trivial, especialmente em uma rede.Estruturas como o NServiceBus lidam com isso usando a versão de eventos com despacho de mensagens polimórficas.
Por exemplo, a versão 1 do Serviço A pode publicar um evento como IUserRegistered_v1. Quando o Serviço A versão 1.1 precisar incluir um campo adicional, ele poderá declarar a interface IUserRegistered_v1_1, que herdaria de IUserRegistered_v1, além de declarar alguns campos adicionais.
Quando o Serviço A publica um evento IUserRegistered_v1_1, o NServiceBus envia a mensagem para todos os pontos de extremidade que tratam IUserRegistered_v1 ou IUserRegistered_v1_1.
fonte
Melhoria Incremental
Uma mudança simples no modelo é que, quando os ouvintes se registram como observadores, eles incluem uma lista ou outra estrutura dos elementos de dados que desejam conhecer. Isso pode funcionar se os dados retornados do serviço forem simples, mas se você tiver uma quantidade razoável de dados hierárquicos, isso poderá ser realmente complicado de implementar.
Rocha sólida
Se você realmente deseja uma maneira robusta de fazer isso, projete o serviço de forma que ele mantenha um histórico das alterações feitas nos dados armazenados. Essencialmente, você nunca atualiza registros em seu banco de dados, adiciona novos registros em que cada um representa a alteração. Cada um desses novos registros está associado a um ID de evento que identifica a ação. Um registro par é armazenado com todas as informações relevantes sobre a alteração (quem, o que, quando, etc.). Isso tem outros benefícios que estão fora do escopo desta resposta, mas são discutidos neste artigo sobre o teorema da CAP .
Quando uma alteração é feita, você cria o registro do evento e adiciona todos os novos dados ao seu banco de dados. Em seguida, você publica um evento para os ouvintes que contém (no mínimo) o ID do evento. Os ouvintes podem solicitar os dados associados a esse ID e obter a versão dos dados associados a ele. Cada ouvinte é capaz de obter o que precisa sem acoplar as necessidades de outros ouvintes diferentes. Aconselho que você adicione um subconjunto dos campos de dados mais usados à mensagem do evento, para que os ouvintes possam filtrar eventos nos quais não estão interessados. Isso pode reduzir a propriedade do processo e alguns ouvintes talvez nunca precisem ligar. de volta a todos. Isso também protege você de problemas de tempo. Se você acabou de ligar para o serviço e obter os dados com base na chave, pode haver outras alterações ocorridas entre a obtenção do evento e a recuperação dos dados. Isso pode não ser importante para todos os ouvintes, mas pode criar grandes problemas se você precisar conhecer todas as alterações. A melhoria incremental do projeto acima é compatível com essa abordagem, se você realmente deseja transformá-la em 11.
Parte disso pode ser um exagero para o que você precisa fazer, mas, na minha experiência, se você não tiver uma maneira precisa de ver como um registro está mudando ao longo do tempo, você ou alguém trabalhando com seus dados acabará desejando.
fonte
@CandiedOrange faz um argumento válido em um comentário para sua própria resposta sobre formatos de dados extensíveis, como xml.
Não deve importar desde que você adicione dados. Entretanto, forneça padrões adequados para eventos mais antigos / campos não obrigatórios.
Você só precisa atualizar os serviços que se preocupam com - neste caso - Gênero. Um analisador xml / json deve poder ignorar dados extras para os outros serviços. Isso depende da sua escolha de analisador e formato de dados do evento, é claro.
Não concordo com eventos que não tenham os dados relevantes. Para fornecimento de eventos, os eventos devem definir o que mudou. Ao receber um evento, outros serviços não precisam recuperar dados da origem do evento.
fonte