핵심 인사이트
- DLM(Distributed Lock Manager)은 분산 시스템에서 여러 노드가 공유 자원에 대한 접근 순서와 일관성을 조율하는 핵심 미들웨어 — 단일 서버의 뮤텍스/세마포어가 분산 환경으로 확장된 개념이며, 클러스터 파일시스템(GFS, OCFS2)의 핵심 구성 요소다.
- DLM의 핵심 과제는 CAP 트릴레마와 장애 시나리오 — 네트워크 분단(Partition) 시 일관성(Consistency)과 가용성(Availability) 중 하나를 포기해야 하며, "잠금 보유자 장애 시 잠금 해제"가 구현 난이도의 핵심이다.
- Redis/ZooKeeper/etcd 기반 분산 잠금이 현대 클라우드 환경의 실용적 선택 — 각각 Redlock(Redis), curator(ZooKeeper), etcd의 lease 기반으로 구현되며, 잠금 유효 시간(TTL)과 Fencing Token이 안전한 분산 잠금의 핵심 패턴이다.
Ⅰ. 분산 잠금 필요성
분산 환경에서의 잠금 문제:
단일 서버:
뮤텍스/세마포어로 임계 구역 보호
OS 커널이 원자적 연산 보장
분산 시스템:
서버 A, B, C가 공유 DB/파일 접근
각 서버의 로컬 잠금으로는 충돌 방지 불가
예시 문제 (분산 재고 관리):
서버 A: 재고 확인(100개) → 구매 처리 시작
서버 B: 재고 확인(100개) → 구매 처리 시작
둘 다 재고 100개로 판단 → 동시 100개씩 판매
→ 실제 재고 100개인데 200개 판매 오류!
분산 잠금으로 해결:
서버 A: 잠금 획득 → 재고 확인/처리 → 잠금 해제
서버 B: 잠금 대기 → A 해제 후 획득 → 처리
DLM 핵심 기능:
1. 잠금 획득/해제 (Lock/Unlock)
2. 잠금 대기 (Blocking/Non-blocking)
3. 잠금 범위 (Resource 식별)
4. 잠금 만료 (TTL: Time-To-Live)
5. 장애 복구 (잠금 보유자 죽었을 때)
6. 재진입 허용 여부 (Reentrant Lock)
📢 섹션 요약 비유: 분산 잠금은 화장실 키 — 건물에 화장실이 하나인데 사용자가 여러 건물에 있어요. 키(잠금)를 받은 사람만 사용. 키 받기 전까지 대기!
Ⅱ. DLM 구현 기술
분산 잠금 구현 방식:
1. Redis 기반 (Redlock):
단일 Redis:
SET lock_key unique_val NX EX 30
(NX: 없을 때만, EX: 30초 TTL)
성공: "OK" 반환 → 잠금 획득
실패: nil → 이미 잠금 존재
해제: Lua 스크립트 (원자적 확인+삭제)
IF GET lock_key == unique_val:
DEL lock_key
Redlock (다중 Redis 노드):
N개 Redis 노드 (홀수, 예: 5개)
과반수(N/2+1) 획득 → 잠금 성공
→ 단일 노드 장애 내성
2. ZooKeeper 기반:
임시 노드(Ephemeral Node) 생성
/locks/resource_A → 잠금 획득
클라이언트 세션 종료 → 임시 노드 자동 삭제
→ 장애 시 자동 잠금 해제
공정한 잠금 (Fair Lock):
순서 노드(Sequence Node) 사용
/locks/resource_A/lock-0001, lock-0002, ...
가장 낮은 번호 = 잠금 보유
자신 앞 번호 watch → 해제 시 알림
3. etcd 기반 (Lease):
Lease 생성: TTL 30초
key 연결: key = lock, lease = leaseID
KeepAlive: 주기적으로 lease 갱신
클라이언트 죽음 → KeepAlive 중단 → 만료 → 삭제
Kubernetes: etcd로 리더 선출 구현
controller-manager, scheduler: etcd 잠금 사용
📢 섹션 요약 비유: DLM 구현 3종 — Redis는 빠른 메모 (NX 명령 원자적), ZooKeeper는 자동 사라지는 포스트잇 (세션 종료 시 임시 노드 삭제), etcd는 타이머 키 (Lease TTL)!
Ⅲ. 잠금 만료와 Fencing Token
잠금 만료(TTL) 문제:
시나리오:
서버 A: 잠금 획득 (TTL 30초)
서버 A: GC 일시 정지 50초 (STW GC)
잠금 만료 → 서버 B가 잠금 획득
서버 A: GC 완료 후 처리 재개 (잠금 없이!)
→ A와 B가 동시에 자원 접근!
문제: "잠금이 만료된 줄 모르고 계속 처리"
해결: Fencing Token
잠금 획득 시 단조 증가 토큰 발급:
서버 A: 잠금 획득, 토큰=33
서버 B: 잠금 획득 (A 만료 후), 토큰=34
자원 서버(DB, 파일 서버):
"이전 토큰보다 작은 요청은 거부"
서버 A 요청 (토큰=33): 서버 DB: 34 이상만 허용 → 거부!
서버 B 요청 (토큰=34): 서버 DB: 허용
단조 토큰 발급:
etcd 트랜잭션 번호 (Revision)
ZooKeeper 트랜잭션 ID (zxid)
Redis INCR 연산 결과
TTL 설정:
너무 짧음: 작업 중 만료 → 재시도 오버헤드
너무 긺: 장애 시 복구 지연 (다음 클라이언트 오래 대기)
실무: 예상 작업 시간 × 3~5배 (충분한 여유)
+ KeepAlive (주기적 갱신)
📢 섹션 요약 비유: Fencing Token은 번호표 규칙 — 33번(A)이 잠들었을 때 34번(B)이 입장. 잠들었다 깬 33번이 "내가 잠금 있어요!" 해도 DB가 "34번 이상만 가능"으로 거부!
Ⅳ. CAP과 분산 잠금
CAP 트릴레마와 잠금 선택:
CAP:
C (Consistency): 모든 노드 동일 데이터
A (Availability): 항상 응답
P (Partition Tolerance): 네트워크 분단 허용
분산 잠금 구현별 선택:
ZooKeeper (CP):
네트워크 분단 시 과반수 노드 없으면 → 서비스 중단
일관성 보장: 항상 최신 잠금 상태
Paxos/ZAB 합의 알고리즘
→ 강한 일관성 + 가용성 부분 포기
etcd (CP):
Raft 합의 알고리즘
과반수 노드 필요
강한 일관성
Redis 단일 노드 (AP):
빠른 응답 (메모리 기반)
복제는 비동기 → 마스터 장애 시 잠금 손실 가능
Redlock (다수 Redis, "CP에 가까운 AP"):
논쟁: Martin Kleppmann "Redlock은 안전하지 않다"
반론: Antirez "Redlock 충분히 안전"
Kleppmann 주장:
- GC 일시 정지 + TTL 만료 조합 = 위험
- Fencing Token 없이는 불완전
실무 선택:
금융/주문: ZooKeeper 또는 etcd (강한 일관성)
캐시 레이스 방지: Redis Redlock (성능 우선)
단순 중복 방지: Redis SETNX (충분)
📢 섹션 요약 비유: CAP과 분산 잠금 — ZooKeeper/etcd는 엄격한 경비원(CP: 분단 시 서비스 중단), Redis는 빠른 경비원(AP: 빠르지만 가끔 실수). 돈(금융)은 엄격한 경비원!
Ⅴ. 실무 시나리오 — 쿠폰 중복 발급 방지
대규모 쿠폰 발급 시스템 분산 잠금:
문제:
이벤트: "선착순 1,000개 쿠폰"
트래픽: 초당 50,000 요청
서버: 10개 인스턴스
분산 잠금 없이:
동시 요청 → 1,000개 이상 발급 가능
설계 (Redis SETNX + Fencing Token):
1단계: 분산 잠금 획득
잠금 키: coupon:event_12345:lock
TTL: 100ms (짧게, 빠른 작업)
unique_val: UUID 생성
SET coupon:event_12345:lock UUID NX PX 100
2단계: 잠금 성공 시 쿠폰 발급
DECR coupon:event_12345:count
IF count >= 0: 쿠폰 발급
IF count < 0: INCR (롤백), 쿠폰 소진
3단계: 잠금 해제
Lua 스크립트로 원자적 해제
4단계: 잠금 실패 시
재시도: 5ms 대기 후 최대 10회 재시도
계속 실패 → "잠시 후 다시 시도" 응답
성능:
초당 50,000 요청 → 잠금 경합
Redis throughput: ~100,000 ops/sec
평균 지연: < 5ms (잠금 획득 포함)
정확성: 1,000개 초과 발급 0건
고가용성:
Redis Sentinel (마스터-레플리카-센티넬)
마스터 장애 → 자동 레플리카 승격
TTL 100ms로 짧게 → 장애 시 빠른 잠금 해제
📢 섹션 요약 비유: 쿠폰 분산 잠금은 원 버튼 줄서기 — 50,000명이 동시에 쿠폰 버튼. Redis 잠금이 한 명씩만 서버에 접근하게 해서 1,000개 정확히 발급. 줄 서기 없이 공정하게!
📌 관련 개념 맵
DLM (분산 잠금 관리자)
+-- 구현
| +-- Redis SETNX/Redlock
| +-- ZooKeeper 임시 노드
| +-- etcd Lease
+-- 핵심 패턴
| +-- Fencing Token (단조 증가)
| +-- TTL (만료 자동 해제)
| +-- KeepAlive (갱신)
+-- CAP 선택
| +-- CP: ZooKeeper, etcd
| +-- AP: Redis
+-- 활용
+-- 클러스터 파일시스템
+-- 선착순 이벤트
+-- 리더 선출
📈 관련 키워드 및 발전 흐름도
[초기 DLM (1990s)]
클러스터 파일시스템 (VMS, VAXcluster)
중앙 잠금 서버
|
v
[분산 데이터베이스 잠금 (2000s)]
2PC 기반 분산 트랜잭션
|
v
[ZooKeeper (2007)]
분산 코디네이션
임시 노드 기반 잠금
|
v
[Redis SETNX 패턴 (2010s)]
초고성능 분산 잠금
Redlock 알고리즘 제안
|
v
[etcd + Kubernetes (2014~)]
Raft 합의 기반
클라우드 네이티브 DLM
👶 어린이를 위한 3줄 비유 설명
- 분산 잠금은 여러 건물 공유 열쇠 — 여러 건물의 사람들이 하나의 화장실을 쓸 때, 열쇠(잠금)를 받은 사람만 사용. 동시 사용 방지!
- Fencing Token은 번호표 갱신 — 33번이 자는 사이 34번이 입장. 33번이 깨도 "34번 이상만 허용" 규칙으로 거부. 만료된 잠금 무력화!
- 선착순 쿠폰 분산 잠금 — 50,000명이 동시 클릭해도 Redis 잠금이 한 명씩 처리. 1,000개 딱 발급하고 끝. 중복 발급 0건!