Manipulando Alterações em uma Arquitetura de Microsserviço Dirigida a Eventos


9

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?


Qual é o formato das suas mensagens ou é algo que você pode criar? Alguns formatos de mensagem permitem atributos opcionais. Dependendo da implementação do leitor, você pode adicionar atributos opcionais sem precisar atualizar todos os leitores.
Thomas Owens

Sou livre para escolher um formato para usar nas minhas mensagens. Eu acho que usar JSON é o melhor caminho a percorrer. É importante que esses diferentes serviços sejam criados em diferentes idiomas. É por isso que um formato geral como XML ou JSON é necessário.
precisa saber é o seguinte

Respostas:


1

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.


Isso não aumentaria drasticamente o tráfego entre serviços? Usando o exemplo da pergunta, um UserRegisteredevento, 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.
Thomas Owens

@ThomasOwens Enviar dados com o evento significa que se eu tiver N observadores, envio N mensagens. Enviar o evento sozinho significa que eu envio 3N mensagens, apenas 1 das quais possui o pacote de dados. Isso é muito bom mesmo em uma rede. A única desvantagem significativa é que triplica o seu atraso. Não estou dizendo que você não pode encontrar uma solução mais ideal para uma situação específica. Estou demonstrando que os sistemas de eventos e as versões de dados não precisam ser acoplados.
Candied_orange 21/09

11
A idéia geral desse barramento de eventos é dissociar os diferentes serviços. Usando um middleware, podemos garantir que esses serviços não se conheçam e possam existir e se comunicar sem saber a existência um do outro. Se removermos o estado desses eventos e permitirmos que os serviços se conectem diretamente, estaremos acoplando esses serviços. Dessa forma, nunca podemos reimplantar um único serviço sem ter que redistribuir o resto
CGeense

11
O ponto aqui é que sistema de eventos ou você não precisa de dados extensíveis. JSON ou XML fazem isso bem se você não alterar os nomes ou estruturas que foram estabelecidas anteriormente. Eu fiz o mesmo com coleções. O sistema de eventos não deve se importar com os sexos. Se estiver enviando dados, deve apenas transmiti-los e algo do outro lado se preocupará com os sexos ou não.
Candied_orange 21/09/16

1

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.


0

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.


-1

@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.


O que quero dizer é que ele precisa lidar com todos os tipos de mudanças. Pense em um serviço que transmite um evento. E esse evento contém uma propriedade obsoleta e deve ser removida. Mesmo se esses outros serviços não estiverem usando a propriedade, eles serão interrompidos simplesmente porque eles a esperam. Então, li este artigo no martinfowler.com sobre contratos direcionados ao consumidor: martinfowler.com/articles/consumerDrivenContracts.html Ao aplicar esse princípio. Cada provedor (evento) sabe o que é esperado dele. com essa informação, ele pode validar se interromper algum consumidor.
CGeense 26/09/16
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.