Saltar al contenido principal

Una publicación etiquetados con "distributed-locks"

Ver Todas las Etiquetas

Bloqueos Distribuidos Explicados

· 5 min de lectura
Clustron Team
Ingeniería de Sistemas Distribuidos

Una guía práctica para desarrolladores de .NET

Introducción​

A medida que las aplicaciones escalan a través de varias máquinas, la coordinación se convierte en uno de los aspectos más desafiantes del diseño de sistemas.

En una aplicación de una sola máquina, la exclusión mutua es sencilla. Los desarrolladores pueden apoyarse en primitivas del lenguaje como lock en C#, Mutex o Semaphore para garantizar que solo un hilo acceda a un recurso compartido a la vez.

Sin embargo, estas primitivas solo funcionan dentro de un único proceso o máquina.

Una vez que las aplicaciones se ejecutan en varios servicios o nodos, los mecanismos de bloqueo tradicionales dejan de funcionar. Dos servicios que se ejecutan en diferentes máquinas no pueden apoyarse en una instrucción lock local para coordinar el acceso a un estado compartido.

Aquí es donde los bloqueos distribuidos se vuelven esenciales.

Los bloqueos distribuidos permiten que los servicios de un clúster coordinen el acceso a recursos compartidos garantizando al mismo tiempo que solo un participante mantenga el bloqueo en un momento dado.


Bloqueos locales frente a bloqueos distribuidos​

Un bloqueo local típico en C# tiene este aspecto:

private static readonly object _lock = new object();

public void ProcessOrder()
{
lock(_lock)
{
Console.WriteLine("Processing order safely.");
}
}

Esto funciona perfectamente dentro de un único proceso.

Sin embargo, si tu aplicación se ejecuta en varias instancias de servicio, cada instancia tiene su propio objeto _lock. El bloqueo ya no coordina el trabajo en todo el sistema.

Worker A → lock acquired Worker B → lock acquired Worker C → lock acquired

Todos los trabajadores proceden simultáneamente, lo que anula el propósito del bloqueo.

Los sistemas distribuidos requieren un mecanismo de coordinación compartido.


Bloqueo Distribuido


La idea detrás de los bloqueos distribuidos​

Un bloqueo distribuido utiliza un sistema compartido para representar la propiedad del bloqueo.

En lugar de bloquear la memoria, un nodo registra la propiedad del bloqueo en un sistema de coordinación distribuida como:

  • un almacén clave‑valor distribuido
  • un servicio de coordinación
  • una caché distribuida

Concepto de ejemplo:

Lock Key: order:123 Owner: worker‑1

Si otro trabajador intenta adquirir el mismo bloqueo, la operación falla hasta que el bloqueo se libera o expira.


Escenario del mundo real: procesamiento distribuido de facturas​

Imagina un clúster de trabajadores que procesan facturas.

Worker A Worker B Worker C

Todos los trabajadores buscan facturas pendientes.

Sin bloqueo:

Worker A → processes invoice #101 Worker B → processes invoice #101 Worker C → processes invoice #101

La misma factura podría procesarse varias veces.

Un bloqueo distribuido garantiza que solo un trabajador procese la factura.


Bloqueos distribuidos con Clustron DKV​

Clustron DKV proporciona primitivas integradas para la coordinación distribuida.

Los bloqueos se gestionan a través de la API de bloqueos (Locks API), y las operaciones sobre claves bloqueadas deben incluir el identificador de bloqueo (lock handle) correcto.


Adquirir un bloqueo​

Un cliente adquiere primero un bloqueo para una clave específica.

var locks = ((IDkv)client).Locks;

var key = "order:123";

var lockHandle = await locks.AcquireAsync(key, TimeSpan.FromSeconds(10));

if (lockHandle == null)
{
Console.WriteLine("Failed to acquire lock.");
return;
}

Console.WriteLine("Lock acquired.");

El identificador de bloqueo devuelto representa la propiedad del bloqueo.


Realizar operaciones bajo el bloqueo​

Una vez adquirido un bloqueo, las operaciones deben incluir el identificador de bloqueo.

var result = await client.PutAsync(
key,
"processed",
Put.WithLock(lockHandle.Handle));

if (result.IsSuccess)
{
Console.WriteLine("Value updated safely.");
}

Solo el propietario del bloqueo puede modificar el valor.


Lectura con el bloqueo​

Las lecturas también pueden respetar la propiedad del bloqueo.

var value = await client.GetAsync<string>(
key,
Get.WithLock(lockHandle.Handle));

if (value.IsSuccess)
{
Console.WriteLine($"Value: {value.Value}");
}

Operaciones en competencia sin el bloqueo​

Si otro trabajador intenta modificar la clave sin el bloqueo, la operación falla.

var attempt = await client.PutAsync(key, "new-value");

if (!attempt.IsSuccess)
{
Console.WriteLine($"Operation rejected: {attempt.Status}");
}

Resultado:

KvStatus.Locked

Esto evita la modificación concurrente del mismo recurso.


Liberar el bloqueo​

Una vez finalizado el trabajo, el bloqueo puede liberarse.

await lockHandle.ReleaseAsync();

Console.WriteLine("Lock released.");

Después de liberar el bloqueo, otro trabajador puede adquirirlo.


Flujo de trabajo de ejemplo en el clúster​

Worker A → Acquire Lock → Success Worker B → Acquire Lock → Failed Worker C → Acquire Lock → Failed

Worker A → Update Key Worker A → Release Lock

Solo un trabajador realiza la operación, lo que garantiza la corrección.


Gestión de fallos​

Los bloqueos en Clustron tienen un límite de tiempo.

Al adquirir un bloqueo, debe especificarse una duración:

await locks.AcquireAsync(key, TimeSpan.FromSeconds(10));

Si el cliente que mantiene el bloqueo se bloquea o se desconecta, el bloqueo expira finalmente, lo que permite que otro trabajador lo adquiera.

Esto evita que los bloqueos permanezcan retenidos de forma permanente.


Buenas prácticas​

Al implementar bloqueos distribuidos:

  • Mantén las secciones críticas cortas
  • Evita los bloqueos globales cuando sea posible
  • Particiona los bloqueos por recurso
  • Diseña siempre pensando en los escenarios de fallo

Reflexiones finales​

Los bloqueos distribuidos son una de las primitivas de coordinación más fundamentales en los sistemas distribuidos.

Permiten que los servicios que se ejecutan en varias máquinas coordinen de forma segura el acceso a recursos compartidos preservando al mismo tiempo la corrección del sistema.

Plataformas como Clustron DKV lo simplifican proporcionando primitivas de bloqueo integradas, operaciones atómicas y sólidas garantías de consistencia.

En el próximo artículo, exploraremos otra primitiva esencial de los sistemas distribuidos:

La Elección de Líder.