Implementace distribuovaných zámků v .NET s RedLock.NET
Distribuované zámky zajišťují exkluzivní přístup k kritickým sekcím v systémech s více instancemi služeb. To je aktuální pro mikro služby v Kubernetes, kde pody nebo různé služby soutěží o zdroje. Hlavní cíl – atomické provádění operací, jako je aktualizace klíčových dat v DB nebo volání externích API.
Typické scénáře:
- Změna obchodně kritických hodnot v databázi.
- Odesílání požadavků do regulačních systémů (např. analogy Čestného Znaku).
- Synchronizace mezi pody jednoho mikro služby nebo služebami v orchestraci/choreografii.
Standardní .NET primitivy jako SemaphoreSlim, AsyncLock nebo lock nejsou vhodné kvůli fyzické oddělenosti instancí. Mutex funguje na Windows, ale je problematický v asynchronním kódu a Docker kontejnerech.
Přehled RedLock.NET
RedLock.NET – knihovna pro implementaci algoritmu RedLock na .NET. Poslední stabilní verze 2.3.2 (2022). Balíček prošel bezpečnostní kontroly, bez známých zranitelností. Autor aktivně řeší issues na GitHub.
Algoritmus RedLock využívá Redis cluster pro distribuované zámky s TTL a zajišťuje bezpečnost i při síťových selháních. Knihovna zapouzdřuje logiku: vytváření, prodlužování a mazání zámků.
Alternativy: zámky přes DB
Tabulka locks v PostgreSQL
Klasický přístup – speciální tabulka pro zámky:
CREATE TABLE locks (
resource VARCHAR(100) PRIMARY KEY,
locked_by VARCHAR(100),
locked_at TIMESTAMPTZ DEFAULT NOW(),
expires_at TIMESTAMPTZ
);
Atomární INSERT se zpracováním konfliktů:
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;
Logika:
- Pokud zámek neexistuje – vytvoří se nový s TTL.
- Pokud zámek vypršel – aktualizuje se.
- Pokud je aktivní – vrátí prázdný výsledek.
Požadavky:
- Unikátní
resourcepro operaci. - Unikátní
locked_by(GUID nebo instance ID + thread ID).
Úrovně izolace
SERIALIZABLE zajišťuje atomárnost bez dalších tabulek, ale snižuje propustnost. V enterprise prostředí DBA zřídka schválí kvůli zátěži. Upřednostňují se UPSERT přístupy s READ COMMITTED.
Srovnání přístupů
| Přístup | Výhody | Nevýhody |
|--------------|---------------------------------|---------------------------------------|
| .NET primitivy | Jednoduchost, nízká latence | Pouze single instance |
| Mutex | Sync na úrovni OS | Ne pro Docker/Linux, async problémy |
| DB zámky | Integrace s DB | Overhead na DB, problémy se škálováním|
| RedLock.NET | Vysoká dostupnost, TTL | Závislost na Redis |
DB zámky jsou vhodné pro jednoduché případy s nízkou frekvencí. RedLock.NET – pro systémy s vysokým zatížením se zárukami.
Praktická implementace RedLock.NET
Instalace: dotnet add package RedLock.net. Vytvořte RedLockFactory s Redis endpoints:
var multiplexer = new ConnectionMultiplexer(...);
var factory = RedLockFactory.Create(...);
using var @lock = await factory.CreateLockAsync(resource, expiry);
if (@lock.IsAcquired) {
// critical section
}
Klíčové parametry:
resource: řetězec-identifikátor (key v Redis).expiry:TimeSpanpro TTL.- Quorum: většina Redis nodů pro konsenzus.
Zpracování selhání: knihovna automaticky prodlužuje zámek při dlouhých operacích prostřednictvím IExtensibleLock.
Škálování a best practices
- Používejte Redis Sentinel nebo Cluster pro HA.
- Clock drift < 10ms mezi nodami.
- Doba platnosti > 2x clock drift + doba operace.
- Monitorujte míru selhání získání zámku.
V produkci kombinujte s circuit breaker pro externí volání v kritické sekci.
Co je důležité
- RedLock.NET zajišťuje bezpečnost založenou na quoru bez single point of failure.
- DB zámky jsou jednodušší, ale zranitelné vůči přetížení DB a neshkálovatelné.
- Vždy nastavte TTL pro ochranu před zombie zámky.
- Testujte pod zátěží se simulací síťového oddělení.
- Pro .NET Core+ se vyhněte Mutex v kontejnerech.
— Editorial Team
Zatím žádné komentáře.