advanced

Distributed locks caveats

Рассматривайте Redis locks как leases с fencing, timeout, clock, failover и idempotency concerns, а не magic mutex.

Redis lock обычно — lease: `SET resource:lock <token> NX EX <ttl>` — один держатель до истечения TTL. Это не «магический» mutex кластера; корректность зависит от timeout, проверки token, fencing, failover и идемпотентных воркеров.

					// Захват
const token = crypto.randomUUID()
const ok = await redis.set('lock:invoice:9', token, 'NX', 'EX', 30)
if (!ok) throw new Error('busy')

// Освобождение — сравнить token перед DEL (Lua для atomicity)
const script = `
  if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
  else
    return 0
  end`
await redis.eval(script, 1, 'lock:invoice:9', token)
				

| Риск | Смягчение | |------|-----------| | Пауза процесса > TTL | Короткие единицы работы; осторожное продление lease | | Удаление чужого lock | Проверка token в Lua перед DEL | | Дубль после expiry | Idempotency keys; fencing tokens в БД | | Failover теряет exclusivity | Redlock — знать лимиты кластера | | Clock skew | TTL leases вместо wall-clock |

Redlock на нескольких узлах снижает часть split-brain, но сложен и спорен — многие команды предпочитают dedicated coordination или ограничения БД для жёстких инвариантов.

На интервью: не утверждайте «exactly-once» только на Redis; объясните длительность lease, безопасный release и смерть воркера mid-task.

Типовые ошибки: `DEL` без проверки token; длинные критические секции под одним lock; locks без идемпотентности; locks там, где хватит unique constraints или optimistic locking.

Компромисс — низколатентная координация vs хрупкие границы корректности: Redis locks для best-effort распределения работы; жёсткие инварианты — в data store с fencing.

Чеклист:

  • `SET NX EX` с уникальным token.
  • Release через compare-and-del в Lua.
  • Работа под lease короче TTL.
  • Locks вместе с idempotency или fencing.