Ultimamente, tenho lido sobre o fornecimento de eventos e realmente gosto das idéias por trás dele, mas estou com o seguinte problema.
Digamos que você tenha N processos simultâneos que recebem comandos (por exemplo, servidores web), geram eventos como resultado e os armazenam em um armazenamento centralizado. Vamos supor também que todo o estado transitório do aplicativo seja mantido na memória dos processos individuais, aplicando sequencialmente eventos do armazenamento.
Agora, digamos que temos a seguinte regra de negócios: cada usuário distinto deve ter um nome de usuário exclusivo.
Se dois processos recebem um comando de registro de usuário para o mesmo nome de usuário X, ambos verificam se X não está na lista de nomes de usuários, a regra é validada para ambos os processos e ambos armazenam um evento "novo usuário com nome de usuário X" na loja .
Agora entramos em um estado global inconsistente porque a regra de negócios é violada (há dois usuários distintos com o mesmo nome de usuário).
Em um sistema tradicional de estilo N servidor <-> 1 RDBMS, o banco de dados é usado como um ponto central de sincronização, o que ajuda a evitar essas inconsistências.
Minha pergunta é: como os sistemas de origem de eventos normalmente abordam esse problema? Eles simplesmente processam todos os comandos sequencialmente (por exemplo, limitam a quantidade de processos que podem ser gravados na loja para 1)?
fonte
Respostas:
Nos sistemas de origem de eventos, o "armazenamento de eventos" desempenha a mesma função. Para um objeto de origem de evento, sua gravação é um acréscimo de seus novos eventos a uma versão específica do fluxo de eventos. Portanto, assim como na programação simultânea, você pode adquirir um bloqueio nesse histórico ao processar o comando. É mais comum que os sistemas de origem de eventos adotem uma abordagem mais otimista - carregue o histórico anterior, calcule o novo histórico e compare-e-troque. Se algum outro comando também tiver sido gravado nesse fluxo, sua comparação e troca falharão. A partir daí, você reexecuta seu comando ou abandona seu comando, ou talvez mescla seus resultados ao histórico.
A contenção se torna um grande problema se todos os N servidores com seus comandos M estiverem tentando gravar em um único fluxo. A resposta usual aqui é alocar um histórico para cada entidade originada por evento em seu modelo. Portanto, o usuário (Bob) teria um histórico distinto do usuário (Alice) e as gravações em um não bloquearão as gravações no outro.
Greg Young na validação de conjunto
Existe uma maneira elegante de verificar restrições exclusivas nos atributos do objeto de domínio sem mover a lógica de negócios para a camada de serviço?
Resposta curta, em muitos casos, investigar mais profundamente esse requisito revela que (a) é um proxy pouco compreendido para outro requisito, ou (b) que violações da "regra" são aceitáveis se puderem ser detectadas (relatório de exceção) , mitigados dentro de uma janela de tempo ou com baixa frequência (por exemplo: os clientes podem verificar se um nome está disponível antes de enviar um comando para usá-lo).
Em alguns casos, onde seu armazenamento de eventos é bom na validação de conjunto (ou seja: um banco de dados relacional), você implementa o requisito gravando em uma tabela de "nomes exclusivos" na mesma transação que persiste nos eventos.
Em alguns casos, você só pode impor o requisito publicando todos os nomes de usuário no mesmo fluxo (o que permite avaliar o conjunto de nomes na memória, como parte do seu modelo de domínio). - Nesse caso, dois processos atualizarão a tentativa de atualizar "o" histórico do fluxo, mas uma das operações de comparação e troca falhará e a nova tentativa desse comando poderá detectar o conflito.
fonte
Parece que você pode implementar um processo de negócios (
saga
no contexto deDomain Driven Design
) para o registro do usuário em que o usuário é tratado como aCRDT
.Recursos
https://doc.akka.io/docs/akka/current/distributed-data.html http://archive.is/t0QIx
"CRDTs com dados distribuídos da Akka" https://www.slideshare.net/markusjura/crdts-with-akka-distributed-data para obter informações sobre
CmRDT
s - CRDTs baseados em operaçãoCvRDT
s - CRTDs baseados no estadoExemplos de código no Scala https://github.com/akka/akka-samples/tree/master/akka-sample-distributed-data-scala . Talvez o "carrinho de compras" seja o mais adequado.
fonte