Usando MongoDB y PostgreSQL juntos

25

Mi proyecto actual es esencialmente una ejecución del sistema de gestión de documentos de fábrica.

Dicho esto, hay algunas arrugas (sorpresa, sorpresa). Si bien algunas de las arrugas son bastante específicas del proyecto, creo que han surgido algunas observaciones generales y preguntas que no tienen una respuesta canónica (que pude encontrar, de todos modos) y que son aplicables a un dominio de problemas más amplio . Hay mucho aquí y no estoy seguro de que sea una buena opción para el formato de preguntas y respuestas de StackExchange, pero creo que es a) una pregunta que se debe responder yb) lo suficientemente inespecífica como para que pueda beneficiar a la comunidad. Algunas de mis consideraciones son específicas para mí, pero creo que la pregunta podría ser útil para cualquiera que tenga que decidir SQL vs NoSQL frente a ambos.

El fondo:

La aplicación web que estamos creando contiene datos que son claramente de naturaleza relacional, así como datos orientados a documentos. Nos gustaría tener nuestro pastel y comerlo también.

TL; DR: Creo que # 5 a continuación pasa la prueba de olor. ¿Vos si? ¿Alguien tiene experiencia con tal integración de SQL y NOSQL en una sola aplicación? Intenté enumerar todos los enfoques posibles para esta clase de problema a continuación. ¿Me he perdido una alternativa prometedora?

Complejidades

  • Hay muchas clases diferentes de documentos. Los requisitos ya requieren docenas de documentos diferentes. Este número solo aumentará alguna vez. El mejor caso posible sería uno en el que podríamos aprovechar un lenguaje específico de dominio simple, generación de código y un esquema flexible para que los expertos en dominio pudieran manejar la adición de nuevas clases de documentos sin la intervención de DBA o programadores. (Nota: ya somos conscientes de que estamos viviendo la Décima Regla de Greenspun )
  • La integridad de las escrituras exitosas anteriores es un requisito central del proyecto. Los datos serán críticos para el negocio. La semántica completa de ACID en las escrituras se puede sacrificar siempre que las cosas que se escriben con éxito permanezcan escritas.
  • Los documentos son en sí mismos complejos. El documento prototipo en nuestro caso específico requerirá el almacenamiento de más de 150 datos distintos por instancia de documento. El caso patológico podría ser un orden de magnitud peor, pero ciertamente no dos.
  • Una sola clase de documentos es un objetivo móvil sujeto a actualizaciones en un momento posterior.
  • Nos gustan las cosas gratuitas que obtenemos de Django cuando las conectamos a una base de datos relacional. Nos gustaría mantener los obsequios sin tener que retroceder dos versiones de Django para usar la bifurcación django-nonrel. Volcar el ORM por completo es preferible a degradar a 1.3.

Esencialmente, es una mezcla de datos relacionales (las cosas típicas de su aplicación web, como usuarios, grupos, etc.), así como metadatos de documentos que necesitaremos para poder dividir y cortar con consultas complejas en tiempo real) y datos de documentos (p. Ej. los cientos de campos en los que no tenemos interés en unirnos o consultarlos: nuestro único caso de uso para los datos será mostrar el documento único en el que se ingresó).

Quería hacer una verificación de cordura (si revisas mi historial de publicaciones, soy bastante explícito sobre el hecho de que no soy un DBA) en mi método preferido, así como enumerar todas las opciones que he encontrado para que otros resuelvan problemas ampliamente similares que involucran tanto datos relacionales como no relacionales.

Soluciones propuestas:

1. Una tabla por clase de documento

Cada clase de documento obtiene su propia tabla, con columnas para todos los metadatos y datos.

Ventajas:

  • El modelo de datos SQL estándar está en juego.
  • Los datos relacionales se manejan de la mejor manera posible. Nos desnormalizaremos más tarde si es necesario.
  • La interfaz de administración incorporada de Django se siente cómoda con la introspección de estas tablas y el ORM puede vivir feliz con el 100% de los datos listos para usar.

Desventajas

  • Pesadilla de mantenimiento. Docenas (¿cientos?) De tablas con (¿decenas?) Miles de columnas.
  • Lógica a nivel de aplicación responsable de decidir exactamente en qué tabla escribir. Hacer que el nombre de la tabla sea un parámetro para una consulta apesta.
  • Básicamente, todos los cambios de lógica de negocios requerirán cambios de esquema.
  • Los casos patológicos pueden requerir la división de datos para formularios individuales en varias tablas (consulte: ¿Cuál es el número máximo de columnas en una tabla PostgreSQL? ).
  • Probablemente tendríamos que buscar un DBA real y honesto que sin duda terminaría odiando la vida y a nosotros.

2. Modelado EAV

Solo hay una tabla de campos. El modelado de Entidad-Atributo-Valor ya se entiende bien. Lo he incluido para completar. No creo que ningún proyecto nuevo que se inicie en 2013 vaya con un enfoque EAV a propósito.

Ventajas:

  • Fácil de modelar.

Desventajas

  • Más difícil de consultar.
  • La capa de base de datos ya no tiene una representación directa de lo que constituye un objeto de nivel de aplicación.
  • Perderíamos la comprobación de restricciones de nivel DB.
  • El número de filas en una tabla crecerá entre 100 y 1000 veces más rápido. Probable punto de dolor futuro, en cuanto al rendimiento.
  • Indización limitada posible.
  • El esquema de base de datos no tiene sentido en lo que respecta a ORM. Las baterías incluidas en la aplicación web se conservan, pero los modelos de datos personalizados requerirán consultas personalizadas.

3. Utilice los campos hstore o json de PostgreSQL

Cualquiera de estos tipos de campo haría el truco para almacenar datos sin esquema dentro del contexto de una base de datos relacional. La única razón por la que no salto a esta solución de inmediato es que es relativamente nueva (introducida en la versión 8.4, por lo que no es tan nueva), no tengo exposición previa y sospecho. Me parece erróneo precisamente por las mismas razones por las que me sentiría incómodo al arrojar todos mis datos agradables y fácilmente normalizados a Mongo, a pesar de que Mongo puede manejar referencias entre documentos.

Ventajas:

  • Obtenemos los beneficios de Django ORM y la gestión integrada de autenticación y sesión.
  • Todo se queda en un backend que hemos utilizado anteriormente en otros proyectos con éxito.

Desventajas

  • No hay experiencia con esto, personalmente.
  • No parece una característica muy utilizada. Parece que se recomiendan bastante a las personas que buscan soluciones NOSQL, pero no veo mucha evidencia de que estén siendo elegidos. Esto me hace pensar que me falta algo.
  • Todos los valores almacenados son cadenas. Pierda la comprobación de restricciones de nivel DB.
  • Los datos en hstore nunca se mostrarán al usuario a menos que vean específicamente un documento, pero los metadatos almacenados en columnas más estándar sí lo serán. Estaremos superando esos metadatos y me preocupa que los almacenes bastante grandes que crearemos puedan tener inconvenientes de rendimiento.

4. Ir a todo el documento orientado a documentos

Haga todos los documentos de las cosas (en el sentido de MongoDB). Cree una sola colección de tipo Documenty llámela un día. Traiga también todos los datos periféricos (incluidos los datos de cuentas de usuarios, grupos, etc.) a mongo. Obviamente, esta solución es mejor que el modelado EAV, pero me parece mal por la misma razón que el # 3 se sintió mal: ambos tienen ganas de usar su martillo como destornillador también.

Ventajas:

  • No es necesario modelar datos por adelantado. Tenga una colección con documentos de tipo Documenty llámela al día.
  • Buenas características de escala conocidas, en caso de que la colección necesite crecer para abarcar millones o incluso miles de millones de documentos.
  • El formato JSON (BSON) es intuitivo para los desarrolladores.
  • Según tengo entendido (que es solo vagamente en este punto), al ser paranoico con respecto al nivel de preocupación de escritura, incluso una sola instancia puede proporcionar seguridad de datos bastante fuerte en caso de cualquier cosa y todo hasta un bloqueo del disco duro.

Desventajas

  • El ORM está fuera de la ventana para el tronco Django. Regalos que salen por la ventana: el marco de autenticación, el marco de sesiones, la interfaz de administración, seguramente muchas otras cosas.
  • Debe usar las capacidades de referencia de mongo (que requieren múltiples consultas) o desnormalizar los datos. No solo perdemos regalos que recibimos de Django, también perdemos regalos como JOIN que damos por sentado en PostgreSQL.
  • Seguridad de los datos. Cuando uno lee sobre MongoDB, parece que siempre hay al menos una persona que se refiere a cómo aumentará y perderá sus datos. Nunca citan una ocurrencia en particular y todo podría ser solo lavado de tontos o simplemente relacionado con el antiguo fuego predeterminado y olvidar la preocupación de escritura, pero todavía me preocupa. Por supuesto, utilizaremos una estrategia de copia de seguridad bastante paranoica en cualquier caso (si los datos se corrompen silenciosamente, eso podría ser irrelevante, por supuesto ...).

5. PostgreSQL y MongoDB

Los datos relacionales van en la base de datos relacional y los datos del documento van en la base de datos orientada a documentos. La documentstabla en la base de datos relacional contiene todos los datos que podríamos necesitar para indexar o dividir, así como un ObjectId MongoDB que usaríamos cuando necesitáramos consultar los valores reales de los campos en los documentos. No podríamos usar el ORM o el administrador incorporado para los valores de los documentos en sí, pero eso no es una gran pérdida ya que toda la aplicación es básicamente una interfaz de administración para los documentos y probablemente habríamos tenido que personalizar esa parte específica del ORM en un grado inaceptable para que funcione de la manera que necesitamos.

Ventajas:

  • Cada backend solo hace lo que es bueno.
  • Las referencias entre modelos se conservan sin requerir múltiples consultas.
  • Podemos mantener las baterías que Django nos dio en lo que respecta a los usuarios, sesiones, etc.
  • Solo necesita una documentstabla, sin importar cuántas clases diferentes de documentos se creen.
  • Los datos de documentos consultados con menos frecuencia están fuertemente separados de los metadatos que se consultan con mucha más frecuencia.

Desventajas

  • La recuperación de datos del documento requerirá 2 consultas secuenciales, primero contra el DB de SQL y luego contra el MongoDB (aunque esto no es peor que si los mismos datos hubieran sido almacenados en Mongo y no desnormalizados)
  • Escribir ya no será atómico. Se garantiza que una escritura en un solo documento de Mongo será atómica y PG obviamente puede garantizar la atomicidad, pero garantizar la atomicidad de la escritura en ambos requerirá lógica de aplicación, sin duda con una penalización de rendimiento y complejidad.
  • Dos backends = dos idiomas de consulta = dos programas diferentes con requisitos de administración diferentes = dos bases de datos que compiten por la memoria.
chucksmash
fuente
Iría por una columna con un JSONtipo de datos. No tenga miedo de usar nuevas funciones en Postgres: el equipo de Postgres no lanza funciones que no sean estables. Y 9.2 no es tan nuevo en realidad). Además, puede utilizar las nuevas funciones JSON en 9.3 una vez que esté allí. Si siempre está procesando completamente los documentos en el código de su aplicación (en lugar de usar SQL), también puede almacenar JSON en una textcolumna normal .
a_horse_with_no_name
Para posibles respondedores: ¡no dude en dar una respuesta! Sin embargo, como esta pregunta ha sobrevivido bastante tiempo sin una respuesta "perfecta", tengo la intención de responder la pregunta con un postmortem completo de la experiencia una vez que la hayamos implementado y pasado a producción. Puede ser un año en el futuro, pero no se preocupe, OP lo entregará. Supongo que eso es lo que aquellos que han favorecido / votado esta pregunta en particular encontrarían más útil: la verificación de que funciona o una explicación de qué obstáculos bloquearon la opción de lado a lado.
Chucksmash
2
@chucksmash. ¿Fuiste con el # 5, después de todo? ¿Cómo lograste implementar ambas dbs? ¿Qué herramientas usaste? Si no, ¿por qué?
xpanta
@chucksmash Todavía estoy esperando los comentarios que prometiste.
Bhashit Parikh
@chucksmash OP no entregó ... :(
Albert Rothman

Respuestas:

13

Algunos pensamientos....

Por lo general, uno no quiere almacenar piezas de información estrechamente interrelacionadas en diferentes sistemas. Las posibilidades de que las cosas se desincronicen son significativas y ahora, en lugar de tener un problema en tus manos, tienes dos. Sin embargo, una cosa que puede hacer con Mongo es usarlo para canalizar sus datos hacia adentro o hacia afuera. Mi preferencia es mantener todo en PostgreSQL en la medida en que esto sea posible. Sin embargo, señalaría que hacerlo realmente requiere un conocimiento experto de la programación PostgreSQL y no es para tiendas que no estén dispuestas a dedicarse al uso de funciones avanzadas. Veo un conjunto de opciones algo diferente al tuyo. Como mi preferencia no es algo que veo en la lista, se lo daré.

Probablemente pueda separar sus metadatos en datos comunes, datos requeridos para clases y datos de documentos. A este respecto, tendría una tabla de catálogo general con la información común básica más una tabla por clase. En esta tabla, tendría un campo hstore, json o xml que almacenaría el resto de los datos junto con las columnas donde está almacenando datos que deben restringirse significativamente. Esto reduciría lo que necesita poner en estas tablas por clase, pero le permitirá aprovechar las restricciones como desee. Las tres opciones tienen diferentes problemas y vale la pena considerarlas por separado:

hstore es relativamente limitado, pero también lo usa mucha gente. No es extremadamente nuevo, pero solo es un almacén de clave / valor, y es incapaz de estructuras de datos anidadas, a diferencia de json y xml.

json es bastante nuevo y realmente no hace mucho en este momento. Esto no significa que no puedas hacer mucho con él, pero no vas a hacer mucho fuera de la caja. Si lo hace, puede esperar hacer una gran cantidad de programación, probablemente en plv8js o, si desea seguir con entornos más antiguos, plperlu o plpython. jsonestá mejor soportado en 9.3, aunque al menos en las instantáneas de desarrollo actuales, por lo que cuando se lance esa versión, las cosas mejorarán.

xml es el mejor soporte de los tres, con la mayoría de las características y el historial de soporte más largo. Por otra parte, es XML .....

Sin embargo, si decide ir con Mongo y PostgreSQL juntos, tenga en cuenta que PostgreSQL admite la confirmación de 2 fases, lo que significa que puede ejecutar las operaciones de escritura, luego emita PREPARE TRANSACTIONy si esto tiene éxito, haga sus escrituras atómicas en Mongo. Si eso tiene éxito, puede COMMIThacerlo en PostgreSQL.

Chris Travers
fuente
1
Estas son todas buenas sugerencias. Había mencionado el uso de hstore / json antes (y había descontado silenciosamente xml, porque, bueno, xml) pero no había pensado en usarlos de la manera que me recomiendan. Además de todo esto, la sugerencia de confirmación de la fase 2 de Postgres es oro. No tenía idea de que esto existía. Gracias por las geniales sugerencias.
chucksmash
El compromiso de 2 fases es realmente oro. Hace que el uso de un NoSQL en conjunto sea muy factible. Especialmente si los datos entre los 2 DB solo se interrelacionan raramente, y en su mayoría resuelven diferentes problemas
haknick
0

Puede configurar un motor de consulta como Presto o Dremio para unir datos que residen en MongoDB y Postgres con una sola consulta. Ambos tienen conectores para cada una de estas bases de datos (consulte los documentos aquí y aquí ) y proponen, respectivamente, ejecutar "SQL en cualquier cosa" y "unir cualquier cosa".

Para probar Presto, puede implementar un pequeño clúster en AWS EMR con Hadoop, Hive y Presto (agregue tono si no desea usar la línea de comando), funciona desde el cuadro; asegúrese de seguir estas instrucciones para configurar Los conectores . Hive no es estrictamente necesario, pero con él, puede crear tablas usando el resultado de las uniones entre Mongo y Postgres (consulte esta página para ver ejemplos). También hay una versión paga en el mercado , que está (supuestamente) muy optimizada y tiene una prueba de 30 días.

No he usado Dremio, pero también hay algunas formas fáciles de implementarlo en AWS, Azure o en las instalaciones. Tienen algunos cursos en línea en su sitio web , con acceso a un "laboratorio virtual" que puede utilizar para seguir las clases de forma gratuita.

kadu
fuente