Microsserviços sem duplicação de dados


19

Estou achando difícil evitar a duplicação de dados ou um banco de dados compartilhado, mesmo para o design mais simples de microsserviços, o que me faz pensar que estou perdendo alguma coisa. Aqui está um exemplo básico do problema que estou enfrentando. Supondo que alguém esteja usando um aplicativo da Web para gerenciar um inventário, eles precisariam de dois serviços; uma para o inventário que gerencia os itens e a quantidade em estoque e um serviço de usuários que gerenciaria os dados dos usuários. Se desejarmos uma auditoria de quem estocou o banco de dados, podemos adicionar o ID do usuário ao banco de dados do serviço de inventário como o último estoque por valor.

Usando o aplicativo, podemos ver todos os itens que estão acabando e uma lista de quem os estocou da última vez, para que possamos pedir que eles os reponham novamente. Usando a arquitetura descrita acima, uma solicitação seria feita ao serviço de inventário para recuperar os detalhes do item de todos os itens em que a quantidade é menor que 5. Isso retornaria uma lista incluindo os IDs do usuário. Em seguida, uma solicitação separada seria feita ao serviço do usuário para obter o nome do usuário e os detalhes de contato da lista de IDs do usuário obtidos no serviço de inventário.

Isso parece muito ineficiente e não são necessários muitos serviços antes de fazermos várias solicitações para diferentes APIs de serviços, que, por sua vez, fazem várias consultas ao banco de dados. Uma alternativa é replicar os detalhes dos usuários nos dados do inventário. Quando um usuário altera seus detalhes de contato, precisamos replicar a alteração através de todos os outros serviços. Mas isso não parece se encaixar na idéia de contexto limitado dos microsserviços. Também poderíamos usar um único banco de dados e compartilhá-lo entre diferentes serviços e ter todos os problemas de um banco de dados de integração .

Qual é a melhor / correta maneira de implementar isso?


5
Bem-vindo ao paradoxo dos microsserviços. Aquilo que parece tornar as coisas mais simples pode realmente tornar as coisas mais complexas.
Robert Harvey

A maneira "correta" é a mesma de sempre: descubra uma maneira de fazer as coisas que melhor se adequam aos seus objetivos específicos.
Robert Harvey

1
@RobertHarvey Esse é sempre o caso, mas estou tentando entender a maneira dos microsserviços de livros didáticos. Depois que eu entender como deve funcionar em um mundo ideal, eu o mudarei feliz para se adequar ao meu caso de uso.
Geraint Anderson

1
Mas você está estruturando sua pergunta em termos de eficiência, que é um requisito de software não funcional. A maneira de resolver o problema de eficiência é perguntando diretamente ao banco de dados.
Robert Harvey

1
Eu estava prestes a escrever uma pergunta exatamente como a sua. Ainda não vejo vantagens no MSA para aplicativos Web razoavelmente simples. Eu acho que em muitos casos a modularidade poderia ser alcançada sem tornar as coisas tão complexas.
Glasnhost 26/10/19

Respostas:


10

Eu perdi completamente onde você está sendo obrigado a duplicar.

Um princípio central dos microsserviços é que o serviço seja a única autoridade. Isso significa que o gerenciamento de inventário e usuário pode ser completamente separado. Eu projetaria o gerenciamento de usuários para que ele nem soubesse que o sistema de inventário existe.

Mas eu projetaria o sistema de inventário para que ele nunca armazene nada sobre usuários além de um ID do usuário. Isso cuida do seu problema de propagar alterações nas informações do usuário.

Quanto às coisas que precisam de informações de inventário e de usuário, como registros, auditorias e impressões, elas não são atualizadas à medida que as informações são alteradas. Eles são um registro do que era. Novamente, você não propaga mudanças.

Portanto, em todos os casos, quando você quiser as informações mais recentes do usuário, solicite o serviço de informações do usuário.


@Geraint: Você pode ser mais específico sobre que tipo de duplicação está ocorrendo no seu sistema?
Robert Harvey

1
Obrigado. A duplicação se refere à cópia dos detalhes de contato dos usuários para o serviço de inventário, mas você o abordou (isto é, não é necessário). Parece contra-intuitivo mudar de um único banco de dados relacional onde eu poderia obter os dados do inventário e os dados do usuário com uma associação para fazer duas chamadas API distintas, nas quais a segunda não pode começar até que a primeira retorne os resultados. Mas acho que isso faz parte da avaliação sobre se eu uso microsserviços ou outra coisa.
Geraint Anderson

É o mesmo truque que o banco de dados usaria se gerenciasse ambos. Você não copia informações do usuário na tabela de inventário. Você fornece uma chave estrangeira. O ID do usuário está fazendo o mesmo trabalho nos serviços. Basta torná-lo único.
2191818

It seems counter-intuitive to move from a single relational database where I could get the inventory data and the user data with a joinLembre-se de que "idealmente" há uma loja por serviço (ou mais!). Portanto, não há nada como "junção" entre "limites". O motivo é simples: o DB gera acoplamento entre os serviços. Ao contrário da sugestão do @CandiedOrange, acho que podemos duplicar um mínimo de dados de um serviço para outro. Estou me referindo a dados que provavelmente não serão alterados. Se este dups melhora a eficiência e performance (e ambos são obrigatórios) os "prós" provavelmente off-set os "contras"
LAIV

@GeraintAnderson Quero dizer, se você precisar de eficiência (que é por definição um requisito não-funcional), existem maneiras de fazer isso. Ou seja, solicite páginas de dados do Serviço de Inventário (como 10 elementos), pegue cada página e use essa página para solicitar dados do Serviço do Usuário e agregue no final. Dessa forma, você mantém seus limites enquanto aproveita o paralelismo de serviços independentes. Mesmo assim, não se preocupe até identificá-lo como um gargalo real do aplicativo que deve ser resolvido - esperar um segundo extra de 1/2 segundo em um trabalho noturno de 1 segundo não importa para ninguém.
Delioth 8/01/19

11

Estou achando difícil evitar a duplicação de dados ....

De acordo com o e- book da Microsoft sobre arquitetura de microsserviço , não há nada errado com a duplicação de dados. Basicamente, a duplicação de dados aumenta a dissociação entre os serviços e, portanto, fortalece suas funções como uma única autoridade. Uma passagem relevante:

E finalmente (e é aí que a maioria dos problemas surge ao criar microsserviços), se o microsserviço inicial precisar de dados que pertencem originalmente a outros microsserviços, não confie em fazer solicitações síncronas para esses dados. Em vez disso, replique ou propague esses dados (apenas os atributos necessários) para o banco de dados do serviço inicial usando consistência eventual (geralmente usando eventos de integração ...


1
Eu discordo completamente. Isso dificulta a manutenção. Faz você implementar transações entre microsserviços quando algo precisa ser adicionado, atualizado ou removido. Caso deseje evitar um único ponto de falha, você pode usar request ou qualquer outro tipo de cache.
Alan Sereb 20/09/19

1
@AlanSereb É mais difícil de manter, mas o ponto é que às vezes você não tem outra escolha. Por exemplo, e se você precisar fazer um FK entre objetos que vivem em dois bancos de dados? A única maneira de garantir consistência ao fazer consultas em um banco de dados local é ter uma replicação de dados. Dê uma olhada em: stackoverflow.com/a/4452586/2255491
David D.

Concordo. Outra ótima abordagem é seguir a rota de fornecimento de eventos. E que todas as mutações sejam executadas através do pipeline de eventos #
Alan Sereb 27/10/19

4

uma solicitação seria feita ao serviço de inventário para recuperar os detalhes do item de todos os itens em que a quantidade é menor que 5. Isso retornaria uma lista incluindo os IDs do usuário. Em seguida, uma solicitação separada seria feita ao serviço do usuário para obter o nome do usuário e os detalhes de contato da lista de IDs do usuário obtidos no serviço de inventário.

De fato sim.

É verdade que, em um monólito, você pode ter um modelo de inventário que consulta os itens relevantes, alimentá-lo em um modelo de usuário e obter os mesmos dados.

Ou você pode ir além, se você os tiver no mesmo banco de dados relacional e escrever SQL que o banco de dados tomará a tabela de inventário e a tabela de usuários, isso faz alguma mágica e você obtém os dados que procura.

Independentemente de como você o faça, em algum lugar haverá um código que buscará essencialmente uma lista de IDs de usuário do sistema de inventário, as alimentará no sistema do usuário e compilará uma lista de dados.

A pergunta que você precisa responder é sobre desempenho e manutenção e outras qualidades "suaves".

O principal benefício dos microsserviços é o dimensionamento. Se você tiver dez mil usuários em uma máquina e for um pouco lento, poderá adicionar outra máquina e o sistema se tornará duas vezes mais rápido. Adicione mais oito e é dez vezes mais rápido. (Escala linear é provavelmente otimista, mas é o ideal e não que razoável esperança para.)

E isso é por serviço . Se o sistema de inventário é o gargalo, ele é usado para mais do que relatórios sobre usuários, você pode adicionar mais máquinas apenas a esse serviço . As máquinas também podem ser especializadas; esse serviço precisa de muita memória, esse serviço faz cálculos pesados ​​e precisa de mais CPU.

Se você não precisar do dimensionamento, há outro benefício dos microsserviços: eles são modulares . É claro que aplicativos monolíticos também podem ser modulares, e você tem um banco de dados normalizado e ... mas, na prática, as paredes entre os módulos são como paredes de vidro no melhor caso, e as linhas na areia no pior. Os microsserviços são separados por aço sólido.

Se o sistema do usuário pegar fogo literalmente, isso não afetará nem um pouco o sistema de inventário. Você não poderá imprimir relatórios bonitos sobre quem estocou o quê, mas os clientes poderão fazer pedidos com segurança, sabendo que os itens estocados estão lá.

E você não duplica dados em microsserviços , assim como em um banco de dados relacional (*). Em um banco de dados relacional, você pode fazer uma junção e o equivalente é mesclar as listas no código como descrito.

Você também pode adicionar uma visualização , o equivalente é adicionar um novo serviço que faz a mesclagem para você; isso resultaria em três solicitações; um para o novo serviço e, em seguida, esse serviço executa os dois originais. Os bancos de dados relacionais têm coisas sofisticadas que otimizam as visualizações, que precisam ser implementadas no nível de serviço. Você não o obtém "de graça".

O armazenamento em cache é diferente da duplicação de dados, pois se dois valores não correspondem, você sabe qual deles está errado. É frequentemente usado em microsserviços para aumentar a disponibilidade à custa da consistência (teorema da CAP). Como os bancos de dados relacionais abatem completamente a disponibilidade no altar de consistência, é menos comum neles. Eu diria que não há nada inerente nos microsserviços que facilite o armazenamento em cache, mas, na prática, o cache é uma preocupação principal e que facilita o armazenamento em cache nos microsserviços .

(*) Se fizer sentido duplicar dados em um enxame de microsserviços, provavelmente faria sentido no banco de dados relacional equivalente a.


3
Gostei muito da sua resposta até a parte "não duplique dados em microsserviços". Eu acho que há casos em que a duplicação de dados é a abordagem correta. Melhora a tolerância a falhas e a autonomia. Se o serviço do usuário cair, o serviço de inventário ainda poderá exibir uma lista de estoque baixo com quem os estocou por último.
Peter Pompeii

1
@peterpompeii Eu chamaria isso de cache, não duplicação de dados. A duplicação de dados ocorre quando você tem dois locais para atualizar para um dado, armazenando em cache quando há um local e propagação automática para os outros locais. Também eu disse mais do que relacional. Se faz sentido em um banco de dados relacional duplicar dados, faz sentido em um microsserviço. Acho que concordamos e essa parte poderia ser mais clara, mas eu só tenho um telefone no momento e não atualizo o texto no momento.
Odalrick 18/02/19

@PeterPompeii Espero que a seção adicionada sobre cache resolva algumas de suas preocupações.
Odalrick 6/03/19

1
@ Odalrick, o que você descreveu, soa como replicação de dados. Replicação e caching são ambas formas de duplicação de dados. A replicação ocorre quando uma cópia é garantida para sempre ter todos os dados necessários. O cache está sob demanda. O cache pode ter uma falha. O cache da disponibilidade não faz tanto sentido quanto o cache do desempenho. TL; DR, se você estiver armazenando uma cópia completa de algo com consistência suficiente, garante que você nunca precise verificar erros, então não é um cache.
Brandon

1
@Brandon Outra diferença entre replicação e armazenamento em cache é como você sabe quais dados estão errados quando há uma diferença. A replicação define algumas regras sobre como mesclar os dados. O armazenamento em cache, por outro lado, é sempre : o cache está errado.
Odalrick
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.