핵심 인사이트

  1. DLM(Distributed Lock Manager)은 분산 시스템에서 여러 노드가 공유 자원에 대한 접근 순서와 일관성을 조율하는 핵심 미들웨어 — 단일 서버의 뮤텍스/세마포어가 분산 환경으로 확장된 개념이며, 클러스터 파일시스템(GFS, OCFS2)의 핵심 구성 요소다.
  2. DLM의 핵심 과제는 CAP 트릴레마와 장애 시나리오 — 네트워크 분단(Partition) 시 일관성(Consistency)과 가용성(Availability) 중 하나를 포기해야 하며, "잠금 보유자 장애 시 잠금 해제"가 구현 난이도의 핵심이다.
  3. 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줄 비유 설명

  1. 분산 잠금은 여러 건물 공유 열쇠 — 여러 건물의 사람들이 하나의 화장실을 쓸 때, 열쇠(잠금)를 받은 사람만 사용. 동시 사용 방지!
  2. Fencing Token은 번호표 갱신 — 33번이 자는 사이 34번이 입장. 33번이 깨도 "34번 이상만 허용" 규칙으로 거부. 만료된 잠금 무력화!
  3. 선착순 쿠폰 분산 잠금 — 50,000명이 동시 클릭해도 Redis 잠금이 한 명씩 처리. 1,000개 딱 발급하고 끝. 중복 발급 0건!