스택큐힙리스트

분산락 3종 비교 – Redisson, ShedLock, DB 락의 장단점 본문

개발

분산락 3종 비교 – Redisson, ShedLock, DB 락의 장단점

스택큐힙리스트 2025. 8. 16. 23:02
반응형

“동시에 한 번만 실행”을 보장하는 방법은 하나가 아닙니다. 실무에서 가장 많이 쓰는 세 가지—Redisson(레디스 기반 락), ShedLock(스케줄 단일 실행), DB 락(Advisory/행 수준 락)—을 아키텍처 관점과 장애 시나리오까지 묶어 고급 비교로 정리했습니다.


1) 한 줄 요약

  • Redisson: 초저지연·고QPS 임계영역 보호에 적합. TTL/워치독으로 고아락 방지. 레디스 가용성/네트워크 분할 가정이 안전성의 전제.
  • ShedLock: “스케줄 job을 동시에 최대 1회만” 실행하는 데 특화. 비즈니스 임계구간 일반 락 용도는 아님. lockAtMostFor/lockAtLeastFor로 종료 보장·중복 억제.
  • DB 락: 트랜잭션 모델과 강한 일관성이 장점. PostgreSQL Advisory/MySQL GET_LOCK으로 애플리케이션 레벨 조정 가능. DB 부하·교착, 클러스터 전역 보장 범위는 DB 특성에 좌우.

2) 레디스 기반: Redisson 분산락

언제 쓰나

  • 초당 수천~수만 요청이 한 키(자원)를 두고 경쟁할 때—예: 재고 차감, 선착순 쿠폰, 멱등 처리의 임계구간 보호.

설계 핵심

  • Redisson RLock은 임대시간(leaseTime) 만료 또는 unlock() 시 해제. 워치독(Watchdog)이 기본 30초 간격으로 자동 연장해, 홀더가 살아있는 동안 락을 유지한다는 점이 고아락을 줄여줍니다.
  • 레디스의 분산락 알고리즘(예: Redlock)은 단일 노드 대비 내고장성을 높이려는 시도지만, 네트워크 분할·시계 드리프트 등 가정이 현실과 어긋날 수 있다는 비판도 존재합니다. 즉, 성능은 탁월하지만, 완전한 안전성은 워크로드·배포구조에 의존합니다.

장점

  • 대기 시간이 짧고 Lock/Unlock 오버헤드가 낮다.
  • JVM 친화 API, 재진입락/공정락 등 도구 세트가 풍부.

주의점·안티패턴

  • TTL 미설정 + 긴 GC/스톰 → 워치독 연장 실패 시 조기 해제 위험. 장시간 업무는 명시적 leaseTime 또는 보수적 설계. (워치독 이슈 사례 다수)
  • 레디스 장애·페일오버 시 락 상실/이중 실행 가능성. 중요 거래는 멱등성 키유니크 제약을 병행해 2차 방어막 마련.
  • 참고할 만한 한국어 실무 글: Redisson 적용기와 한계 논의.

3) 스케줄 단일 실행: ShedLock

언제 쓰나

  • 다중 인스턴스에서 돌아가는 @Scheduled/배치 작업을 “동시에 한 번만” 돌리고 싶을 때.

설계 핵심

  • 공유 저장소(DB/Redis/Mongo 등)에 락 상태를 기록.
  • lockAtMostFor: 노드가 죽어도 일정 시간 뒤 자동 해제(세이프티넷). lockAtLeastFor: 최소 실행 시간 보장(너무 자주 재실행 방지).
  • “공유 저장소가 있어야 동작”하는 구조.

장점

  • 구현·운영이 단순하고, 스케줄 중복 실행을 안정적으로 차단.
  • Quartz 클러스터 대체로 가벼운 선택지.

주의점·안티패턴

  • HTTP 요청 임계구간 보호용 ‘일반 분산락’ 라이브러리가 아님. 요청-응답 경로의 수ms~수십ms 단위 경쟁에는 부적합.
  • lockAtMostFor는 반드시 설정(노드 장애 시 영구 락 방지).
  • 국내 도입기·설정 예시는 아래를 참고.

4) 데이터베이스 락: Advisory/행 수준 락

언제 쓰나

  • 이미 강한 트랜잭션 모델을 쓰는 서비스에서, DB를 중심으로 일관성과 순서를 엄격히 가져가고 싶을 때.

두 가지 대표 방식

  1. 행 수준(PESSIMISTIC/FOR UPDATE): 데이터 행을 잠가 Lost Update 방지.
  2. Advisory Lock: 애플리케이션 정의 키로 협력적 잠금.
    • PostgreSQL: 트랜잭션/세션 레벨 둘 다 제공. 세션 락은 롤백과 무관하게 유지될 수 있으므로 해제 정책 주의.
    • MySQL: GET_LOCK(name, timeout)으로 서버 단위 이름 기반 락. 세션 종료 시 암묵 해제. (클러스터 토폴로지에 따라 전역 보장은 달라질 수 있음)

장점

  • 트랜잭션 경계 내 완결성·가시성이 좋고, DB 감사/메트릭으로 관찰 가능.
  • 외부 미들웨어 의존 없이 단일 장애면(SPOF)를 줄일 수 있음.

주의점·안티패턴

  • DB 커넥션이 곧 락 리소스. 락 경합이 늘면 풀 고갈·교착 위험.
  • 세션 레벨 Advisory는 롤백과 분리될 수 있어 정확한 해제 코딩이 중요.
  • MySQL GET_LOCK은 배포 구조에 따라 노드 간 전역성 한계가 있음—클러스터 전역 보장을 전제로 설계하면 오작동 위험.
  • 한국어 실무 정리: Advisory/락 동작 이해 글 다수.

5) 선택 가이드 (실무 체크리스트)

  • HTTP 임계구간, 초저지연·고QPS: Redisson 우선. 단, 멱등성 키 + DB 유니크 제약을 보조로 깔아 재시도·중복에 안전하게.
  • 스케줄·배치 단일 실행: ShedLock 정답. lockAtMostFor는 필수.
  • DB 중심 강한 일관성/순서 보장: DB 락. 트랜잭션 시간 최소화·인덱스/쿼리 설계로 교착 리스크를 낮출 것.

보너스 팁: 어떤 락이든 “락만으로 안전하지 않다”는 사실을 기억하세요. 멱등성(Idempotency), 재시도 정책, 타임아웃, 모니터링(락 보유 시간 관측)을 함께 설계해야 진짜 실전 내구성이 나옵니다.

반응형
Comments