sql server - supported - Diseño arquitectónico para la coherencia de los datos en el sistema analítico distribuido
sincronizar bases de datos sql server (3)
Gracias a todos por su ayuda.
Como creo que este es un problema que podría ser habitual en otros escenarios, me gustaría compartir la solución que elegimos.
Pensando más en detalle sobre el problema, lo entendí por lo que realmente es.
- Necesitaba algún tipo de control de sesión para cada trabajo
- Hubo un proceso en caché que sirvió como control de sesión para cada trabajo
Ahora el cálculo ha evolucionado para ser distribuido, solo necesitaba evolucionar mi caché para distribuirlo también.
Para hacer eso, elegimos utilizar una base de datos en memoria (hash-value), implementada como un servidor separado. (en este caso Redis ).
Ahora, cada vez que comienzo un trabajo, creo una identificación para el trabajo y la paso a sus mensajes
Cuando cada trabajador desea información de la base de datos, debería:
- Busque los datos en Redis (con la identificación del trabajo)
- Si los datos están en Redis, usa los datos
- Si no es así, cárguelo de SQL y guárdelo en redis (con la ID del trabajo).
Al final del trabajo, borro todos los hashes asociados con la identificación del trabajo.
Estoy refacturando un sistema analítico que hará muchos cálculos, y necesito algunas ideas sobre posibles diseños arquitectónicos para un problema de coherencia de datos que estoy enfrentando.
Arquitectura actual
Tengo un sistema basado en cola, en el cual las diferentes aplicaciones que lo solicitan crean mensajes que eventualmente son consumidos por los trabajadores.
Cada " Solicitud de solicitud " divide un cálculo grande en piezas más pequeñas que serán enviadas a la cola y procesadas por los trabajadores .
Cuando todas las piezas estén terminadas, la "aplicación solicitante" de origen consolidará los resultados.
Además, los trabajadores consumen información de una base de datos centralizada (SQL Server) para procesar las solicitudes ( Importante: los trabajadores no cambian ningún dato en la base de datos, solo lo consumen ).
Problema
De acuerdo. Hasta aquí todo bien. El problema surge cuando incluimos un servicio web que actualiza la información en la base de datos. Esto puede suceder en cualquier momento, pero es fundamental que cada "gran cálculo" originado en la misma "Aplicación solicitante" vea los mismos datos en la base de datos.
Por ejemplo:
- La aplicación A genera mensajes A1 y A2, enviándolo a la cola
- El trabajador W1 recoge el mensaje A1 para procesarlo.
- El servidor web actualiza la base de datos, cambiando de estado S0 a S1 .
- El trabajador W2 recoge el mensaje A2 para su procesamiento
Simplemente no puedo tener trabajador W2 usando el estado S1 de la base de datos. para que el cálculo completo sea consistente, debe usar el estado S0 anterior.
Pensamientos
Un patrón de bloqueo para evitar que el servidor web cambie la base de datos mientras hay un trabajador consumiendo información del mismo.
- Contras : El bloqueo puede estar activado durante un tiempo prolongado, ya que el cálculo de diferentes "Aplicaciones de solicitud" podría superponerse (A1, B1, A2, B2, C1, B3, etc.).
Crear una nueva capa entre la base de datos y los trabajadores (un servidor que controla la aplicación de caché de db por solicitud)
- Contras : Agregar otra capa puede imponer una sobrecarga significativa (¿quizás?), y es mucho trabajo, ya que tendré que volver a escribir la persistencia de los trabajadores (un montón de código).
Estoy pendiente de la segunda solución, pero no tengo mucha confianza al respecto.
¿Alguna idea brillante? ¿Lo estoy diseñando mal o me falta algo?
OBS:
- Este es un ENORME sistema heredado de 2 niveles (en C #) que estamos tratando de convertir en una solución más escalable con el mínimo esfuerzo posible.
- Cada trabajador potencialmente se ejecuta en diferentes servidores.
¿Puedes versionar tu DB?
Digamos que la solicitud solicitante marca el inicio del cálculo con ct1. Ahora cada mensaje generado por este cálculo está marcado con la misma marca de tiempo.
Y también cada actualización de base de datos marca el estado de la base de datos con la hora de la actualización. Entonces, el estado S0 es a tiempo t0, estado S1 en t1, etc.
Ahora, cuando un trabajador recibe un mensaje, necesita obtener el estado de DB donde el tiempo de actualización es el más grande que es menor o igual al tiempo del mensaje. En su ejemplo, si A1 y A2 están marcados con ct1 y t1> ct1, ambos trabajadores recuperarán S0 y no S1.
Esto significa, por supuesto, que necesita mantener varias versiones en su base de datos. Puede limpiar esas versiones después de un cierto tiempo si sabe que sus cálculos deben haber terminado después de un intervalo de tiempo.
Me gusta la opción 2, especialmente si la cantidad de datos necesarios para el conjunto completo de cálculos no es irrazonablemente grande. Supongo que hay una forma de correlacionar (a través de id) los cálculos que pertenecen al mismo trabajo en general?
Cuando entra el primer mensaje de un conjunto de cálculos, el trabajador que lo recoge consulta la base de datos y todos los datos necesarios para hacer todos los cálculos y crea un almacén de datos temporal. El aspecto que tendría este almacén de datos dependería de muchos factores (tamaño, estructura, etc.), pero podría ser un blob / documento, un conjunto de datos en un esquema relacional (aislado por correlationId), una entrada en un caché de la empresa, etc.
Debería tener cuidado con el caso cuando Trabajador 1 y Trabajador 2 trabajan en el mismo conjunto de cálculos, ya que solo uno de ellos debería crear el almacén de datos, y ambos tendrían que esperar hasta que la tienda esté completamente poblada. proceder.