Por que é tão ruim ler dados de um banco de dados "pertencente" a um microsserviço diferente

64

Recentemente, li este excelente artigo sobre a arquitetura de microsserviços: http://www.infoq.com/articles/microservices-intro

Ele afirma que, quando você carrega uma página da Web na Amazon, mais de 100 microsserviços cooperam para servir essa página.

Esse artigo descreve que toda a comunicação entre microsserviços só pode passar por uma API. Minha pergunta é por que é tão ruim dizer que todas as gravações de banco de dados só podem passar por uma API, mas você é livre para ler diretamente dos bancos de dados dos vários micro serviços. Pode-se dizer, por exemplo, que apenas algumas visualizações do banco de dados são acessíveis fora do microsserviço, para que a equipe que mantém o microsserviço saiba que, enquanto mantiverem essas visualizações intactas, poderão alterar a estrutura do banco de dados do microsserviço, tanto quanto quiserem. quer.

Estou faltando alguma coisa aqui? Existe alguma outra razão pela qual os dados devem ser lidos apenas por meio de uma API?

Desnecessário dizer que minha empresa é significativamente menor que a Amazon (e sempre será) e o número máximo de usuários que podemos ter é de cerca de 5 milhões.

David
fonte
Um fator mais geral não mencionado nas respostas é que, quando gravado no banco de dados, o cache local, mesmo o simples mapeamento de O / R, pode gerar dados obsoletos ao acessar imediatamente o banco de dados. Se você considerar ignorar a API µservice por motivos de velocidade, pode ser que alguém tenha levado a arquitetura µservice longe demais.
Joop Eggen
Ao permitir a leitura do banco de dados, todos os detalhes do banco de dados se tornam parte da API pública. Eu não gostaria de manter a compatibilidade em uma API tão complexa.
25414 Patrick Patrick
Mas, nesse caso, a visualização simplesmente não se torna parte da API, pelo menos para fins semânticos? É apenas uma questão do que você está chamando de API e o que isso força você a manter. (Geralmente, é mais fácil manter a consistência da camada acima do banco de dados.)
lc.
Concordo que a visualização seria simplesmente uma forma de uma API. Acho que a maioria das pessoas que responde a essa pergunta não lê minha ideia sobre o uso de visualizações como um nível de abstração. Entendo que manter a visão intacta, se alguém mudasse a tecnologia de banco de dados, seria um grande desafio, mas estou disposto a apostar que não precisaremos mudar nossa tecnologia de banco de dados pelos próximos cinco anos. Além disso, o desempenho não será um problema para apenas 5 usuários de usinas. Portanto, dado o nosso tamanho, agradeço por seguir essa solução, embora as respostas aqui pareçam indicar que estou indo direto para um mundo de dor.
David

Respostas:

69

Os bancos de dados não são muito bons em ocultar informações, o que é bastante plausível, porque o trabalho deles é realmente expor as informações. Mas isso os torna uma ferramenta ruim quando se trata de encapsulamento. Por que você deseja encapsulamento?

Cenário: você vincula alguns componentes diretamente a um RDBMS e vê um componente específico se tornando um gargalo de desempenho para o qual você pode querer desnormalizar o banco de dados, mas não pode, porque todos os outros componentes seriam afetados. Você pode até perceber que seria melhor ter um armazenamento de documentos ou um banco de dados de gráficos do que com um RDBMS. Se os dados forem encapsulados por uma pequena API, você terá uma chance realista de reimplementar a referida API da maneira que precisar. Você pode inserir transparentemente camadas de cache e outras coisas.

Atrapalhar-se com a camada de armazenamento diretamente da camada de aplicação é o oposto diametral do que o princípio de inversão de dependência sugere fazer.

back2dos
fonte
11
Este é um ótimo ponto! Uma coisa que me deixa menos preocupada é que o Postgres agora tem suporte para armazenamento de documentos e RDBMS ( withouttheloop.com/articles/2014-09-30-postgresql-nosql ). Seu argumento ainda é válido, e eu o considerarei com cuidado.
David
3
Isso não deve deixar você menos preocupado com o @David, apenas porque uma ferramenta pode fazer algo não significa que alterá-la não quebrará muitas coisas. Esse é o ponto de ter um grau de separação - você pode alterar completamente os dados por trás de uma API sem alterar o que o usuário vê. Estou falando como um banco de dados aqui ... contanto que o cliente veja o mesmo, você pode alterar o back-end o quanto quiser.
Ben
11
@ David Embora essa notícia seja interessante, é bastante irrelevante para o cenário que descrevi. Se você alterar seu esquema de banco de dados de um relacional para um baseado em documento, ele terá o mesmo impacto em todos aqueles que dependem dele: será necessário reescrever todas as consultas. Há também o pesadelo de ter que implantar todas essas alterações de uma só vez, para que a compatibilidade entre os componentes seja mantida em todo o sistema.
back2dos
11
@ David: Restringir o acesso a algumas visualizações bem definidas significa, sem dúvida, construir outra API, com alguns dos benefícios que a acompanham. Contanto que sejam apenas visualizações, você fica restrito ao acesso somente leitura. E ter um componente depende da API de serviço e da API de exibição, tornando-o muito frágil. Portanto, se você estiver fazendo um componente depender das visualizações, você determinou que ele seja somente leitura ou alta manutenção. Sinto cheiro de dívida técnica aqui. Além disso, convém adicionar o particionamento horizontal de uma maneira que seu banco de dados não permita.
back2dos
2
@ David: A longo prazo, é mais importante como é fácil alterar o código do que como é fácil escrevê-lo. A arquitetura não diz "você não deve escrever código dessa maneira", diz "se você escrever, sofrerá pesadelos terríveis tentando mantê-lo". Se você está falando de protótipos, a manutenção não é um requisito. Continue. Um protótipo deve provar um ponto o mais facilmente possível. Mas, ao tentar integrar todos os pontos comprovados a um sistema sem que ele se transforme em tortura auto-induzida por Sísifo, é melhor você ir além.
back2dos
55

O que é mais importante e significativo sobre um microsserviço: sua API ou seu esquema de banco de dados? A API, porque esse é o seu contrato com o resto do mundo. O esquema do banco de dados é simplesmente uma maneira conveniente de armazenar os dados gerenciados pelo serviço, esperançosamente organizados de maneira a otimizar o desempenho do microsserviço. A equipe de desenvolvimento deve estar livre para reorganizar esse esquema - ou alternar para uma solução de armazenamento de dados totalmente diferente - a qualquer momento. O resto do mundo não deveria se importar. O resto do mundo se importa quando a API muda, porque a API é o contrato.

Agora, se você for espreitar o banco de dados deles

  • Você adiciona uma dependência indesejada no esquema deles. Eles não podem alterá-lo sem causar impacto no seu serviço.
  • Você adiciona carga indesejada e imprevisível a seus internos.
  • O desempenho do seu próprio serviço será afetado pelo desempenho do banco de dados (eles tentarão otimizar o serviço para que tenham um bom desempenho para os clientes e o banco de dados tenha bom desempenho apenas para o serviço)
  • Você está vinculando sua implementação a um esquema que pode muito bem não representar de maneira precisa e distinta os recursos em seu armazenamento de dados - ele pode ter detalhes extras que são necessários apenas para rastrear o estado interno ou satisfazer sua implementação específica (com a qual você não deve se importar).
  • Você pode destruir ou corromper inconscientemente o estado de seus serviços (e eles não saberão que você está fazendo isso)
  • Você pode atualizar / excluir / remover recursos do banco de dados sem que eles saibam que isso aconteceu.

Os dois últimos pontos podem não ocorrer se você tiver apenas acesso de leitura concedido, mas os outros pontos são mais do que um motivo suficientemente bom. Bancos de dados compartilhados são uma coisa ruim.

É comum os desenvolvedores menos experientes (ou aqueles que não aprendem) ver o banco de dados como mais importante que o serviço, ver o banco de dados como algo real e o serviço apenas como uma maneira de acessá-lo. Esse é o caminho errado.

itsbruce
fonte
4
Observe que todos os pontos acima são válidos, mesmo se você for o único desenvolvedor trabalhando em todo o projeto. O gerenciamento de um projeto complexo, mesmo você mesmo, evoca todas essas preocupações.
itsbruce
15

A arquitetura de microsserviço é difícil de descrever, mas a melhor maneira de pensar sobre isso é um casamento entre arquitetura orientada a componentes e arquitetura orientada a serviços. O software como um conjunto é composto por muitos componentes de pequenas empresas com uma responsabilidade de domínio de negócios muito específica. Sua interface com o mundo externo, nos serviços prestados ou nos serviços necessários, é feita através de uma API de serviços claramente definidos.

Gravar e até ler em um banco de dados que está fora do domínio comercial dos componentes é contra esse estilo de arquitetura.

A principal razão para isso é que uma API fornecida por meio de um serviço por outro componente de software tem a expectativa razoável de que a API provavelmente seja compatível com versões anteriores à medida que novas versões do componente fornecedor de serviços estiverem disponíveis. Se eu sou o desenvolvedor de um componente "fornecendo", preciso apenas me preocupar com a compatibilidade com a minha API. Se eu sei que existem três outras equipes de desenvolvimento que escreveram consultas personalizadas diretamente no meu banco de dados, meu trabalho se tornou muito mais complicado.

Pior ainda, talvez a outra equipe que os escreveu esteja no meio do sprint em um projeto crítico e não possa aceitar essa alteração agora do seu componente. Agora, o desenvolvimento de software para seu componente em um domínio comercial de sua propriedade está sendo conduzido pelo desenvolvimento em outro domínio comercial.

A interação completa por meio de serviços reduz o acoplamento entre vários componentes de software, para que situações como essa não ocorram com tanta frequência. Quando se trata de outros componentes usando uma Visualização no banco de dados, você tem mais capacidade de tornar a Visualização compatível com versões anteriores, se alguém escrever consultas sobre ele. Ainda sinto, no entanto, que esse deve ser o caso de exceção e só deve ser feito para, talvez, relatórios ou processamento em lote, nos quais um aplicativo precisará ler enormes quantidades de dados.

Claramente, isso funciona bem em grandes equipes distribuídas, onde as equipes de desenvolvimento são separadas por domínio comercial como a Amazon. Se você é uma pequena loja de desenvolvimento, ainda pode se beneficiar com esse modelo, especialmente se precisar acelerar um grande projeto rapidamente, mas também se precisar lidar com o software do fornecedor.

maple_shaft
fonte
4

Nos últimos 20 anos, vi alguns projetos de banco de dados modulares grandes e vi o cenário sugerido por David algumas vezes agora, em que os aplicativos têm acesso de gravação ao seu próprio esquema / conjunto de tabelas e acesso de leitura a outro esquema / conjunto de mesas. Na maioria das vezes, esses dados aos quais um aplicativo / módulo obtém acesso somente leitura podem ser descritos como "dados mestre" .

Naquele tempo, não vi os problemas que as respostas anteriores sugeriam que eu deveria ter visto, então acho que vale a pena examinar mais de perto os pontos levantados nas respostas anteriores.

Cenário: você amarra dois componentes diretamente a um RDBMS e vê um componente específico se tornando um gargalo de desempenho

Concordo com este comentário, exceto que este também é um argumento para ter uma cópia dos dados localmente para o microsserviço ler. Ou seja, a maioria dos bancos de dados maduros suporta replicação e, portanto, sem nenhum esforço do desenvolvedor, os "dados mestre" podem ser fisicamente replicados no banco de dados de microsserviço, se isso for desejado ou necessário.

Alguns podem reconhecer isso de maneira antiga como um "banco de dados corporativo" replicando tabelas principais para um "banco de dados departamental". Um ponto aqui é que geralmente é bom que um banco de dados faça isso por nós com replicação integrada de dados alterados (apenas deltas, em formato binário e com custo mínimo para o banco de dados de origem).

Por outro lado, quando nossas opções de banco de dados não permitem esse suporte de replicação "pronto para uso", podemos entrar em uma situação em que queremos enviar "dados principais" para os bancos de dados de microsserviço e isso pode resultar em uma quantidade significativa de esforço e desenvolvimento do desenvolvedor. também ser um mecanismo substancialmente menos eficiente.

pode querer desnormalizar o banco de dados, mas você não pode, porque todos os outros componentes seriam afetados

Para mim, essa afirmação não está correta. A desnormalização é uma alteração "aditiva" e não uma "alteração ininterrupta" e nenhum aplicativo deve ser interrompido devido à desnormalização.

A única maneira de interromper um aplicativo é onde o código do aplicativo usa algo como "selecione * ..." e não manipula uma coluna extra. Para mim, isso seria um bug no aplicativo?

Como a desnormalização pode quebrar um aplicativo? Parece FUD para mim.

Dependência de esquema:

Sim, o aplicativo agora depende do esquema do banco de dados e a implicação é que esse deve ser um grande problema. Embora a adição de qualquer dependência extra obviamente não seja ideal, minha experiência é que a dependência do esquema do banco de dados não foi um problema; por que esse poderia ser o caso? Eu apenas tive sorte?

Dados mestre

O esquema ao qual normalmente queremos que um microsserviço tenha acesso somente leitura é o mais comumente descrito como " dados mestre " para a empresa. Ele tem os dados principais que são essenciais para a empresa.

Historicamente, isso significa que o esquema no qual adicionamos a dependência é maduro e estável (algo fundamental para a empresa e imutável).

Normalização

Se três designers de banco de dados projetarem um esquema db normalizado, eles terminarão no mesmo design. Ok, pode haver alguma variação de 4NF / 5NF, mas não muito. Além disso, há uma série de perguntas que o designer pode fazer para validar o modelo para que ele possa ter certeza de que chegou ao 4NF (estou otimista demais? As pessoas estão lutando para chegar ao 4NF?).

update: Por 4NF, aqui quero dizer que todas as tabelas no esquema atingiram sua forma normal mais alta até 4NF (todas as tabelas foram normalizadas adequadamente até 4NF).

Acredito que o processo de design da normalização é o motivo pelo qual os designers de banco de dados geralmente se sentem à vontade com a ideia de depender de um esquema de banco de dados normalizado.

O processo de normalização leva o design do DB a um design "correto" conhecido e as variações a partir daí devem ser desnormalizadas para o desempenho.

  1. Pode haver variações com base nos tipos de banco de dados suportados (JSON, ARRAY, suporte ao tipo geográfico etc.)
  2. Alguns podem argumentar sobre variações baseadas em 4NF / 5NF
  3. Excluímos variação física (porque isso não importa)
  4. Restringimos isso ao design OLTP e não ao design DW, porque esses são os esquemas aos quais queremos conceder acesso somente leitura a

Se três programadores recebessem um design para implementar (como código), a expectativa seria de três implementações diferentes (potencialmente muito diferentes).

Para mim, existe potencialmente uma questão de "fé na normalização".

Quebrando alterações de esquema?

Desnormalização, adição de colunas, alteração de colunas para maior armazenamento, ampliação do design com novas tabelas, etc, são alterações ininterruptas e os designers de banco de dados que chegaram à quarta forma normal estarão confiantes nisso.

Obviamente, as alterações de quebra são possíveis descartando colunas / tabelas ou fazendo uma alteração de tipo de quebra. Possível sim, mas em termos práticos não tive nenhum problema aqui. Talvez porque se entenda o que são mudanças significativas e que elas foram bem gerenciadas?

Eu ficaria interessado em ouvir casos de alterações no esquema no contexto de esquemas somente leitura compartilhados.

O que é mais importante e significativo sobre um microsserviço: sua API ou seu esquema de banco de dados? A API, porque esse é o seu contrato com o resto do mundo.

Embora eu concorde com essa afirmação, acho que há uma advertência importante que podemos ouvir de um arquiteto corporativo, que é "Os dados vivem para sempre" . Ou seja, embora a API possa ser a coisa mais importante, os dados também são importantes para a empresa como um todo e serão importantes por muito tempo.

Por exemplo, quando houver um requisito para preencher o Data Warehouse for Business Intelligence , o suporte ao esquema e ao CDC se tornará importante da perspectiva dos relatórios de negócios, independentemente da API.

Problemas com APIs?

Agora, se as APIs eram perfeitas e fáceis, todos os pontos são discutíveis, pois sempre escolhemos uma API em vez de ter acesso local somente leitura. Portanto, a motivação para considerar o acesso local somente leitura é que pode haver alguns problemas ao usar APIs que o acesso local evita.

What motivates people to desire local read-only access?

Otimização da API:

O LinkedIn tem uma apresentação interessante (de 2009) sobre a questão de otimizar sua API e por que é importante para eles em sua escala. http://www.slideshare.net/linkedin/building-consistent-restful-apis-in-a-highperformance-environment

Em resumo, uma vez que uma API precisa oferecer suporte a muitos casos de uso diferentes, ela pode facilmente entrar na situação em que suporta um caso de uso de maneira otimizada e o restante de maneira ruim da perspectiva da rede e do banco de dados.

Se a API não tiver a mesma sofisticação do LinkedIn, você poderá facilmente obter os cenários em que:

  • A API busca muito mais dados do que você precisa (desperdício)
  • API do Chatty, onde você deve chamar a API várias vezes

Sim, é claro que podemos adicionar cache às APIs, mas, em última análise, a chamada à API é remota e há uma série de otimizações disponíveis para os desenvolvedores quando os dados são locais.

Eu suspeito que existe um conjunto de pessoas por aí que podem adicioná-lo como:

  • Replicação de baixo custo de dados mestre para o banco de dados de microsserviços (sem custo de desenvolvimento e tecnicamente eficiente)
  • Fé na normalização e a resiliência dos aplicativos às mudanças de esquema
  • Capacidade de otimizar facilmente todos os casos de uso e, potencialmente, evitar chamadas remotas tagarelas / desperdiçadas / ineficientes
  • Mais alguns outros benefícios em termos de restrições e design coerente

Essa resposta demorou demais. Desculpas !!

Rob Bygrave
fonte
A adição de uma coluna geralmente quebra os aplicativos. Se você tiver "salário", o aplicativo que soma todos os salários é interrompido quando uma nova coluna "salário_corrência" é introduzida.
Kubanczyk
Realmente? Depende da sua definição de "quebras", suponho. Se o aplicativo estava em produção e operando como esperado, sem uma "taxa_curricular", por que você consideraria esse aplicativo quebrado agora?
precisa
O aplicativo é executado sem erros e exibe algum número. Mas é inútil. Quando o CEO vê que a soma dos salários do mês passado é de 6 milhões em vez de 50 mil (por causa de um novo funcionário pago em Wons sul-coreanos), a definição de uma produção útil / inútil não será discutida muito.
Kbanczyk
0

O gerenciamento de estado (potencialmente um banco de dados) pode ser implantado no contêiner do Microservice e exposto por meio de uma API. O banco de dados de um microsserviço não é visível para outros sistemas fora do contêiner - apenas a API. Como alternativa, você pode ter outro serviço (por exemplo, um cache) para gerenciar o estado por meio de uma API. Ter todas as dependências do Microservice (exceto chamadas de API para outros serviços) em um único contêiner implementável é uma distinção importante na arquitetura. Se alguém não conseguir isso, volte e estude a arquitetura.

Eric Roch
fonte