Volver al inicio

RedLock.NET: bloqueos distribuidos en .NET

El artículo describe la implementación de bloqueos distribuidos en .NET usando RedLock.NET y alternativas vía PostgreSQL. Se comparan primitivas estándar, Mutex, bloqueos DB. Se proporcionan ejemplos SQL y mejores prácticas para microservicios en Kubernetes.

Bloqueos distribuidos en .NET: RedLock vs enfoques DB
Advertisement 728x90

Implementación de bloqueos distribuidos en .NET con RedLock.NET

Los bloqueos distribuidos proporcionan acceso exclusivo a secciones críticas en sistemas con múltiples instancias de servicios. Esto es crucial para microservicios en Kubernetes, donde los pods o diferentes servicios compiten por recursos. El objetivo principal es la ejecución atómica de operaciones, como actualizar datos clave en la BD o llamar a APIs externas.

Escenarios típicos:

  • Cambiar valores críticos para el negocio en la base de datos.
  • Enviar solicitudes a sistemas reguladores (p. ej., análogos de Chestny Znak).
  • Sincronización entre pods del mismo microservicio o servicios en orquestación/coreografía.

Las primitivas estándar de .NET como SemaphoreSlim, AsyncLock o lock no son adecuadas debido a la separación física de las instancias. Mutex funciona en Windows, pero es problemático en código asíncrono y contenedores Docker.

Google AdInline article slot

Resumen de RedLock.NET

RedLock.NET es una biblioteca para implementar el algoritmo RedLock en .NET. La versión estable más reciente es la 2.3.2 (2022). El paquete ha pasado las verificaciones de seguridad sin vulnerabilidades conocidas. El autor mantiene activamente los problemas en GitHub.

El algoritmo RedLock utiliza un clúster de Redis para bloqueos distribuidos con TTL, garantizando la seguridad incluso durante fallos de red. La biblioteca encapsula la lógica para crear, extender y liberar bloqueos.

Alternativas: Bloqueos vía base de datos

Tabla de bloqueos en PostgreSQL

El enfoque clásico es una tabla dedicada para bloqueos:

Google AdInline article slot
CREATE TABLE locks (
    resource VARCHAR(100) PRIMARY KEY,
    locked_by VARCHAR(100),
    locked_at TIMESTAMPTZ DEFAULT NOW(),
    expires_at TIMESTAMPTZ
);

Inserción atómica con manejo de conflictos:

INSERT INTO locks (resource, locked_by, expires_at)
VALUES (@resource, @locked_by, NOW() + (@timespan || ' seconds')::interval)
ON CONFLICT (resource) DO UPDATE
SET locked_by = EXCLUDED.locked_by,
    expires_at = EXCLUDED.expires_at
WHERE locks.expires_at < NOW()
RETURNING locked_by;

Lógica:

  • Si el bloqueo no existe, se crea uno nuevo con TTL.
  • Si el bloqueo ha expirado, se actualiza.
  • Si está activo, se devuelve un resultado vacío.

Requisitos:

Google AdInline article slot
  • resource único por operación.
  • locked_by único (GUID o ID de instancia + ID de hilo).

Niveles de aislamiento

SERIALIZABLE garantiza la atomicidad sin tablas adicionales, pero reduce el rendimiento. En entornos empresariales, los DBA rara vez lo aprueban debido a la carga. Se prefieren enfoques UPSERT con READ COMMITTED.

Comparación de enfoques

| Enfoque | Ventajas | Desventajas |

|--------|-------|--------|

| Primitivas de .NET | Simplicidad, baja latencia | Solo una instancia |

| Mutex | Sincronización a nivel SO | No para Docker/Linux, problemas asíncronos |

| Bloqueos en BD | Integración con BD | Sobrecarga de BD, problemas de escalabilidad |

| RedLock.NET | Alta disponibilidad, TTL | Dependencia de Redis |

Los bloqueos en BD funcionan bien para casos simples con baja frecuencia. RedLock.NET es ideal para escenarios de alta carga con garantías sólidas.

Implementación práctica de RedLock.NET

Instalación: dotnet add package RedLock.net. Crea una RedLockFactory con endpoints de Redis:

var multiplexer = new ConnectionMultiplexer(...);
var factory = RedLockFactory.Create(...);
using var @lock = await factory.CreateLockAsync(resource, expiry);
if (@lock.IsAcquired) {
    // critical section
}

Parámetros clave:

  • resource: identificador de cadena (clave de Redis).
  • expiry: TimeSpan para TTL.
  • Quórum: mayoría de nodos de Redis para consenso.

Manejo de fallos: la biblioteca extiende automáticamente los bloqueos para operaciones de larga duración mediante IExtensibleLock.

Escalado y mejores prácticas

  • Usa Redis Sentinel o Cluster para HA.
  • Desviación de reloj < 10 ms entre nodos.
  • Tiempo de validez > 2x desviación de reloj + tiempo de operación.
  • Monitorea la tasa de fallos en adquisición de bloqueos.

En producción, combínalo con interruptores de circuito para llamadas externas en secciones críticas.

Conclusiones clave

  • RedLock.NET proporciona seguridad basada en quórum sin punto único de fallo.
  • Los bloqueos en BD son más simples, pero vulnerables a sobrecarga de BD y no escalan.
  • Siempre establece TTL para proteger contra bloqueos zombis.
  • Prueba bajo carga con simulaciones de particiones de red.
  • Para .NET Core y posteriores, evita Mutex en contenedores.

— Editorial Team

Advertisement 728x90

Leer después