Usando MongoDB e PostgreSQL juntos

25

Meu projeto atual é essencialmente uma execução do sistema de gerenciamento de documentos do moinho.

Dito isto, existem algumas rugas (surpresa, surpresa). Embora algumas das rugas sejam bastante específicas para o projeto, acredito que surgiram algumas observações e perguntas gerais que não têm uma resposta canônica (que eu poderia encontrar de qualquer maneira) e que são aplicáveis ​​a um domínio de problemas mais amplo . Há muita coisa aqui e não tenho certeza se é uma boa opção para o formato de perguntas e respostas do StackExchange, mas acho que a) é uma pergunta respondível eb) não é específica o suficiente para beneficiar a comunidade. Algumas de minhas considerações são específicas para mim, mas acho que a pergunta pode ser útil para qualquer pessoa que esteja enfrentando a decisão de SQL vs NoSQL vs ambos.

O fundo:

O aplicativo da web que estamos construindo contém dados claramente de natureza relacional, bem como dados orientados a documentos. Gostaríamos de ter o nosso bolo e comê-lo também.

TL; DR: Acho que o 5º abaixo passa no teste de olfato. Você? Alguém tem experiência com essa integração de SQL e NOSQL em um único aplicativo? Tentei listar todas as abordagens possíveis para essa classe de problema abaixo. Perdi uma alternativa promissora?

Complexidades:

  • Existem muitas classes diferentes de documentos. Os requisitos já exigem dezenas de documentos diferentes. Esse número apenas aumentará. O melhor caso possível seria aquele em que poderíamos aproveitar uma linguagem simples específica de domínio, geração de código e um esquema flexível para que especialistas em domínio pudessem lidar com a adição de novas classes de documentos sem a intervenção de DBAs ou programadores. (Nota: já estamos cientes de que estamos vivendo a Décima Regra de Greenspun )
  • A integridade de gravações bem-sucedidas anteriores é um requisito central do projeto. Os dados serão críticos para os negócios. A semântica completa do ACID nas gravações pode ser sacrificada, desde que as coisas que são gravadas com êxito permaneçam escritas.
  • Os documentos são complexos. O protótipo de documento em nosso caso específico exigirá o armazenamento de mais de 150 partes distintas de dados por instância do documento. O caso patológico poderia ser uma ordem de magnitude pior, mas certamente não duas.
  • Uma única classe de documentos é um destino em movimento sujeito a atualizações posteriormente.
  • Gostamos do material gratuito que obtemos do Django quando o conectamos a um banco de dados relacional. Gostaríamos de manter os brindes sem precisar voltar duas versões do Django para usar o fork do django-nonrel. Despejar o ORM inteiramente é preferível a fazer o downgrade para 1.3.

Essencialmente, é uma mistura de dados relacionais (seus aplicativos típicos de aplicativos da Web, como usuários, grupos etc.), além de metadados de documentos que precisaremos ser capazes de dividir e cortar com consultas complexas em tempo real) e dados de documentos (por exemplo, as centenas de campos nos quais não temos interesse em ingressar ou consultar - nosso único caso de uso para os dados será mostrar o documento único no qual ele foi inserido).

Eu queria fazer uma verificação de sanidade (se você verificar meu histórico de postagens, sou bastante explícito sobre o fato de não ser um DBA) no meu método preferido, além de enumerar todas as opções que encontrei para outras pessoas resolverem problemas amplamente semelhantes envolvendo dados relacionais e não relacionais.

Soluções propostas:

1. Uma tabela por classe de documento

Cada classe de documento obtém sua própria tabela, com colunas para todos os metadados e dados.

Vantagens:

  • O modelo de dados SQL padrão está em jogo.
  • Os dados relacionais são tratados da melhor maneira possível. Desnormalizaremos mais tarde, se precisarmos.
  • A interface administrativa interna do Django é confortável com a inspeção dessas tabelas e o ORM pode viver feliz com 100% dos dados prontos para uso.

Desvantagens:

  • Pesadelo de manutenção. Dezenas (centenas?) De tabelas com (dezenas de?) Milhares de colunas.
  • Lógica no nível do aplicativo responsável por decidir exatamente em qual tabela gravar. Tornar o nome da tabela um parâmetro para uma consulta fede.
  • Basicamente, todas as alterações na lógica de negócios exigirão alterações no esquema.
  • Casos patológicos podem exigir a distribuição de dados para formulários únicos em várias tabelas (consulte: Qual é o número máximo de colunas em uma tabela do PostgreSQL? ).
  • Provavelmente precisaríamos encontrar um DBA real e honesto com Deus que, sem dúvida, acabaria odiando a vida e a nós.

2. Modelagem de EAV

Existe apenas uma tabela de campos. A modelagem de Entidade-Atributo-Valor já está bem compreendida. Eu o incluí por completo. Eu não acho que nenhum novo projeto que esteja sendo iniciado em 2013 iria com uma abordagem de EAV de propósito.

Vantagens:

  • Fácil de modelar.

Desvantagens:

  • Mais difícil de consultar.
  • A camada do banco de dados não tem mais uma representação direta do que constitui um objeto no nível do aplicativo.
  • Perderíamos a verificação de restrição no nível do banco de dados.
  • O número de linhas em uma tabela aumentará de 100 a 1000 vezes mais rápido. Provável dor no futuro, em termos de desempenho.
  • Possibilidade de indexação limitada.
  • O esquema do banco de dados é absurdo no que diz respeito ao ORM. As baterias incluídas incluem itens de aplicativos da web, mas os modelos de dados personalizados exigirão consultas personalizadas.

3. Use os campos hstore ou json do PostgreSQL

Qualquer um desses tipos de campo faria o truque para armazenar dados sem esquema no contexto de um banco de dados relacional. A única razão que eu não saltar a esta solução imediatamente é que é relativamente novo (introduzido na versão 8.4, portanto, não que novo), eu tenho zero, exposição prévia a ele e eu sou suspeito. Parece-me errado pelas mesmas razões pelas quais eu me sentiria desconfortável jogando todos os meus dados legais e facilmente normalizados no Mongo - mesmo que o Mongo possa lidar com referências entre documentos.

Vantagens:

  • Nós obtemos os benefícios do Django ORM e o gerenciamento de autenticação e sessão embutido.
  • Tudo fica em um back-end que usamos anteriormente em outros projetos com sucesso.

Desvantagens:

  • Nenhuma experiência com isso, pessoalmente.
  • Não parece um recurso muito usado. Parece que eles são recomendados bastante para as pessoas que procuram soluções NOSQL, mas não vejo muitas evidências de que elas estejam sendo escolhidas. Isso me faz pensar que devo estar perdendo alguma coisa.
  • Todos os valores armazenados são cadeias de caracteres. Perca a verificação de restrição no nível do banco de dados.
  • Os dados no hstore nunca serão exibidos para o usuário, a menos que eles visualizem um documento especificamente, mas os metadados armazenados em mais colunas padrão serão. Nós estaremos superando esses metadados e eu me preocupo que os grandes hstores que criaremos possam ter desvantagens de desempenho.

4. Vá totalmente orientado para documentos

Faça todos os documentos de coisas (no sentido do MongoDB). Crie uma única coleção do tipo Documente chame-a de dia. Traga todos os dados periféricos (incluindo dados de contas de usuários, grupos etc.) para o mongo também. Essa solução é obviamente melhor do que a modelagem EAV, mas parece errada para mim pela mesma razão que o número 3 parecia errado - eles também querem usar o martelo como chave de fenda.

Vantagens:

  • Não há necessidade de modelar dados antecipadamente. Tenha uma coleção com documentos do tipo Documente termine o dia.
  • Boas características de escala conhecidas, caso a coleção precise crescer para abranger milhões ou até bilhões de documentos.
  • O formato JSON (BSON) é intuitivo para desenvolvedores.
  • Pelo que entendi (que é apenas vagamente neste momento), sendo paranóico em relação ao nível de preocupação com a gravação, mesmo uma única instância pode fornecer segurança de dados bastante forte no caso de qualquer coisa e tudo até uma falha no disco rígido.

Desvantagens:

  • O ORM está fora da janela para o tronco do Django. Brindes que saem pela janela com ele: a estrutura de autenticação, a estrutura de sessões, a interface de administração, certamente muitas outras coisas.
  • É necessário usar os recursos de referência do mongo (que exigem várias consultas) ou desnormalizar os dados. Não apenas perdemos brindes que obtivemos do Django, como também perdemos brindes como JOINs que tínhamos como certo no PostgreSQL.
  • Segurança de dados. Quando se lê sobre o MongoDB, parece que sempre há pelo menos uma pessoa se referindo a como isso aumentará e perderá seus dados. Eles nunca citam uma ocorrência específica e tudo pode ser apenas besteira ou apenas relacionado ao antigo incêndio padrão e esquecer a preocupação com a gravação, mas isso ainda me preocupa. Obviamente, estaremos utilizando uma estratégia de backup bastante paranóica em qualquer caso (se os dados forem corrompidos silenciosamente, isso poderia ser irrelevante, é claro).

5. PostgreSQL e MongoDB

Os dados relacionais entram no banco de dados relacional e os dados do documento no banco de dados orientado a documentos. A documentstabela no banco de dados relacional contém todos os dados que podemos precisar indexar ou fatiar e dividir, além de um MongoDB ObjectId que usaríamos quando precisássemos consultar os valores reais dos campos nos documentos. Não poderíamos usar o ORM ou o administrador interno para os valores dos próprios documentos, mas isso não é uma grande perda, já que todo o aplicativo é basicamente uma interface administrativa para os documentos e provavelmente teríamos que personalize essa parte específica do ORM em um grau inaceitável para fazê-lo funcionar da maneira que precisamos.

Vantagens:

  • Cada back-end faz apenas o que é bom.
  • As referências entre modelos são preservadas sem exigir várias consultas.
  • Nós mantemos as baterias que o Django nos deu no que diz respeito a usuários, sessões etc.
  • Precisa apenas de uma documentstabela, não importa quantas classes diferentes de documentos sejam criadas.
  • Os dados do documento menos frequentemente consultados são fortemente separados dos metadados mais frequentemente consultados.

Desvantagens:

  • A recuperação de dados do documento exigirá 2 consultas seqüenciais, primeiro no SQL DB e depois no MongoDB (embora isso não seja pior do que se os mesmos dados tivessem sido armazenados no Mongo e não desnormalizados)
  • A escrita não será mais atômica. Uma gravação em um único documento do Mongo é garantida como atômica e o PG obviamente pode garantir a atomicidade, mas garantir a atomicidade da gravação em ambos exigirá lógica do aplicativo, sem dúvida com uma penalidade de desempenho e complexidade.
  • Dois back-end = duas linguagens de consulta = dois programas diferentes com requisitos de administração diferentes = dois bancos de dados disputando memória.
chucksmash
fonte
Eu iria para uma coluna com um JSONtipo de dados. Não tenha medo de usar novos recursos no Postgres - a equipe do Postgres não libera recursos que não são estáveis. E 9.2 não é tão novo assim). Além disso, você pode usar os novos recursos JSON na 9.3, uma vez lá. Se você estiver sempre processando totalmente os documentos no código do aplicativo (em vez de usar o SQL), também poderá armazenar o JSON em uma textcoluna regular .
a_horse_with_no_name
Para possíveis respondedores: sinta-se à vontade para fornecer uma resposta! Como essa pergunta sobreviveu bastante tempo sem uma resposta "perfeita", pretendo responder à pergunta com um post-mortem completo da experiência depois que implementamos e passamos à produção. Pode demorar um ano no futuro, mas não se preocupe - o OP será entregue. Espero que seja o que aqueles que favoreceram / votaram positivamente nesta questão em particular achariam mais úteis: verificação de que ela funciona ou uma explicação de quais barreiras mataram a opção lado a lado.
Chucksmash
2
@chucksmash. Você foi com o # 5, afinal? Como você conseguiu implementar os dois dbs? Quais ferramentas você usou? Se não, por quê?
Xpanta
@chucksmash Ainda estou aguardando o feedback que você prometeu.
Bhashit Parikh
@chucksmash OP não entregou ... :(
Albert Rothman

Respostas:

13

Alguns pensamentos....

Normalmente, não se deseja armazenar informações inter-relacionadas em sistemas diferentes. As chances de as coisas ficarem fora de sincronia são significativas e agora, em vez de um problema em suas mãos, você tem dois. No entanto, uma coisa que você pode fazer com o Mongo é usá-lo para canalizar ou extrair dados. Minha preferência é manter tudo no PostgreSQL na medida do possível. No entanto, gostaria de observar que isso realmente requer conhecimento especializado da programação do PostgreSQL e não é para lojas que não desejam se dedicar ao uso de recursos avançados. Eu vejo um conjunto de opções um pouco diferente do que você vê. Como minha preferência não é algo que vejo listado, darei a você.

Você provavelmente pode separar seus metadados em dados comuns, dados necessários para classes e dados de documentos. Nesse sentido, você teria uma tabela de catálogo geral com as informações comuns básicas mais uma tabela por classe. Nesta tabela, você teria um campo hstore, json ou xml que armazenaria o restante dos dados junto com as colunas nas quais você está armazenando dados que devem ser restringidos significativamente. Isso reduziria o que você precisa colocar nessas tabelas por classe, mas permitiria que você aproveitasse as restrições como quisesse. As três opções têm problemas diferentes e vale a pena considerar separadamente:

O hstore é relativamente limitado, mas também é usado por muitas pessoas. Não é extremamente novo, mas é apenas um armazenamento de chave / valor e é incapaz de estruturas de dados aninhadas, ao contrário de json e xml.

json é bastante novo e realmente não faz muito agora. Isso não significa que você não pode fazer muito com isso, mas não fará muito fora da caixa. Se você fizer isso, pode esperar fazer uma quantidade significativa de programação, provavelmente no plv8js ou, se desejar continuar com ambientes mais antigos, plperlu ou plpython. jsoné melhor suportado na 9.3, embora pelo menos nos snapshots de desenvolvimento atuais, portanto, quando essa versão for lançada, as coisas ficarão melhores.

O xml é o melhor suportado dos três, com mais recursos e o maior histórico de suporte. Então, novamente, é XML .....

No entanto, se você decidir ir junto com o Mongo e o PostgreSQL, observe que o PostgreSQL suporta confirmação de duas fases, o que significa que você pode executar as operações de gravação e, em seguida, emitir PREPARE TRANSACTIONe, se conseguir, faça suas gravações atômicas no Mongo. Se isso der certo, você pode, então, COMMITno PostgreSQL.

Chris Travers
fonte
11
Essas são todas grandes sugestões. Eu mencionei o uso do hstore / json antes (e silenciosamente desconsiderei o xml, porque, bem, o xml), mas não pensei em usá-los da maneira que você recomenda. Além disso, a sugestão de confirmação da fase do Postgres 2 é ouro. Eu não tinha ideia que isso existia. Obrigado pelas ótimas sugestões.
Chrismash
O commit em duas fases é realmente ouro. Isso torna possível o uso de um NoSQL em conjunto. Especialmente se os dados entre apenas inter-relaciona a 2 da DB raramente, e principalmente resolver problemas diferentes
haknick
0

Você pode configurar um mecanismo de consulta como o Presto ou o Dremio para associar dados residentes no MongoDB e Postgres com uma única consulta. Ambos têm conectores para cada um desses bancos de dados (consulte os documentos aqui e aqui ) e propõem, respectivamente, executar "SQL on qualquer coisa" e "ingressar em qualquer coisa".

Para testar o Presto, você pode implantar um pequeno cluster no AWS EMR com Hadoop, Hive e Presto (adicione matiz se você não quiser usar a linha de comando), funciona da caixa - siga estas instruções para configurar os conectores . O Hive não é estritamente necessário, mas com ele, você pode criar tabelas usando o resultado de junções entre o Mongo e o Postgres (consulte esta página para exemplos). Há também uma versão paga no mercado , que é (supostamente) fortemente otimizada e tem uma avaliação de 30 dias.

Não usei o Dremio, mas existem algumas maneiras fáceis de implantá-lo na AWS, Azure ou local. Eles têm alguns cursos on-line em seu site , com acesso a um "laboratório virtual" que você pode usar para acompanhar as aulas gratuitamente.

kadu
fonte