Necesito un mecanismo de bloqueo de objetos recursivos personalizado \ patrón para un sistema distribuido en C #. Básicamente, tengo un sistema de múltiples nodos. Cada nodo tiene permisos de escritura exclusivos sobre n -número de piezas de estado. El mismo estado también está disponible en forma de solo lectura en al menos otro nodo. Algunas escrituras / actualizaciones deben ser atómicas en todos los nodos, mientras que otras actualizaciones eventualmente se volverán consistentes a través de procesos de replicación en segundo plano, colas, etc.
Para las actualizaciones atómicas, estoy buscando un patrón o muestras que me permitan marcar de manera eficiente un objeto como bloqueado para escrituras que luego pueda distribuir, confirmar, revertir, etc. Como el sistema tiene altos niveles de concurrencia, yo Supongo que tendré que ser capaz de acumular bloqueos que se agotarán o se desenrollarán una vez que se liberen los bloqueos.
La transacción o las piezas de mensajería no son el foco de esta pregunta, pero las proporcioné para un contexto adicional. Dicho esto, siéntase libre de articular qué mensajes cree que serían necesarios si lo desea.
Aquí hay una muestra vaga de lo que estaba imaginando, aunque estoy abierto a cualquier idea nueva además de implementar productos completamente nuevos.
thing.AquireLock(LockLevel.Write);
//Do work
thing.ReleaseLock();
Estaba pensando en usar métodos de extensión, que podrían verse más o menos así
public static void AquireLock(this IThing instance, TupleLockLevel lockLevel)
{
//TODO: Add aquisition wait, retry, recursion count, timeout support, etc...
//TODO: Disallow read lock requests if the 'thing' is already write locked
//TODO: Throw exception when aquisition fails
instance.Lock = lockLevel;
}
public static void ReleaseLock(this IThing instance)
{
instance.Lock = TupleLockLevel.None;
}
Para aclarar un par de detalles ...
- Todas las comunicaciones son TCP / IP utilizando un protocolo binario de solicitud / respuesta
- No existen tecnologías intermedias como colas o bases de datos.
- No hay un nodo maestro central. En este caso, la disposición de bloqueo está definida por el iniciador de la cerradura y el socio que atenderá la solicitud con algún tipo de tiempo de espera para regular su comportamiento
¿Alguien tiene alguna sugerencia?
Respuestas:
Gracias por las aclaraciones.
En ese caso, lo que recomendaría es usar un modelo de publicación / suscripción. Protocolo de bloqueo distribuido Chubby de Google (una implementación de Paxos )
Nunca he usado Paxos (o Chubby), pero parece que hay una implementación de código abierto aquí .
Si eso no funciona, puede implementar su propia versión de Paxos utilizando, por ejemplo, uno de los sospechosos habituales en términos de bibliotecas de mensajes: la biblioteca de cola de mensajes cero , RabbitMQ o ActiveMQ .
Respuesta anterior:
La mayoría de las sugerencias sobre SO ( [A] , [B] ) se utilizan para utilizar una cola de mensajes para lograr el bloqueo entre máquinas.
Su
AcquireLock
método empujaría algo que identifica el objeto de bloqueo en la cola, verificando instancias anteriores de bloqueos antes del éxito. SuReleaseLock
método eliminaría el objeto de bloqueo de la cola.El usuario de SO atlantis sugiere, en esta publicación , la publicación de Jeff Key para algunos detalles.
fuente
Me parece que tienes un par de tecnologías mixtas aquí:
comunicaciones (en las que confía esencialmente como 100% confiables ... que pueden ser fatales)
bloqueo / exclusión mutua
tiempos de espera (con qué propósito)?
Una advertencia: los tiempos de espera en los sistemas distribuidos pueden estar llenos de peligros y dificultades. Si se usan, deben configurarse y usarse con mucho cuidado porque el uso indiscriminado de los tiempos de espera no soluciona un problema, solo retrasa la catástrofe. (Si desea ver cómo se deben usar los tiempos de espera , lea y comprenda la documentación del protocolo de comunicación HDLC. Este es un buen ejemplo de uso adecuado e inteligente, en combinación con un sistema inteligente de codificación de bits para permitir la detección de cosas como la línea IDLE) .
Durante un tiempo trabajé en sistemas distribuidos multiprocesador conectados mediante enlaces de comunicación (no TCP, algo más). Una de las cosas que aprendí fue que, como una generalización aproximada, hay algunos lugares peligrosos de programación múltiple para ir:
depender de las colas generalmente termina en lágrimas (si la cola se llena, usted está en problemas. A MENOS QUE pueda calcular un tamaño de cola que nunca se llenará, en cuyo caso probablemente podría usar una solución sin cola)
la dependencia del bloqueo es dolorosa, intente y piense si hay otra forma (si debe usar el bloqueo, consulte la literatura, el bloqueo distribuido multiprocesador ha sido el tema de muchos documentos académicos de las últimas 2-3 décadas)
Tengo que proceder usando el bloqueo, luego:
ASUMIRÉ que usará los tiempos de espera solo como un medio de recuperación de último recurso, es decir, para la detección de una falla del sistema de comunicaciones subyacente. Asumiré además que su sistema de comunicación TCP / IP tiene un ancho de banda alto y puede considerarse como una latencia baja (idealmente cero, pero esto nunca sucede).
Lo que sugeriría es que cada nodo tiene una lista de conectividad de otros nodos a los que se puede conectar. (A los nodos no les importaría de dónde proviene una conexión). La población de las tablas a las que se puede conectar un nodo se deja como una cosa separada para resolver, no ha dicho si eso se establecería estáticamente o no. También se ignoran convenientemente cosas como la asignación de los números de puerto IP donde las conexiones entrarían en un nodo; puede haber buenas razones para aceptar solicitudes en un solo puerto o en múltiples puertos. Esto debe ser considerado cuidadosamente. Los factores incluirán colas implícitas, pedidos, uso de recursos, tipo de sistema operativo y capacidades.
Una vez que los nodos saben con quién se conectan, pueden enviar a ese nodo una solicitud de bloqueo y deben recibir una respuesta de bloqueo desde ese nodo remoto. Puede empaquetar esas dos operaciones en un contenedor para que parezca atómico. El efecto de esto es que los nodos que desean adquirir un bloqueo harán una llamada algo así como:
las llamadas get_lock y release_lock deberían ser algo así (en principio):
Deberá tener mucho cuidado con un sistema de bloqueo distribuido para que las unidades de trabajo realizadas mientras se mantiene un bloqueo sean pequeñas y rápidas porque tendrá muchos nodos remotos potencialmente retenidos esperando obtener un bloqueo. Este es efectivamente un sistema multiprocesador / comunicación de parada y espera que es robusto pero no tiene el rendimiento más alto posible.
Una sugerencia es adoptar un enfoque completamente diferente. ¿Puede usar una llamada a procedimiento remoto donde cada llamada RPC lleva un paquete de información que puede ser manejado por el destinatario y que elimina la necesidad de bloqueos?
Al volver a leer la pregunta, parece que realmente no desea preocuparse por el lado de la comunicación de las cosas, solo desea resolver su problema de bloqueo.
Por lo tanto, mi respuesta puede parecer un poco fuera de tema, sin embargo, creo que no puede resolver su problema de bloqueo sin tener las partes debajo también. Analogía: construir una casa sobre cimientos malos hace que se caiga ... Eventualmente.
fuente
Su pregunta puede implementarse fácilmente utilizando un caché distribuido como NCache. Lo que necesita es un mecanismo de bloqueo pesimista en el que pueda adquirir un bloqueo con un objeto. Luego realice sus tareas y operaciones y libere el bloqueo para que otras aplicaciones lo consuman más adelante.
Echa un vistazo al siguiente código;
Aquí adquiriría un bloqueo en una Clave específica y luego realizaría tareas (que van desde una o más operaciones) y finalmente liberaría el bloqueo cuando haya terminado.
Tomado del enlace: http://blogs.alachisoft.com/ncache/distributed-locking/
fuente