분산 락(Distributed Lock)은 분산 환경에서 여러 노드/프로세스가 공유 자원에 동시 접근하지 못하도록 상호 배제를 구현하는 메커니즘이다. 재고 차감, 유일성 보장, 배치 작업 중복 실행 방지 등에 활용된다.
분산 락이 필요한 상황
단일 서버:
프로세스 A: 재고 조회 → 재고 감소 (문제 없음)
분산 서버:
서버1: 재고 100 조회
서버2: 재고 100 조회 (동시!)
서버1: 재고 99로 업데이트
서버2: 재고 99로 업데이트 (갱신 손실!)
SETNX (가장 단순한 방법)
python
import redis, time, uuid
r = redis.Redis()
def acquire_lock(resource: str, ttl: int = 10) -> str | None:
lock_id = str(uuid.uuid4())
# SET resource lock_id NX PX ttl (원자적 작업)
result = r.set(f"lock:{resource}", lock_id, nx=True, px=ttl * 1000)
return lock_id if result else None
def release_lock(resource: str, lock_id: str) -> bool:
# Lua 스크립트: 자신이 잠근 락만 해제 (원자적)
script = """
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
"""
return bool(r.eval(script, 1, f"lock:{resource}", lock_id))
# 사용 예시
lock_id = acquire_lock("order:product-123")
if lock_id:
try:
# 임계 구역
process_order("product-123")
finally:
release_lock("order:product-123", lock_id)
단일 Redis 노드 장애 대비, Redis 클러스터 과반수를 이용한다.
N개의 독립적인 Redis 인스턴스:
1. 현재 시간 기록
2. N개 인스턴스에 순서대로 락 획득 시도
3. 과반수(N/2+1) 성공 + 소요 시간 < TTL → 락 획득 성공
4. 실패 시 모든 인스턴스에서 락 해제
ZooKeeper 기반 분산 락
공정한(Fair) 잠금을 보장한다. 각 락 요청이 Ephemeral Sequential 노드를 생성하고, 가장 작은 번호가 락을 획득한다.
펜싱 토큰(Fencing Token)
락 갱신 실패 시 구 잠금 보유자의 요청을 거부하기 위한 단조 증가 토큰이다.
락 획득 → 토큰 10 발급
토큰 10으로 DB 쓰기 → 서버에 현재 토큰 11 → 거부! (구 토큰)
관련 개념