Associações muitos para muitos em microsserviços

13

Atualmente, tenho dois microsserviços. Vamos chamá-los Ae B.

O banco de dados no microsserviço Apossui a seguinte tabela:

A
|-- users

O banco de dados no microsserviço Bpossui a seguinte tabela:

B
|-- trackers

Os requisitos declaram que userse trackerstêm um relacionamento muitos para muitos.

Não sei como lidar adequadamente com isso em uma arquitetura de microsserviços.

Eu pude ver isso funcionando de uma de três maneiras:

  1. Uma user_trackerstabela é adicionada ao microsserviço A. Isso age de maneira semelhante a uma tabela de junção que contém "chaves estrangeiras" para userse trackers.
  2. Uma ownerstabela é adicionada ao microsserviço B. Esta tabela age de maneira semelhante a uma tabela de junção polimórfica. Isso permitiria a qualquer serviço criar uma associação com um rastreador. Isso pode ser algo como isto: B |-- trackers |-- owners |-- owner_id |-- owner_type |-- tracker_id
  3. Mantenha registros para userse trackersem cada microsserviço. Mantenha-os sincronizados com algum tipo de sistema pubsub.

Originalmente, eu iria para a opção 2 porque gostava de preservar os limites da transação. Eu posso criar um rastreador e associá-lo a algo atomicamente. No entanto, parece fora do escopo do microsserviço B. Por que o microsserviço se Bpreocupa com o fato de Aquerer criar uma associação?

Sinto que provavelmente há um bom padrão aqui do qual não estou ciente. Alguma das opções que eu expus faz sentido? Existe outra opção que pode fazer mais sentido?

anthonator
fonte

Respostas:

12

Primeiro de tudo, eu começaria com a descrição do domínio. Você não mencionou sobre o que é (eu posso adivinhar, mas seria apenas um palpite). Depois disso, tentaria decompor usando análise da cadeia de valor ou mapeamento de capacidade de negócios . E somente depois disso eu pensaria na implementação.

Considerando o seu problema, a primeira coisa que me ocorre é que você identificou seus limites de serviço incorretamente, simplesmente porque eles precisam dos dados um do outro. Você não quer acabar com monólito distribuído , não é?

A segunda coisa é que você provavelmente não trabalhou no seu domínio o suficiente. Qual conceito é representado com userstabela? É uma registered user, com todas as informações e comportamentos necessários para o registro? Tem certeza de que é o conceito certo para se comunicar trackers(seja lá o que for)? Portanto, se eu entendi direito, sua opção 2 é exatamente sobre isso: apresentar o ownerconceito muito mais próximo do seu domínio. Se realmente é assim, sou a favor da opção 2 também.

No entanto, parece fora do escopo do microsserviço B. Por que o microsserviço B deve se importar com o microsserviço A que deseja criar uma associação?

É tudo sobre limites. Eu acho que você deseja formar microsserviços em torno de entidades. Foi aí que a SOA falhou com sua arquitetura de serviço em camadas . A melhor abordagem é criar serviços que representem alguma função comercial, para que eles encapsulem dados e comportamento. Do ponto de vista mais prático, trata-se de criar serviços em torno de processos de negócios ou casos de uso. Por exemplo, você pode ter um serviço para registro do usuário. Ele contém dados e comportamento do usuário necessários para registrar um usuário. Assim, o conceito de useré formado naturalmente e pertence apenas ao serviço A. E isso me leva ao próximo ponto: a outra maneira de pensar sobre serviços é um contexto limitado . É uma boa prática alinhar serviços e contextos limitados.

Quando o usuário é registrado, o UserCreatedevento pode ser emitido. Acho que seu segundo serviço está interessado nele. Portanto, ao recebê-lo, uma entidade completamente diferente pode ser criada, por exemplo, Ownerentidade (seja lá o que for). Tenho certeza de que existem muitas colaborações interessantes entre ela e a trackerentidade - mantenha-as em um único serviço.

Seja extremamente cauteloso com a opção 3. Se você copiar dados, a funcionalidade a seguir. Isso resulta em acoplamento apertado. E não cubra com o termo CQRS , não se trata de sincronização de dados entre serviços por meio de eventos.

Zapadlo
fonte
Adoro o termo "monólito distribuído", mas a maneira como ele é definido no link que você fornece parece não estar diretamente relacionada à pergunta aqui. A maneira como acho que você o está usando está relacionada ao acoplamento entre serviços e o artigo se concentra nas dependências binárias. Acho que o jeito que você está usando é superior, mas estou lutando para encontrar uma referência que a defina claramente dessa maneira.
precisa saber é o seguinte
Eu sempre incluí serviços de bate-papo na categoria "monólito distribuído", que não é amplamente difundido, de maneira comum.
Zapadlo
6

A resposta de Zapadlo contém muitas informações e raciocínios bons. Vou adicionar aqui alguns conselhos práticos que podem facilitar o trabalho com seus problemas e com os conselhos nessa resposta.

A maneira como você estruturou sua pergunta de design é em torno das estruturas de banco de dados e como ajustar um novo requisito para suas estruturas. Isso implica que você está criando o design de serviço a partir do seu modelo de dados. Por exemplo, o que não vejo é como o relacionamento entre usuários e rastreadores deve ser acessado ou usado.

No design de serviço, a estrutura da interface é a coisa mais importante sobre o design. De fato, a implementação é quase irrelevante em comparação, principalmente no caso de microsserviços. O motivo é que, uma vez que você coloca seu serviço em prática, todas as dependências do serviço devem existir apenas na interface. Se você acertar, poderá reescrever completamente a implementação sem nenhum consumidor. E esse é o principal benefício da autonomia. Ninguém liga para como você o construiu. Eles só precisam funcionar da maneira que você comunicou.

Antes que alguém possa determinar como isso fica no banco de dados ou onde você deseja isso, você realmente precisa explicar como essas informações serão usadas. Isso é algo que será exposto por meio de um serviço ou é algum tipo de dado que você deseja embaralhar para análise?

Em uma nota lateral, eu evitaria dependências bidirecionais a quase todo custo. Se você tem dependências, realmente deseja que apenas um lado conheça o outro. Uma vez que as dependências estão em ambas as direções, seus serviços se tornam essencialmente uma unidade atômica.

JimmyJames
fonte
0

Muito disso se resume ao próprio domínio. Se um usuário com zero rastreadores não faz sentido, o serviço do usuário precisa saber sobre rastreadores. Se um rastreador precisar ter um usuário, ele precisará saber sobre os usuários. Se algo como ter um rastreador com vários proprietários ou poder transferir um rastreador de um usuário para outro faz sentido, talvez essas informações pertençam a outro serviço.

Placa
fonte
0

Pergunta: Por que seus dados são separados ao longo dos Datatables?

Eu tenderia a optar pela opção 3: os serviços são totalmente separados e podem responder às respectivas perguntas que talvez precisem responder. Além disso, eles são muito mais resistentes. Mas tenha cuidado, seus serviços poderão se desincronizar se perderem eventos, mas isso pode ser resolvido com a consistência eventual.

Além disso, você pode considerar a fusão dos dois serviços - se ambos não puderem responder sem conhecer um ao outro, eu os fundiria, pois provavelmente fazem parte de um único domínio.

Christian Sauer
fonte
Isso faz parte da religião dos microsserviços, que cada serviço precisa de total autonomia. Thomas Erl o descreve como um dos princípios de orientação ao serviço em " Princípios de Design de Serviço" c. 2008.
JimmyJames
@ JimmyJames Como alguém que escreve uma arquitetura ms: Há muito debate sobre a questão de quão grande deve ser uma ms. Nesse caso, o tamanho pode nem importar, porque os serviços podem não estar separados corretamente - por exemplo, não corte em tabelas, corte em domínios comerciais.
Christian Sauer
Certo. O problema é que há um grande culto à carga em torno de microsserviços agora. Eu vejo muitas pessoas implementando microsserviços porque é isso que as crianças legais estão fazendo e não considerando ou compreendendo as vantagens e desvantagens. Por exemplo, tenho a sensação de que muitas pessoas pensam que a autonomia do MS é sobre tecnologia e 'a nuvem'. Eu vejo isso como mais uma solução para um problema organizacional. A desreferenciação de ponteiro de negociação para E / S de rede é extremamente cara. Você não pode simplesmente aplicar isso sem pensar e esperar que as coisas corram bem.
precisa saber é o seguinte
@JimmyJames Acho que também pode ser sobre tecnologia - especialmente quando as tecnologias certian são adequadas para alguns domínios, mas não para outros. Usamos C # e Python para nossos MSs. Parte disso é devido a problemas organizacionais ("programei o c # por 20 anos, não preciso aprender novos idiomas não digitados!"). - mas também devido à natureza do nosso sistema. As partes da ciência de dados são feitas melhor em python, enquanto algumas tarefas de infraestrutura e web são melhor executadas em C #.
Christian Sauer
Claro, essa é uma razão bastante válida para fazê-lo. O problema que vejo é que as pessoas vão querer dividir todos os serviços em um nó separado simplesmente porque "estamos fazendo microsserviços", mesmo que tudo seja escrito com o mesmo código na mesma plataforma e haja muitas dependências entre os serviços. Nesse caso, não há realmente muito benefício para microsserviços e você adicionou um conjunto inteiro de novos problemas.
JimmyJames