2011-01-31 8 views
5

Un poco común de la lógica de programación me encuentro a menudo la implementación es algo como el siguiente pseudo-código:Sincronización de base de datos Access en una Distributed App

Let X = some value 
Let Database = some external Database handle 

if !Database.contains(X): 
    SomeCalculation() 
    Database.insert(X) 

Sin embargo, en un programa multi-hilo que tiene una condición de carrera aquí. El hilo A podría verificar si X está en Database, encuentra que no es así, y luego procede a llamar al SomeCalculation(). Mientras tanto, el hilo B también verificará si X está en Database, encuentra que no es así, e inserta una entrada duplicada.

Así que, por supuesto, esto debe ser sincronizado como:

Let X = some value 
Let Database = some external Database handle 

LockMutex() 
if !Database.contains(X): 
    SomeCalculation() 
    Database.insert(X) 
UnlockMutex() 

Esto está bien, excepto lo que si la aplicación es una aplicación distribuida, se ejecuta en varios equipos, todos los cuales se comunican con la misma fuente Back máquina de base de datos final? En este caso, un Mutex es inútil, ya que solo sincroniza una sola instancia de la aplicación con otros subprocesos locales. Para que esto funcione, necesitaríamos algún tipo de técnica de sincronización distribuida "global". (Suponga que simplemente no permitir duplicados en Database no es una estrategia factible.)

En general, ¿cuáles son algunas soluciones prácticas para este problema?

que dan cuenta de esta pregunta es muy genérica , pero no quiero hacer de esto una cuestión específica del idioma ya que este es un problema que surge a través de múltiples idiomas y múltiples tecnologías de bases de datos.

evitaba intencionalmente especificar si estoy hablando de un RDBMS o base de datos SQL, frente a algo así como una base de datos NoSQL, porque una vez más - Busco respuestas generalizadas en base a prácticas de la industria. Por ejemplo, ¿es esta situación algo que los Procedimientos almacenados atómicos podrían resolver? ¿O transacciones atómicas? ¿O es algo que requiere algo así como un "Mutex distribuido"? O, de manera más general, ¿este problema generalmente es abordado por el sistema de la base de datos, o es algo que la aplicación en sí debería manejar?

Si resulta que esta pregunta es imposible para responder en absoluto sin más información, dígame para que pueda modificarla.

Respuesta

0

Obviamente puede mover la parte "sincronizada" a la capa DB misma, utilizando un bloqueo exclusivo en un recurso específico.

Esto es un poco extremo (en la mayoría de los casos, intentar insertar y administrar la excepción cuando descubres que alguien ya insertó la fila) sería más adecuado, creo.

2

Una forma segura de evitar el pisada de datos es bloquear la fila de datos. Muchas bases de datos le permiten hacer eso, a través de transacciones. Algunos no admiten transacciones.

Sin embargo, esto es excesivo para la mayoría de los casos, donde la contención es baja en general. Es posible que desee leer en Isolation levels para obtener más información sobre el tema.

Un mejor enfoque general suele ser Optimistic Concurrency. La idea detrás de esto es que cada fila de datos incluye una firma, una marca de tiempo funciona bien, pero la firma no necesita estar orientada al tiempo. Podría ser un valor hash, por ejemplo. Este es un enfoque de administración de concurrencia general y no está limitado a tiendas relacionales.

La aplicación que cambia los datos lee primero la fila, y luego realiza los cálculos de lo que requiere, y entonces en algún momento, escribe los datos actualizados con el almacén de datos. A través de la concurrencia optimista, la aplicación escribe la actualización con la estipulación (expresada en SQL si es una base de datos SQL) que la fila de datos debe actualizarse solo si la firma no ha cambiado en el ínterin. Y, cada vez que se actualiza una fila de datos, también se debe actualizar la firma.

El resultado es que las actualizaciones no se pisotean. Pero para una explicación más rigurosa de los problemas de simultaneidad, consulte ese artículo sobre los niveles de Aislamiento DB.

Todos los actualizadores distribuidos deben seguir la convención de OCC (o algo más fuerte, como bloqueo transaccional) para que esto funcione.

0

Bueno, ya que preguntas una pregunta general, voy a tratar de ofrecer otra opción. No es muy ortodoxo, pero puede ser útil: podría "definir" una máquina o un proceso responsable de hacer eso. Por ejemplo:

Let X = some value 
Let Database = some external Database handle 

xResposible = Definer.defineResponsibleFor(X); 

if(xResposible == me) 
    if !Database.contains(X): 
     SomeCalculation() 
     Database.insert(X) 

El truco aquí es hacer defineResponsibleFor siempre devuelven el mismo valor independientemente de quién está llamando. Entonces, si tiene un rango distribuido equitativo de X y un Definer justo, todas las máquinas tendrán trabajo por hacer. Y podría usar un mutex simple para evitar las condiciones de carrera. Por supuesto, ahora tiene que encargarse de la tolerancia a fallas (si una máquina o proceso está fuera del negocio, su definidor debe saber y no definir ningún trabajo para ello). Pero deberías hacer esto anyawy ... :)

Cuestiones relacionadas