Como escolher os bancos de dados certos para microsserviços

Prédio de escritórios iluminado à noite

Explorando os diferentes fatores a serem considerados ao tentar determinar as melhores opções de banco de dados ao refatorar para uma abordagem de microsserviços.

Em um artigo anterior, abordamos alguns dos diferentes aspectos que podem levá-lo a refatorar seu código para uma abordagem baseada em microsserviço. Um dos últimos aspectos que abordamos foi a questão do que fazer com seus dados. Em aplicações corporativas de grande escala, essa costuma ser a questão mais delicada e que merece um tratamento mais aprofundado. O que vimos é que, às vezes, é difícil determinar quando você está olhando para um problema de programação ou um problema de modelagem de dados que está disfarçando como um problema de programação.

Analisaremos vários desses casos e falaremos sobre escolhas de modelagem de dados que você pode fazer para simplificar e melhorar seu código refatorado. Mas primeiro, precisamos lidar com aquela que costuma ser a pergunta inicial feita pelas equipes que estão refatorando aplicações corporativas existentes em microsserviços.

 

As mais recentes notícias de tecnologia, corroboradas por insights de especialistas.

Mantenha-se atualizado sobre as tendências mais importantes e fascinantes do setor em IA, automação, dados e muito mais com o boletim informativo da Think. Consulte a declaração de privacidade da IBM.

Agradecemos a você! Você se inscreveu.

Sua inscrição será entregue em inglês. Você pode encontrar um link para cancelar a inscrição em todos os boletins informativos. Você pode gerenciar suas inscrições ou cancelar a inscrição aqui. Consulte nossa declaração de privacidade da IBM para obter mais informações.

Está começando devagar: um grande banco de dados ou muitos bancos de dados pequenos?

Se sua aplicação é como a maioria das aplicações que vemos que estão começando o caminho para ser refatorada em microsserviços, provavelmente podemos assumir com segurança que ela está funcionando com um único e grande banco de dados relacional. Além do mais, há uma chance quase igual de que esse banco de dados seja um Oracle Database — todo o resto dos bancos de dados relacionais (DB2, SQL Server, Informix ou até mesmo um banco de dados de código aberto como MySQL ou Postgres) dividem o restante da Compartilhe. Na verdade, sair do banco de dados relacional corporativo (geralmente caro) é um dos benefícios frequentemente promovidos da refatoração para microsserviços.

Agora, há muito boas razões para escolher outros tipos de bancos de dados - seja NewSQL ou NoSQL para muitos microsserviços. No entanto, abandonar todo o seu banco de dados relacional atual de uma só vez costuma ser uma decisão temerária. Em vez disso, você pode querer olhar para uma abordagem mais incremental para mudar seu banco de dados, assim como defendemos uma abordagem incremental para refatorar seu código Java existente.

No entanto, assim como a abordagem incremental para programação que defendemos, o maior problema em seguir uma abordagem incremental para refatoração de banco de dados é decidir por onde começar. A primeira decisão que você tem que tomar depois de decidir sobre uma abordagem incremental é se deve usar um grande banco de dados ou muitos bancos de dados pequenos. No início, isso parece sem sentido. É claro que você não quer um grande banco de dados, é isso que você tem no seu monólito! Mas vamos explicar o que queremos dizer primeiro.

Essencialmente, o lugar para começar é fazer uma distinção entre um servidor de banco de dados e um esquema de banco de dados. Para aqueles que estão familiarizados com bancos de dados em escala empresarial como Oracle ou Db2, isso é natural, porque as empresas geralmente têm um grande servidor Oracle (ou RAC, que é um servidor grande composto por muitos servidores menores) no qual várias equipes hospedarão seus próprios bancos de dados separados (cada um representado por um esquema separado). A razão pela qual isso é feito é que o licenciamento geralmente é por CPU, e a empresa quer maximizar a quantidade de uso que pode obter pelo seu dinheiro. Reunir várias equipes em um grande servidor é uma forma de fazer isso. Para aqueles que estão mais familiarizados com bancos de dados de código aberto, como MySQL ou PostgreSQL, isso é um pouco menos comum porque a distinção é menos necessária.

Isso é importante porque, quando estamos falando sobre a construção de bancos de dados para microsserviços, é importante reduzir ou eliminar o acoplamento no banco de dados, mas isso na verdade significa o acoplamento no nível do esquema do banco de dados. Surgem problemas quando você tem dois microsserviços diferentes que usam as mesmas informações — as mesmas tabelas dentro do mesmo esquema. Você entende o que queremos dizer quando olha para a Figura 1.

Figura 1: Aplicação monolítica funcionando a partir de um grande esquema.
Figura 1: Aplicação monolítica funcionando a partir de um grande esquema.

O equivalente no banco de dados de uma aplicação monolítica (também conhecida como “Grande Bola de Lama”, onde tudo se conecta a todo o resto) tem um grande esquema que conecta todas as tabelas. Sempre que isso acontece, a quantidade de desembaraço necessária para separar as tabelas é enorme. 

No entanto, ao fazer a transição para microsserviços, você deve perceber que há muito menos problemas causados pelo compartilhamento de hardware e licenças no nível do servidor. Na verdade, ao fazer a refatoração inicial para microsserviços, há muitas vantagens em manter os novos esquemas mais limpos e separados nos mesmos servidores corporativos, pois as empresas geralmente já têm procedimentos em vigor para backup e restauração de banco de dados e para atualizações do servidor de banco de dados, que as equipes podem aproveitar. 

De certa forma, o que a empresa está oferecendo por meio do fornecimento de hardware, software e gerenciamento de um banco de dados empresarial é uma versão limitada de um banco de dados como serviço (DBaaS). Isso se encaixa especialmente bem com uma abordagem que começa com uma separação mais clara de partes de seu monólito por área funcional, começando com uma abordagem de "monólito modular", como mostra a Figura 2.

Figura 2: Monólito modular e vários esquemas refatorados.
Figura 2: Monólito modular e vários esquemas refatorados.

Neste exemplo (que visa mostrar um trabalho de refatoração em andamento), você pode ver como o banco de dados foi dividido separando as tabelas correspondentes a três novos esquemas (A, B e C) que correspondem a módulos específicos no aplicação refatorada. Depois de separados desta forma, eles podem ser divididos de forma limpa e clara em microsserviços distintos. No entanto, D e E ainda estão sendo refatoradas, elas ainda compartilham um único esquema com tabelas interconectadas.

Eventualmente, até mesmo a vinculação no nível do servidor de banco de dados pode se tornar um problema. Por exemplo, você está limitado às funcionalidades disponíveis de um banco de dados corporativo, se é essa a sua escolha. Mesmo em um modelo relacional, nem todos os esquemas precisam de todas as funcionalidades, ou podem precisar de funcionalidades que são mais bem suportadas por meio de um servidor diferente (por exemplo, uma melhor fragmentação geralmente é mencionada como uma razão para usar um banco de dados NewSQL). Da mesma forma, atualizar um servidor de banco de dados compartilhado por vários microsserviços pode levar vários serviços ao ar uma vez. 

Mas o problema é que essa é uma decisão que pode ser adiada — ela não precisa ser tomada imediatamente no início do projeto. Quando as equipes começam inicialmente a refatorar, mantê-las no mesmo servidor de banco de dados durante pelo menos os estágios iniciais de um projeto de refatoração é uma forma de fazer mudanças incrementais enquanto a equipe ganha a experiência necessária em código e refatoração de banco de dados.

Considerando modelos não relacionais

Como você indicou na última seção, à medida que avança no processo de refatoração, talvez você queira pensar com um pouco mais de cuidado sobre as opções do seu banco de dados — nem todos os conjuntos de dados são perfeitamente adequados para um modelo relacional. Decidir qual a melhor abordagem para gerenciar esses conjuntos de dados geralmente se resume à questão de "o que você está realmente armazenando em seu banco de dados?"

Passamos anos ajudando empresas a construir, manter e, muitas vezes, torturar frameworks de mapeamento relacional de objetos, mas a realidade do problema era que, em vários casos, os dados que estavam sendo armazenados não mapeavam bem para um modelo de dados relacional. Sempre que isso ocorria, nos tínhamos que "torcer" o modelo relacional para se ajustar, ou, mais provavelmente, superar obstáculos nos programas para forçar o código a corresponder ao armazenamento de dados relacionais.

Agora que migramos para uma era de escolhas de persistência poliglota, podemos reexaminar algumas dessas decisões e tomar outras melhores. Em particular, queremos analisar quatro casos diferentes nos quais é óbvio que o modelo relacional não era a melhor opção. Depois, considerar um caso em que o modelo relacional era a melhor opção e colocar os dados em outro formulário não teria sido a abordagem correta. .

microsserviços

O que são microsserviços?

Neste vídeo, Dan Bettinger oferece uma visão geral dos microsserviços. Comparando a arquitetura das aplicações de microsserviço com o tipo tradicional de arquitetura monolítica por meio do exemplo de uma aplicação de criação de tíquetes, Dan expõe as inúmeras vantagens dos microsserviços e as soluções que oferecem para os desafios apresentados pelos sistemas monolíticos.

Manipulação de armazenamento de Blobs

Muitas vezes, examinamos o código de persistência de sistemas corporativos apenas para descobrir, para nossa surpresa, que o que eles na verdade armazenam em seus bancos de dados relacionais são representações binárias de objetos Java serializados. Eles são armazenados em colunas "Binary Large Object" ou "Blob" e geralmente são o resultados de uma equipe jogando suas mãos para cima da complexidade de tentar mapear seus objetos Java em tabelas e colunas relacionais. O armazenamento de Blob tem certas desvantagens: ele nunca pode ser consultado por coluna; muitas vezes é lento; e é sensível a alterações na estrutura dos próprios objetos Java — dados mais antigos podem não ser legíveis se a estrutura do objeto mudar significativamente.

Se sua aplicação (ou, mais provavelmente, um subconjunto da sua aplicação) estiver usando armazenamento Blob em um banco de dados relacional, isso já é um bom sinal de que você estaria melhor utilizando um armazenamento de valores-chave como Memcached ou Redis. Por outro lado, talvez você queira dar um passo atrás e pensar um pouco sobre o que está armazenando. Se for apenas um objeto Java estruturado (talvez profundamente estruturado, mas não nativamente binário), talvez seja melhor armazenar em um repositório de documentos como Cloudant ou MongoDB. Além disso, com um pouco de esforço gasto na forma como você armazena seus documentos (por exemplo, ambos os bancos de dados acima são armazenamentos de documentos JSON, e os Analisadores JSON estão amplamente disponíveis e fáceis de personalizar), você pode lidar com qualquer "esquema deriva" de problemas com muito mais facilidade do que você poderia com uma abordagem de armazenamento de Blob, que é muito mais opaco em seu mecanismo de armazenamento.

Objetos planos e o padrão Active Record

Anos atrás, quando Martin Fowler estava escrevendo "Patterns of Enterprise Application Architectures", tínhamos uma correspondência ativa e várias avaliações animadas sobre muitos dos padrões. Um em particular sempre se destacou – o padrão Active Record. Foi estranho porque, vindo da comunidade Java, nunca o tínhamos encontrado (embora Martin nos tenha garantido que era comum na comunidade de programação Microsoft .NET). Mas o que realmente nos impressionou - e especialmente quando começamos a ver algumas implementações em Java usando tecnologias de código aberto como o iBatis - foi que parecia que o melhor caso para usá-lo era quando os objetos eram, bem, planos.

Se o objeto que você está mapeando para um banco de dados for completa e totalmente simples, sem relacionamentos com outros objetos (com a exceção limitada, talvez, de objetos aninhados), então você provavelmente não está aproveitando todos os recursos do modelo relacional. Na verdade, é muito mais provável que você esteja armazenando um documento. Muitas vezes, nos casos em que vimos isso, as equipes estão literalmente armazenando versões eletrônicas de documentos em papel, sejam pesquisas de satisfação do cliente, tickets de problemas etc. Nesse caso, um banco de dados de documentos como o Cloudant ou o MongoDB provavelmente será a melhor opção. Dividir seu código em seus próprios serviços que funcionam nesse tipo de banco de dados resultará em um código muito mais simples e muitas vezes será mais fácil de manter do que tentar fazer o mesmo como parte de um grande banco de dados corporativo.

Tratamento de dados de referência

Outro padrão comum que vimos em sistemas ORM é a combinação de "dados de referência em uma tabela sugada para um cache na memória". Os dados de referência consistem em itens que não são frequentemente (ou nunca) atualizados, mas que são constantemente lidos. Um bom exemplo disso é a lista de estados dos EUA ou províncias canadenses; outros exemplos incluem códigos médicos ou listas de peças padrão. Esse tipo de dado é frequentemente usado para preencher menus suspensos em GUIs.

O padrão comum é começar lendo a lista de uma tabela (geralmente uma tabela plana de duas ou, no máximo, três colunas) cada vez que é usada. No entanto, você descobrirá que o desempenho de fazer isso todas as vezes é proibitivo, então, em vez disso, a aplicação os lê em um cache em memória como o EhCache na inicialização.

Sempre que você tem esse problema, ele está implorando para ser refatorado em um mecanismo de cache mais simples e rápido. Novamente, esta é uma situação em que o Memcached ou o Redis seriam perfeitamente razoáveis. Se os dados de referência forem independentes do restante da estrutura do seu banco de dados (e muitas vezes forem, ou no máximo, fracamente acoplados), a separação dos dados e seus serviços do restante do sistema pode ajudar.

A consulta do inferno

No sistema de um cliente com o qual trabalhamos, estávamos fazendo modelagem financeira complexa que exigia consultas muito complicadas (da ordem de junções de seis ou sete vias) apenas para criar os objetos que o programa estava manipulando. As atualizações eram ainda mais complicadas, pois tínhamos que combinar vários níveis diferentes de verificações de bloqueio otimistas apenas para descobrir o que havia mudado e se o que estava no banco de dados ainda correspondia à estrutura que havíamos criado e manipulado.

Em retrospectiva, fica claro que o que estávamos fazendo teria sido mais naturalmente modelado como um gráfico. Situações como esta (neste caso, estávamos modelando parcelas de fundos, cada uma composta por diferentes tipos de ações e obrigações de dívida, e cada um deles precificado em moedas diferentes e com vencimento em momentos diferentes, com regras diferentes envolvendo cada avaliação) são algo que quase implora por uma estrutura de dados que permita que você faça facilmente o que realmente quer fazer—traverse o gráfico para cima e para baixo e migrar partes do gráfico à vontade.

É aqui que uma solução como o Apache Tinkerpop ou o Neo4J seria uma boa abordagem. Ao modelar a solução diretamente como um gráfico, poderíamos ter evitado muitos códigos Java e SQL complicados e, ao mesmo tempo, provavelmente melhorado muito nosso desempenho em tempo de execução.

De volta para o futuro; ou, quando o SQL tradicional ou o NewSQL brilham

Embora haja muitos casos em que os bancos de dados NoSQL são a abordagem lógica certa para estruturas de dados específicas, muitas vezes é difícil superar a flexibilidade e o poder do modelo relacional. A grande vantagem dos bancos de dados relacionais é que você pode efetivamente "fatiar e fatiar" os mesmos dados em diferentes formulários para diferentes propósitos. Truques como visualizações de banco de dados permitem que você crie múltiplos mapeamentos dos mesmos dados — algo que muitas vezes é útil ao implementar um conjunto de consultas relacionadas de um modelo de dados complexo. 

Para uma comparação mais detalhada entre NoSQL e SQL, consulte "SQL versus NoSQL: qual é a diferença? "

Conforme discutimos em um artigo anterior, se o "limite inferior" de um microsserviço é um conjunto de Entidades agrupadas em um Agregado com o conjunto associado de Serviços que operam nesses dados, implementar as visualizações para representar um conjunto de consultas relacionadas é Geralmente, a maneira mais fácil e direta com SQL.

Vimos isso pela primeira vez no exemplo do cliente que levou ao nosso exemplo simples de conta/item de linha no artigo anterior. Neste caso, havia um banco que tentava muito fazer um modelo simples como esse funcionar em um banco de dados NoSQL orientado a documentos, apenas para ser derrotado pelo teorema CAP. No entanto, a equipe escolheu esse modelo de dados por todos os motivos errados. Eles optaram por usar o banco de dados orientado a documentos para todos os seus diversos microsserviços devido a um desejo equivocado de consistência arquitetônica.

Nesse caso, eles precisavam de todos os atributos do modo ACID, mas não de fragmentação (por exemplo, particionamento); seu sistema existente tinha funcionado por anos em um nível de desempenho totalmente aceitável em um modelo relacional, e eles não estavam antecipando um crescimento enorme. Mas, embora o núcleo do sistema precisasse de transações ACID e não precisasse de particionamento, isso não era necessariamente verdade para todas as diferentes partes do sistema. Há algumas coisas em que os SQL Database são ótimos, e as transações ACID estão entre elas. Em sistemas de microsserviço, agrupar essas transações ACID em torno do menor conjunto de dados com que operam geralmente é a abordagem correta.

No entanto, SQL não significa necessariamente SQL Database tradicionais. Ele pode, e certamente há um lugar para isso em muitas arquiteturas de microsserviços, mas o SQL também é implementado em pelo menos dois outros tipos de bancos de dados que podem ser escolhas úteis para muitas equipes que implementam microsserviços. O primeiro é "SQL pequeno", que é o domínio de bancos de dados de código aberto como MySQL e Postgres. Para muitas equipes que implementam microsserviços, esses bancos de dados são uma escolha perfeitamente razoável por muitos motivos:

  1. As equipes que estão refatorando aplicações existentes em microsserviços geralmente têm experiência com SQL e frameworks de mapeamento relacional de objetos, como Hibernate ou Spring Persistence. Aproveitar esse conhecimento e, ao mesmo tempo, permanecer dentro dos limites de uma abordagem de microsserviço, é certamente razoável.
  2. Esses bancos de dados são muito bem suportados, tanto pela comunidade de código aberto quanto por muitos fornecedores que fornecem suporte para eles. É relativamente fácil encontrar documentação e tutoriais para eles e encontrar desenvolvedores qualificados neles.
  3. Esses bancos de dados são pequenos e leves o suficiente para serem facilmente conteinerizados e implementados e atualizados por meio dos mesmos mecanismos GitOps que você usa para o código da sua aplicação.
  4. Esses bancos de dados são compatíveis em versões SaaS da maioria ou de todas as nuvens públicas hiperescalas.

A principal desvantagem de usar esses SQL Databases pequenos é que eles muitas vezes não oferecem suporte ao mesmo nível de escala (especialmente no que diz respeito à fragmentação) que os bancos de dados corporativos podem oferecer suporte. No entanto, isso foi surpreendentemente abordado por um novo conjunto de fornecedores de bancos de dados e projetos de código aberto que combinam os melhores atributos de SQL Databases pequenos e a escalabilidade dos bancos de dados NoSQL. Frequentemente chamados de bancos de dados "NewSQL", eles incluem CockroachDB, Apache Trofidion e Clustrix.

Sempre que você precisar de todas as transações ACID, um mecanismo SQL que ofereça suporte total ao modelo relacional e também amplos recursos de dimensionamento e fragmentação, os bancos de dados NewSQL podem ser uma boa escolha para as equipes. No entanto, essa escolha tem um custo: esses bancos de dados geralmente são mais complexos de configurar e gerenciar do que as soluções mais antigas de "SQL pequeno". Também é mais difícil encontrar pessoas com habilidades nesses bancos de dados. Independentemente disso, eles ainda precisam ser cuidadosamente considerados quando você analisa suas opções.

O que fazer a partir daí?

Fizemos um tour rápido por vários problemas diferentes de modelagem de banco de dados que podem se disfarçar como problemas de programação. Se você descobrir que tem um ou mais desses problemas específicos, talvez seja melhor separar o armazenamento de dados corporativo existente e reformulá-lo com um tipo diferente de armazenamento de dados. Nosso conselho é, em qualquer caso, fazer isso de forma lenta e incremental. Saiba que nem todas as aplicações precisam de todos os tipos de modelos de dados e que você precisa desenvolver habilidades e compreender os recursos operacionais dos bancos de dados escolhidos ao longo do tempo antes de começar a implementá-los em ampla escala.

Por fim, esteja ciente do fato de que toda a abordagem de microsserviços se baseia na ideia de que as equipes que criam cada microsserviço podem tomar suas próprias decisões sobre qual armazenamento de dados é adequado para elas. O maior problema que encontramos (como muitas dessas histórias têm insinuado) foi tentar fazer com que uma única abordagem de representação e armazenamento de dados funcione para todas as situações. 

Muitas vezes vi equipes tentarem lidar com as realidades do teorema CAP em situações em que nem deveriam estar usando um banco de dados NoSQL. Da mesma forma, tentar fazer relatórios complexos a partir de um banco de dados NoSQL costuma ser um exercício frustrante. Por outro lado, as situações que mostramos apontam que o modelo relacional não é abrangente. Outros modelos também têm seus lugares. O melhor conselho que podemos dar é garantir que suas equipes tenham a autonomia necessária para escolher o modelo certo para cada microsserviço.

Saiba mais

O IBM Garage foi criado para se mover mais rápido, trabalhar de forma mais inteligente e inovar de uma forma que possibilite impedir a disrupção.

Autora

Kyle Brown

IBM Fellow, CTO

IBM CIO Office

Soluções relacionadas
IBM Red Hat OpenShift

O Red Hat OpenShift on IBM Cloud é uma plataforma de contêineres OpenShift (OCP) totalmente gerenciada.

Explore o Red Hat OpenShift
Soluções de DevOps

Utilize softwares e ferramentas de DevOps para desenvolver, implementar e gerenciar aplicativos nativos da nuvem em diversos dispositivos e ambientes.

Explore as soluções de DevOps
Serviços de consultoria em nuvem 

Libere novos recursos e aumente a agilidade dos negócios com os serviços de consultoria em nuvem da IBM. Descubra como cocriar soluções, acelerar a transformação digital e otimizar o desempenho por meio de estratégias de nuvem híbrida e parcerias especializadas.

Serviço de nuvem
Dê o próximo passo

Libere novos recursos e aumente a agilidade dos negócios com os serviços de consultoria da IBM Cloud.

Explore nossos serviços de consultoria da IBM Cloud Crie sua conta gratuita na IBM Cloud