Interactuando con datos usando múltiples bases de datos / servidores

18

Todos los proyectos con los que he tenido que lidiar hasta ahora solo han requerido una única base de datos en un solo servidor. Estoy interesado en aprender más sobre cómo los proyectos que necesitan escalar se mueven a múltiples bases de datos y / o servidores para ayudar a administrar la carga. Soy consciente de la alta escalabilidad , pero estoy particularmente interesado en algunos ejemplos de código o recursos adicionales donde podría leer más sobre el tema.

Por ejemplo:

  • ¿Cómo se construyen las uniones entre dos tablas en múltiples bases de datos? (Un ejemplo de código aquí sería útil).
  • ¿Existen estrategias especiales para rastrear qué tablas están en qué base de datos?
  • ¿El código de la aplicación necesita saber que una o más bases de datos están distribuidas en varios servidores? Si no, ¿a qué nivel se filtran las solicitudes?
  • ¿Cuándo es el momento de ir más allá de una configuración de 1 base de datos / 1 servidor? ¿Qué tan común es tener que hacer esto?
VirtuosiMedia
fuente
Esta pregunta podría responderse mejor en los administradores de bases de datos . Sin embargo, tampoco hay nada realmente malo aquí, así que solo voy a consultar con los mods de DBA. Si es adecuado allí, ¿le gustaría migrar?
Adam Lear
@AnnaLear: creo que depende de las respuestas. En este punto, estoy más interesado en el lado de la aplicación del problema, por lo que por ahora, creo que podría ser mejor aquí.
VirtuosiMedia
@AnnaLear ack, de acuerdo con el OP, entonces si quieren un código específico de la aplicación.
jcolebrand

Respuestas:

13

Ok, vamos a desglosarlo:

  • ¿Cómo se construyen las uniones entre dos tablas en múltiples bases de datos? (Un ejemplo de código aquí sería útil).

Esto es bastante sencillo. Los objetos SQL tienen desde una convención de nomenclatura de una a cuatro partes:

Servername.databasename.schemaname.tablename

Si todas sus tablas están en el mismo servidor en la misma base de datos, con el mismo propietario / esquema, puede ignorar las tres primeras partes y usar lo que está más acostumbrado a:

Select a.*,b.* from 
tableA a inner join 
tableB b on a.col1=b.col1

Si una de sus tablas está en una base de datos diferente y ambas usan el esquema predeterminado para sus bases de datos, simplemente agregue la base de datos a la segunda tabla:

Select a.*,b.* from 
tableA a inner join 
databaseC..tableB b on a.col1 = b.col1

Si se encuentra en una tercera base de datos diferente de cualquiera de las que está consultando, use ambos nombres de base de datos explícitamente:

Select a.*,b.* from 
databaseD..tableA a inner join 
databaseC..tableB b on a.col1 = b.col1

Si termina utilizando diferentes esquemas y / o propietarios, puede agregarlos en:

Select a.*,b.* from 
databaseD.john.tableA a inner join 
databaseC.accounting.tableB b on a.col1 = b.col1

Y, por último, si tiene mucho cuidado y tiene una muy buena razón, puede unirse a una tabla (generalmente pequeña) en otro servidor:

Select a.* from 
databaseD.john.TableA a inner join 
ATLANTA.databaseC.accounting.tableB b on a.col1 = b.col1
  • ¿Cuándo es el momento de ir más allá de una configuración de 1 base de datos / 1 servidor? ¿Qué tan común es tener que hacer esto? ¿Existen estrategias especiales para rastrear qué tablas están en qué base de datos?

Combinaré estos dos porque van juntos. En general, casi siempre está bien comenzar con la suposición de que una base de datos de un servidor es suficiente hasta que sus limitaciones técnicas / comerciales / de diseño lo obliguen a usar más.

Entonces, para responder a su segunda pregunta primero, dado que generalmente tiene una razón para tener bases de datos separadas, debería ser bastante obvio saber el diseño de su sistema donde está algo.

En cuanto a cuándo / por qué es necesario ir más allá de una sola base de datos. Por lo general, es una combinación de reglas comerciales, políticas y / o razones técnicas.

Por ejemplo, donde trabajo tenemos 16 bases de datos repartidas en 4 servidores. Tenemos MainDB, ImageDB, referencetableDB, HighvolumeTransactionDB, ReportingDB, StagingDB, ProcessingDB, ArchiveDB, FinancialDB. Para dar algunos ejemplos de por qué son diferentes:

  • FinancialDB, información sensible
  • Image DB, requisitos específicos de almacenamiento y recuperación diferentes
  • Referencia DB, transacción baja, lectura alta
  • ReportingDB, lectura muy alta, necesita ser restaurado / replicado a varios otros entornos a diferencia de muchos otros datos
  • StagingDB, nada permanente, solo un tempdb reforzado sobre el que tenemos más control
  • MainDB, interactúa con todos los otros DB pero necesita copias de seguridad diferenciales, así que ... dividimos el
  • Las tablas de HighVolumeTransaction (que son relativamente transitorias) a su propia base de datos para mantener el tamaño razonable de la copia de seguridad.
  • Archivo, muchos de los mismos datos de Principal e Informes, pero con períodos de retención más largos y consultas más difíciles de cavar en profundidad en los datos. Si esto todavía se combinara con Main / Reporting, se estancaría nuestro sistema.

¿El código de la aplicación necesita saber que una o más bases de datos están distribuidas en múltiples servidores? Si no, ¿a qué nivel se filtran las solicitudes?

En un sentido amplio, probablemente lo hagan. Como mínimo, necesitan saber a qué servidor apuntan en la cadena de conexión de la base de datos. Procesamiento, Informes, Principal, etc.

A partir de ahí, necesitan un contexto de base de datos para ejecutar. En general, ese sería el más utilizado para la aplicación, tal vez incluso el original de la base de datos / un servidor días de la aplicación. PUEDE hacer que la aplicación cambie explícitamente el contexto de la base de datos en cada llamada, pero eso hace que sea muy difícil ajustar la base de datos sin cambiar la aplicación.

El enfoque habitual (o al menos MI habitual) es acceder siempre a través de una o quizás dos bases de datos principales.

Luego, cree vistas en otras bases de datos según sea necesario combinadas con la interfaz con la base de datos a través de procedimientos almacenados.

Entonces para ilustrar:

Supongamos que desea obtener la información demográfica, los datos de ventas y el saldo de crédito de un Cliente, y eso se distribuye en tres tablas originalmente todas en MainDB.

Entonces escribes una llamada desde tu aplicación:

Select c.ClientName, c.ClientAddress, s.totalSales,f.CreditBlance from
Clients c join Sales s on c.clientid = s.clientid inner join AccountReceivable f on 
c.clientid=f.clientid where c.clientid = @clientid

Increíble. Sin embargo, ahora cada vez que cambiemos el nombre de una columna, o cambiemos el nombre / muevamos una tabla, debe actualizar el código de la aplicación. Entonces, en su lugar, hacemos dos cosas:
crear clientes, ventas, vistas de cuentas por cobrar (no usaría Select * pero estoy haciendo una demostración aquí)

Use MainDB
GO
Create view v_Clients as select * from Clients
Create view v_Sales as select * from Sales
Create view v_AccountReceivable as select * from AccountReceivable
Go

Luego también creamos un procedimiento almacenado, spGetClientSalesAR

Create proc spGetClientSalesAR @clientID int
as
Select c.ClientName as ClientName, 
       c.ClientAddress as ClientAddress, 
       s.totalSales as TotalSales, 
       f.CreditBlance as CreditBalance 
from
v_Clients c join v_Sales s 
    on c.clientid = s.clientid 
inner join v_AccountReceivable f 
    on c.clientid=f.clientid 
where c.clientid = @clientid

Y que tu aplicación llame así.

Ahora, siempre y cuando no cambie la interfaz en ese proceso almacenado, puedo hacer casi cualquier cosa que necesite hacer en la base de datos de back-end para escalar o escalar.

En el extremo, incluso podría hacer que mi viejo MainDB fuera solo un montón de procedimientos almacenados y vistas almacenadas de forma tal que debajo de esas vistas que creamos se veía así:

Create view v_Clients as select * from ServerX.DatabaseY.dbo.Clients
Create view v_Sales as select * from ServerQ.DatabaseP.dbo.Sales
Create view v_AccountReceivable as select * from ServerJ.DatabaseK.dbo.AccountReceivable

Y su aplicación nunca notaría la diferencia (suponiendo entregas rápidas y datos bien organizados, entre otras cosas).

Obviamente, eso es extremo y estaría mintiendo si dijera que todo fue planeado de esta manera, pero el uso de procedimientos / vistas almacenados, incluso si lo hace durante la refactorización, le permitirá mucha flexibilidad a medida que su aplicación crezca desde su humilde base de datos / servidor comenzando.

TetonSig
fuente
TetonSig - Gracias por la respuesta. No pude volver a la pregunta a tiempo para otorgarle la recompensa completa (estaba viajando), pero creé una nueva recompensa para la pregunta y se la podré otorgar en 24 horas.
VirtuosiMedia
Wow gracias. Soy consciente de que. Fue muy divertido responder la pregunta.
TetonSig
5

La forma principal en la que me he encontrado con múltiples servidores de bases de datos en el mundo web (dado que la pregunta está etiquetada como PHP) es configuraciones donde había una base de datos 'maestra' (escritura), y luego una o más bases de datos 'esclavas' replicadas (leídas) . Las escrituras de la base de datos se realizan contra la base de datos 'maestra'. El contenido de esa base de datos se replica en los servidores 'esclavos' en tiempo casi real. Las consultas, especialmente los informes intensivos, se ejecutan en una de las bases de datos 'esclavas' para transferir la carga a esos servidores. Tenga en cuenta que esa configuración particular es mejor para aplicaciones que tienen muchas lecturas, pero no mucha escritura. De ninguna manera es la única forma de organizar las cosas.

Gran maestro B
fuente
3

¿Cómo se construyen las uniones entre dos tablas en múltiples bases de datos? (Un ejemplo de código aquí sería útil).

Ellos no están. Las bases de datos NoSQL no hacen "uniones" en absoluto, e incluso si pudiera hacer una unión SQL a través de servidores RDBMS, no desearía hacerlo si valora el rendimiento (consulte las falacias de la computación distribuida ).

¿Existen estrategias especiales para rastrear qué tablas están en qué base de datos?

En una base de datos relacional / SQL, la partición normalmente se realiza dentro de los límites de un único servidor / base de datos, utilizando diferentes archivos colocados en diferentes discos. Casi por definición, una solución de escala horizontal significa que todas las bases de datos tienen todas las tablas y usted tiene algún tipo de reflejo transaccional, replicación o solución personalizada de consistencia eventual para asegurarse de que todos los datos lleguen a donde se supone que deben hacerlo.

Si en realidad está dividiendo la base de datos de manera lógica y no solo física, entonces las asignaciones definidas en su DAL u ORM declararán qué tablas están en qué base de datos.

Las bases de datos NoSQL son una mezcla de soluciones de particionamiento. A veces son las "tablas" (o más comúnmente, "colecciones") las que se particionan. Otras veces son las "filas" (o "documentos"). En algunos casos, en realidad son las columnas , como en una base de datos orientada a columnas como HBase. Depende totalmente de la tecnología que esté utilizando. Lo único que todos tienen en común es que el motor mismo realiza un seguimiento de todo, por lo que todo lo que tiene que hacer es solicitar un documento o fila.

Eso, por supuesto, supone que en realidad está utilizando las funciones de fragmentación y no solo está creando un montón de bases de datos diferentes. Si estás haciendo lo último, entonces estás solo.

¿El código de la aplicación necesita saber que una o más bases de datos están distribuidas en varios servidores? Si no, ¿a qué nivel se filtran las solicitudes?

Si son bases de datos lógicas diferentes , sí. Si solo se distribuyen físicamente, entonces no, suponiendo que su base de datos específica sea compatible de forma nativa con sharding o que use una solución de equilibrio de carga (para bases de datos SQL). Suponiendo también que todas sus operaciones no tienen estado; si quieres una escala horizontal, tendrás que renunciar a ACID.

¿Cuándo es el momento de ir más allá de una configuración de 1 base de datos / 1 servidor? ¿Qué tan común es tener que hacer esto?

Es hora de que haya optimizado todo lo que pueda en un servidor y aún no pueda exprimir el rendimiento suficiente debido a las restricciones en la carga de E / S. Si tiene que hacer la pregunta, entonces es demasiado temprano.

Tenga en cuenta que los problemas de rendimiento en un producto RDBMS decente (Oracle, SQL Server) se deben con mayor frecuencia a un diseño deficiente, indexación deficiente, consultas deficientes, contención de bloqueo, etc. Estos productos pueden escalar verticalmente hasta un grado ridículo. De nuevo, debería considerar "ir más allá de una configuración de 1 base de datos / 1 servidor" cuando esté absolutamente seguro de que sus problemas de rendimiento se deben a limitaciones de hardware y no solo a un diseño / implementación deficiente.

O, supongo, otra razón por la que algunas personas cambian a bases de datos distribuidas es cuando no están preparadas para pagar mucho (o ningún) dinero en tarifas de licencia y quieren deshacerse de SQL como una opción consciente para cambiar el bajo costo por una mayor complejidad de la aplicación. Razón totalmente válida si eres un startup de software pero generalmente no es aplicable en el sector corporativo.

Aaronaught
fuente
+1 - Realmente no estaba considerando NoSQL, pero de todos modos esto es útil. Gracias.
VirtuosiMedia
1

Existen tres tipos principales de configuraciones de replicación para bases de datos:

  • Maestro-esclavo
  • Maestro maestro
  • Consenso

Ejemplo de maestro-esclavo: maestro MySQL + esclavos MySQL, MongoDB

Ejemplo maestro-maestro: CouchDB, Cassandra, Riak

Ejemplo de consenso: ScalienDB

...para nombrar unos pocos.

Estos tienen diferentes características. Las configuraciones maestro-esclavo permiten que los nodos esclavos alcancen al maestro a su velocidad máxima mientras atienden solicitudes de lectura muy rápidamente, mientras que el servidor maestro es responsable de la integridad de los datos. Debido a que todas las escrituras van al maestro, nunca hay contención de bloqueo porque un solo escritor relativamente lento está bloqueando a muchos lectores, pero por otro lado, los servidores esclavos son eventualmente consistentes y no obtienes las garantías de aislamiento de transacción que tendrías de leer solo del maestro. (lectura adicional; ACID vs BASE, niveles de aislamiento de transacción, replicación de base de datos, MVCC / aislamiento: instantánea, replicación transaccional)

Master-Master siempre permite escrituras, por lo que tendría múltiples autoridades sobre lo que es cierto. Esto puede o no ser un problema, dependiendo de lo que esté haciendo su aplicación, pero si escribe datos contradictorios, puede obtener múltiples resultados la próxima vez que lea esa clave / fila / columna que deberá fusionar con la lógica de la aplicación y guardar de nuevo en la base de datos. (lectura adicional: teorema CAP, replicación CouchDB, replicación Riak, hashing consistente, Bitcask & StormDB, Quorum- con MongoDB en división de red, estrategias de resolución de fusión)

Las bases de datos basadas en el consenso con replicación a través de nodos, como Scalien, siempre serían consistentes en las escrituras, pero a costa de intercambiar múltiples mensajes antes de ACK la escritura. Esto no es un gran problema si tiene un ethernet rápido y no necesita escribir en el disco antes de ACKing, lo cual no necesitará si su mínimo de tres servidores están en bastidores de servidores diferentes con fuentes de alimentación separadas (una muere; los otros dos se aseguran de que hayan guardado en el disco). (lectura adicional; PAXOS, PAXOS COMMIT, compromiso de dos fases con transacciones distribuidas, compromiso de tres fases)

Otras lecturas adicionales: (libro: 'Elementos de computación distribuida', relojes vectoriales, vectores de versión, vectores de matriz, relojes lógicos, algoritmo de panadería, relojes de árbol de intervalo, actores y programación reactiva y reactores, memoria transaccional de software, transactores, AKKA, Stact, falacias de computación distribuida, protocolos de chismes, extensiones de protocolo de chismes anti-entropía de Cassandra, tablas de hash distribuidas, documentos sobre la fusión de datos en un entorno distribuido, arquitectura ZooKeeper, presentación de InfoQ sobre "protocolo asincrónico", arquitectura HBase, papel MapReduce, papel Amazon Dynamo que comenzó todo el material NoSQL, colas, clustering de alta disponibilidad rabbitmq)

Espero haber pensado en algo :). También puedes seguirme en Twitter @henrikfeldt si quieres tuits sobre estas cosas.

Henrik
fuente
1

Bien, aquí hay otro punto de vista sobre la escalabilidad.

Analicemos lo que significa que las cosas sean datos, lo que significa tener comportamiento y lo que significa tener lógica de aplicación.

Normalmente, cuando uno se aventura en la tierra de las aplicaciones empresariales y similares, uno estaría expuesto a la idea de estratificación. Por supuesto, las capas están en todas partes en las computadoras, como en la pila de red (modelo ISO), o en gráficos (Photoshop) o en SOA (los servicios pueden llamar a hermanos o hijos, pero nunca a padres).

Sin embargo, el tipo específico de capas que se ha abusado sin importar lo que sea es la 'GUI', 'Business Logic Layer' y luego 'Data Access Layer'. Quiero decir, sí, la idea es buena en principio, como el comunismo es bueno en principio, pero en realidad no lo es.

Echemos un vistazo a por qué. El argumento que voy a usar es sobre el acoplamiento; puntos de una capa que toca puntos en otra capa. Cada vez que comienzas a crear una aplicación en capas de n niveles en el modo empresarial predeterminado en el que las personas entran, crean tantos puntos de contacto entre las capas.

En esencia, la idea es que las capas son intercambiables; pero no lo son! ¿Por qué? Debido a todo el acoplamiento del sitio de llamada.

En cambio, eche un vistazo a por qué la red está desacoplada. ¡Porque la interfaz es una secuencia de bytes sobre un único puntero de archivo que apunta a un socket abierto! ¡Todas las capas en los modelos ISO son como lo que el patrón de diseño llamado 'cadena de responsabilidad' es la orientación a objetos! Cada capa envuelve la capa subyacente, sin conocer la semántica de los datos en esa capa subyacente.

A medida que un paquete de datos se dirige hacia Ethernet y señales eléctricas sin procesar en la parte inferior, se envuelve continuamente por capas que solo conocen su propio sobre de mensaje específico, su propio "lote de bytes" específico que puede enviar; y nada más. No es necesario alterar las rutas de llamadas en función del contenido del paquete.

Compare esto con el n-tier donde tendría que alterar la ruta de llamada en las capas de su aplicación en una 'llamada' que atraviesa sus capas en su camino a la base de datos; por ejemplo, los 'clientes de oro' son polimórficamente un superconjunto de 'clientes normales' y, como usamos 'tabla por subclase', necesitamos saber sobre esto ahora que los datos (entidad) están atravesando las capas; tanto en la llamada 'capa de lógica de negocios' como en la capa de datos que realmente está guardando.

No es escalable ni óptimo desde una perspectiva informática.

¿Por qué no es escalable? ¡Debido a que la arquitectura está acoplada, y aún está dentro del mismo DB antiguo que estaba tratando de escalar a muchos nodos! Pero, debido a que necesita ACID para esto, ¡eso y una tercera entidad (objeto de datos) necesita tenerlos en una única base de datos que realice transacciones!

Correcto, así que con ese despotricar fuera del camino; ¿Qué otras formas hay?

Bueno, existe el acrónimo odiado llamado 'SOA', es decir, arquitectura orientada a servicios. Por supuesto, el Tomas Erls del mundo , tendría que implementar todas sus capas pero con XML y SOAP.

Por todas las razones anteriores, esta es la manera incorrecta de hacerlo, ya que te estarías acoplando a esos proxies XML al igual que te unirías a las capas de la aplicación como se explicó anteriormente.

En su lugar, use la mensajería y deje que lo que implemente la funcionalidad para ellos, escúchelos. Su superficie de servicio se convierte en una lista de mensajes que puede enviar y no ha acoplado sus operaciones a su fachada de servicio; y ni siquiera necesita saber qué aplicación o punto final implementan estas operaciones, ¡porque todo lo que está haciendo es publicar un mensaje de que algún otro mecanismo de enrutamiento se enrutará al consumidor correcto!

Debido a que ha desacoplado las fachadas de servicios de las operaciones reales que desea realizar, ahora puede agregar múltiples servicios; de hecho, así es como lo hace Netflix. Eche un vistazo a estas presentaciones: http://www.slideshare.net/adrianco/global-netflix-platform . http://www.slideshare.net/adrianco/global-netflix-platform . ¡Ellos son buenos!

Henrik
fuente
0

Hay una nueva base de datos SQL (ACID) en beta que se afirma que tiene propiedades de escalado elástico. Ahora hay un programa beta gratuito y le sugiero que eche un vistazo, se llama NuoDB.

Aparentemente, supera fácilmente a MySQL incluso en una sola máquina de subprocesos, pero se escala felizmente a más de 70 instancias en ciertos puntos de referencia.

Dibbeke
fuente
Un solo hilo? ¿Cómo es entonces un punto de referencia relevante?
Henrik