Minha equipe está migrando de um aplicativo ASP.NET monolítico para o .NET Core e o Kubernetes. As alterações de código parecem estar indo tão bem quanto o esperado, mas onde minha equipe está encontrando muita discórdia é em torno do banco de dados.
Atualmente, temos um banco de dados do SQL Server bastante grande que abriga todos os dados de toda a empresa. Estou propondo que dividamos o banco de dados de maneira semelhante à divisão do código - dados de catálogo em um banco de dados (lógico), dados de inventário em outro, pedidos em outro, etc. - e cada microsserviço seria o guardião do seu banco de dados .
A implicação aqui é que as chaves estrangeiras que cruzam os limites dos microsserviços precisam ser removidas e os sprocs e visualizações que atingem os limites seriam proibidos. Todos os modelos de dados podem ou não residir no mesmo banco de dados físico, mas, mesmo que existam, não devem interagir diretamente entre si. Os pedidos ainda podem fazer referência aos itens do catálogo por ID, mas a integridade dos dados não seria rigorosamente aplicada no nível do banco de dados e esses dados deverão ser unidos no código, e não no SQL.
Eu vejo a perda dessas como compensações necessárias na mudança para o microsserviço e na obtenção dos benefícios de escalabilidade que acompanham. Enquanto escolhermos nossas costuras com sabedoria e desenvolvermos em torno delas, tudo ficará bem. Outros membros da equipe afirmam que tudo deve permanecer no mesmo banco de dados monolítico para que tudo possa ser ACID e ter integridade referencial preservada em todos os lugares.
Isso me leva à minha pergunta. Primeiro, a minha posição sobre restrições de chave estrangeira e a adesão é plausível? Em caso afirmativo, alguém conhece algum material de leitura confiável que eu possa oferecer aos meus colegas? A posição deles é quase religiosa e eles não parecem ser influenciados por nada menos que o próprio Martin Fowler dizendo que eles estão errados.
fonte
Respostas:
Não há uma solução clara, porque isso depende inteiramente do seu contexto - em particular, ao longo de quais dimensões seu sistema deve escalar e quais são seus problemas reais. O banco de dados é realmente o seu gargalo?
Essa resposta (infelizmente bastante longa) será um pouco parecida com “microsserviços ruins, monólitos para toda a vida!”, Mas essa não é minha intenção. O que quero dizer é que os microsserviços e os bancos de dados distribuídos podem resolver vários problemas, mas não sem ter alguns problemas próprios. Para apresentar um argumento forte para sua arquitetura, você deve mostrar que esses problemas não se aplicam, podem ser mitigados e que essa arquitetura é a melhor escolha para suas necessidades de negócios.
Dados distribuídos são difíceis.
A mesma flexibilidade que permite uma melhor escala é o outro lado das garantias mais fracas. Notavelmente, os sistemas distribuídos são muito mais difíceis de raciocinar.
Atualizações atômicas, transações, consistência / integridade referencial e durabilidade são extremamente valiosas e não devem ser dispensadas precipitadamente. Há pouco sentido em ter dados se estiverem incompletos, desatualizados ou totalmente errados. Quando você tem o ACID como um requisito comercial, mas está usando a tecnologia de banco de dados que não pode oferecê-lo imediatamente (por exemplo, muitos bancos de dados NoSQL ou uma arquitetura DB por microsserviço), seu aplicativo deve preencher a lacuna e fornecer essas garantias.
Isso não é impossível, mas complicado de acertar. Muito complicado. Especialmente em um ambiente distribuído, onde há vários gravadores para cada banco de dados. Essa dificuldade se traduz em uma grande chance de erros, possivelmente incluindo dados descartados, dados inconsistentes e assim por diante.
Por exemplo, considere ler as análises Jepsen de sistemas de banco de dados distribuídos conhecidos , talvez começando com a análise de Cassandra . Não entendo metade dessa análise, mas o TL; DR é que os sistemas distribuídos são tão difíceis que até mesmo os projetos líderes do setor às vezes os entendem errado, de maneiras que podem parecer óbvias em retrospectiva.
Os sistemas distribuídos também implicam um maior esforço de desenvolvimento. Até certo ponto, há uma troca direta entre custos de desenvolvimento ou queda de dinheiro em hardware mais robusto.
Exemplo: referências pendentes
Na prática, você não deve considerar a ciência da computação, mas os requisitos da sua empresa para ver se e como o ACID pode ser relaxado. Por exemplo, muitos relacionamentos de chave estrangeira podem não ser tão importantes quanto parecem. Considere um relacionamento de categoria de produto n: m. Em um RDBMS, podemos usar uma restrição de chave estrangeira para que apenas produtos e categorias existentes possam fazer parte desse relacionamento. O que acontece se introduzirmos serviços separados de produtos e categorias, e um produto ou categoria for excluído?
Nesse caso, isso pode não ser um grande problema e podemos escrever nosso aplicativo para filtrar quaisquer produtos ou categorias que não existem mais. Mas existem vantagens e desvantagens!
Observe que isso pode exigir um nível de aplicativo
JOIN
em vários bancos de dados / microsserviços, o que apenas move o processamento do servidor de banco de dados para seu aplicativo. Isso aumenta a carga total e precisa mover dados extras pela rede.Isso pode mexer com paginação. Por exemplo, você solicita os próximos 25 produtos de uma categoria e filtra produtos indisponíveis dessa resposta. Agora, seu aplicativo exibe 23 produtos. Em teoria, uma página com zero produtos também seria possível!
Ocasionalmente, você desejará executar um script que limpe as referências pendentes, após cada alteração relevante ou em intervalos regulares. Observe que esses scripts são bastante caros porque precisam solicitar todos os produtos / categorias do banco de dados / microsserviço de backup para verificar se ele ainda existe.
Isso deve ser óbvio, mas para maior clareza: não reutilize IDs. As IDs no estilo de incremento automático podem ou não ser boas. GUIDs ou hashes oferecem mais flexibilidade, por exemplo, ao atribuir um ID antes que o item seja inserido em um banco de dados.
Exemplo: pedidos simultâneos
Agora, considere um relacionamento de pedido de produto. O que acontece com um pedido se um produto for excluído ou alterado? Ok, podemos simplesmente copiar os dados relevantes do produto na entrada do pedido para mantê-los disponíveis - trocando espaço em disco pela simplicidade. Mas e se o preço do produto mudar ou o produto ficar indisponível pouco antes de um pedido para esse produto ser feito? Em um sistema distribuído, os efeitos levam tempo para se propagar e o pedido provavelmente será executado com dados desatualizados.
Novamente, como abordar isso depende dos requisitos de negócios. Talvez o pedido desatualizado seja aceitável e, posteriormente, você poderá cancelar o pedido se não puder ser atendido.
Mas talvez isso não seja uma opção, por exemplo, para configurações altamente simultâneas. Considere 3.000 pessoas correndo para comprar ingressos para shows nos primeiros 10 segundos e vamos assumir que uma alteração na disponibilidade exigirá 10ms para se propagar. Qual é a probabilidade de vender o último ingresso para várias pessoas? Depende de como essas colisões são tratadas, mas, usando uma distribuição Poisson,
λ = 3000 / (10s / 10ms) = 3
temos umaP(k > 1) = 1 - P(k = 0) - P(k = 1) = 80%
chance de colisão por intervalo de 10ms. Se a venda e o cancelamento posterior da maioria de seus pedidos são possíveis sem cometer fraudes, isso pode levar a uma conversa interessante com seu departamento jurídico.Pragmatismo significa escolher as melhores características.
A boa notícia é que você não precisa mudar para um modelo de banco de dados distribuído, se isso não for necessário. Ninguém revogará a sua associação ao Microservice Club se você não fizer microsserviços “adequadamente”, porque não existe esse clube - e não existe uma maneira verdadeira de criar microsserviços.
O pragmatismo vence sempre, então misture e combine várias abordagens à medida que resolvem seu problema. Isso pode até significar microsserviços com um banco de dados centralizado. Realmente, não passe pelo sofrimento dos bancos de dados distribuídos se não precisar.
Você pode escalar sem microsserviços.
Os microsserviços têm dois benefícios principais:
Se o dimensionamento independente não for necessário, os microsserviços serão muito menos atraentes.
Um servidor de banco de dados já é um tipo de serviço que você pode escalar (um pouco) de forma independente, por exemplo, adicionando réplicas de leitura. Você mencionou procedimentos armazenados. Reduzi-los pode ter um efeito tão grande que qualquer outra discussão sobre escalabilidade é discutível.
E é perfeitamente possível ter um monólito escalável que inclua todos os serviços como bibliotecas. Você pode escalar iniciando mais instâncias do monólito, o que naturalmente exige que cada instância seja sem estado.
Isso tende a funcionar bem até que o monólito seja muito grande para ser razoavelmente implantado ou se alguns serviços tiverem requisitos de recursos especiais para que você possa escalá-los independentemente. Os domínios com problemas que envolvem recursos extras podem não envolver um modelo de dados separado.
Você tem um caso de negócios forte?
Você está ciente das necessidades comerciais da sua organização e, portanto, pode criar um argumento para uma arquitetura de banco de dados por microsserviço, com base em uma análise:
Por outro lado, se você não conseguir demonstrar isso, principalmente se o design atual do banco de dados puder suportar uma escala suficiente no futuro (como seus colegas parecem acreditar), também terá sua resposta.
Há também um grande componente YAGNI na escalabilidade. Diante da incerteza, é uma decisão comercial estratégica de construir agora a escalabilidade (custos totais menores, mas envolve custos de oportunidade e pode não ser necessário) versus adiar algum trabalho de escalabilidade (custos totais mais altos, se necessário, mas você tem uma melhor idéia da escala real). Esta não é principalmente uma decisão técnica.
fonte
Eu acredito que ambas as abordagens são plausíveis. Você pode optar por obter escalabilidade sacrificando os benefícios dos bancos de dados ACID e monolíticos, além de manter a arquitetura atual e sacrificar a escalabilidade e agilidade de uma arquitetura mais distribuída. A decisão certa virá do atual modelo de negócios e da estratégia para os próximos anos. Puramente, do ponto de vista da tecnologia, existem dificuldades em mantê-lo monolítico e em mudar para uma abordagem mais distribuída. Eu analisaria o sistema e veria quais aplicativos / módulos / processos de negócios são mais críticos para escalar e avaliar os riscos, custos e benefícios para decidir os que devem esperar ou continuar na arquitetura monolítica.
fonte
Sua postura é plausível e correta.
Como convencer tingidos nos viciados em lã db é outra questão. Eu diria que você tem duas opções.
Encontre um exemplo concreto em que o banco de dados atingiu seus limites. Você tem 'tabelas de arquivamento', por exemplo? Por que está tudo bem? Qual é o número máximo de pedidos por segundo que você pode receber? etc. Mostre que o banco de dados não atende aos requisitos e sua solução os corrige.
Contrate empreiteiros caros para lhe oferecer a melhor solução. Por serem despesas e ter blogs, todos acreditarão neles
fonte