Qual é a maneira correta de sincronizar dados entre microsserviços?

18

Eu sou relativamente novo na arquitetura de microsserviços. Temos um aplicativo da Web de tamanho médio e estou avaliando os prós e os contras de dividi-lo em microsserviços, em vez de em um sistema monolítico que agora avançamos.

Pelo que entendi, considere microsserviços Ae Bcada um deles depende de um subconjunto de dados que o outro possui. Se uma mensagem for postada Adizendo que algo mudou, você Bpode consumi-la e replicar uma cópia local das Ainformações de e usá-la para fazer o que for Bnecessário.

No entanto, o que se Bcai / falha e depois de um tempo, volta a aparecer novamente. Durante esse tempo de inatividade, Apublicou mais duas mensagens. Como Bsaber como atualizar sua cópia local das Ainformações de?

É verdade que, se Bé o único consumidor da Afila, ele pode começar a lê-lo quando voltar a ficar on-line, mas e se houver outros consumidores dessa fila e essas mensagens forem consumidas?

Como um exemplo mais concreto, se um Usersserviço tiver seu endereço de email atualizado enquanto um Billingmicrosserviço estiver inativo, se o Billingmicrosserviço voltar a funcionar novamente, como saberá que o email foi atualizado?

Quando os microsserviços retornam, ele faz uma transmissão dizendo "Ei, estou de volta, me dê todas as suas informações atuais?"

Em geral, quais seriam as melhores práticas do setor para sincronização de dados?

noblerare
fonte
1
Para evitá-lo sempre que possível.
Telastyn
1
Por que Ordersprecisa saber alguma coisa Users?
Kdgregory
É apenas um exemplo. Substitua os dois pelo que você quiser que faça sentido.
noblerare
um roteamento de fan-out resolverá seu problema de 'mensagem é consumida por outra pessoa'. mas não está realmente claro o que você está tentando alcançar.
Ewan
@ Ewan Atualizei meu post original para explicar melhor o que estou tentando perguntar.
noblerare

Respostas:

6

Depois de fazer um pouco mais de pesquisa, deparei-me com este artigo, do qual retirei algumas citações que considero úteis para o que quero realizar (e para futuros leitores). Isso oferece uma maneira de adotar um modelo de programação reativa sobre um modelo de programação imperativo.

Origem do evento

A idéia aqui é representar a transição de estado de cada aplicativo na forma de um evento imutável. Os eventos são armazenados em um formato de log ou diário à medida que ocorrem (também chamados de 'armazenamento de eventos'). Eles também podem ser consultados e armazenados indefinidamente, com o objetivo de representar como o estado do aplicativo, como um todo, evoluiu ao longo do tempo.

O que isso ajuda a realizar é que, se um microsserviço ficar inativo, ainda que outros eventos pertinentes a ele estejam sendo publicados e os eventos sejam consumidos por, digamos, outras instâncias desse microsserviço, quando o microsserviço voltar, ele poderá se referir a ele event storepara recuperar todos os eventos que perdeu durante o período em que caiu.

Apache Kafka como Agente de Eventos

Considere o uso do Apache Kafka, que pode armazenar e despachar milhares de eventos por segundo e possui mecanismos internos de replicação e tolerância a falhas. Possui um armazenamento persistente de eventos que podem ser armazenados no disco indefinidamente e consumidos a qualquer momento (mas não removidos) do Tópico (fila de fantasia de Kafka) em que foram entregues.

Os eventos são, então, atribuídos deslocamentos que os identificam univocamente no Tópico - Kafka pode gerenciar os deslocamentos, fornecendo facilmente semântica de entrega “no máximo uma vez” ou “pelo menos uma vez”, mas também pode ser negociada quando um consumidor de evento ingressa em um Tópico , permitindo que os microsserviços comecem a consumir eventos a partir de qualquer local arbitrário no tempo - geralmente de onde o consumidor parou. Se o último deslocamento de evento consumido for mantido transacionalmente no armazenamento local dos serviços quando os casos forem 'concluídos com êxito', esse deslocamento poderá ser facilmente usado para obter uma semântica de entrega de evento “exatamente uma vez”.

De fato, quando os consumidores se identificam com a Kafka, a Kafka registra quais mensagens foram entregues a cada consumidor para que não sejam atendidas novamente.

Sagas

Para casos de uso mais complexos em que a comunicação entre diferentes serviços é realmente necessária, a responsabilidade de finalizar o processo deve ser bem reconhecida - o processo é descentralizado e termina quando todos os serviços envolvidos reconhecem sua tarefa como concluída com êxito, caso contrário, todo o processo deve falhar e medidas corretivas devem ser acionadas para reverter qualquer estado local inválido.

É quando a saga entra em cena. Uma saga é uma sequência de transações locais. Cada transação local atualiza o banco de dados e publica uma mensagem ou evento para acionar a próxima transação local na saga. Se uma transação local falhar porque viola uma regra de negócios, a saga executa uma série de transações compensatórias que desfazem as alterações feitas pelas transações locais anteriores. Leia isto para mais informações.

noblerare
fonte
Ainda não entendo por que você deseja construir uma estrutura tão complicada. Geralmente é muito mais fácil se cada serviço apenas mantém seus próprios dados e os fornece a outros serviços mediante solicitação.
J. Fabian Meier
^ Mas isso reduzirá a disponibilidade do sistema. A estrutura complicada pode ser garantida se for necessária alta resiliência.
Avmohan #
4

Eu desafiaria toda a sua idéia de "enviar os dados para todos os outros microsserviços".

Normalmente, se um serviço de cobrança precisar de um endereço de email, ele apenas solicitará o endereço do cliente específico. Ele não precisa manter uma cópia de todos os dados do endereço nem será informado se houver alguma alteração. Apenas pede e obtém a resposta dos dados mais recentes.

J. Fabian Meier
fonte
Eu acho que essa resposta está exatamente correta. Isso elimina muitos problemas relacionados à sincronização. Na verdade, estou analisando agora o código que apresenta esses problemas, porque diferentes serviços mantêm cópias das informações e apresentam problemas de sincronização.
DaveG
2
Obrigado pela sua resposta. Então, por que, então, é necessário um modelo de pub / sub e filas de mensagens? Se estamos tentando "extrair" em vez de "enviar" dados, estamos preocupados com a latência do serviço.
noblerare
AFAIK, seu serviço não precisa reagir imediatamente se algo mudar (como em um pub / sub), mas ocasionalmente precisa de dados. Então eu apenas puxaria. Se você se preocupa com a latência, pode armazenar em cache os dados, mas novamente isso custa o custo de não saber se os dados estão atualizados. Se seus arquivos forem grandes, você também poderá perguntar se algo muda antes de extrair algo novamente.
J. Fabian Meier
Lembre-se de que esta solução tem um custo de acoplamento rígido do serviço dependente, o que significa que o endereço de email ficará indisponível quando o serviço do usuário não estiver disponível. Uma das idéias iniciais de interromper os serviços para começar, para que sejam implantáveis, escalonáveis, etc. Se todos os serviços se comunicarem diretamente sem um cache ou uma garantia de alta disponibilidade, quando um sistema estiver inativo, todos eles descer.
Duquehrash 02/12/19
@dukethrash Em seguida, torne-os altamente disponíveis.
J. Fabian Meier
0

É possível substituir uma fila de eventos normal por um modelo de publicador / assinante, em que o Aserviço publica uma nova mensagem do tópico T e o Btipo de microsserviços se inscreveria no mesmo tópico.

Idealmente, Bseria um serviço sem estado e utilizaria um serviço de persistência desanexado, de modo que uma Binstância de serviço com falha fosse substituída por gerar uma ou mais Binstâncias de serviço para continuar seu trabalho, lendo no mesmo serviço de persistência compartilhado.

A.Rashad
fonte