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 uma P(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:
- O benefício organizacional de que eles podem ser desenvolvidos e implantados independentemente por equipes separadas (o que, por sua vez, exige que os serviços ofereçam uma interface estável).
- O benefício operacional que cada microsserviço pode ser dimensionado independentemente .
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:
- que uma certa escala é necessária e essa arquitetura é a abordagem mais econômica para obter essa escalabilidade, levando em consideração o maior esforço de desenvolvimento para essa configuração e soluções alternativas; e
- que seus requisitos comerciais permitam relaxar as garantias relevantes do ACID, sem levar a vários problemas, como os discutidos acima.
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.