Redis 분산 락
한 줄 정의
Redis 분산 락은 여러 서버 인스턴스가 동시에 같은 작업을 처리하지 않도록 Redis key를 원자적으로 선점하는 방식이다.
실무에서 왜 문제 되는가
- 서버가 여러 대이면 JVM의
synchronized나 로컬 락만으로는 중복 실행을 막을 수 없다. - 락 만료 시간이 작업 시간보다 짧으면 락을 잡은 작업이 끝나기 전에 다른 요청이 락을 얻을 수 있다.
- 락 해제 시 소유자 확인을 하지 않으면 다른 요청의 락을 지울 수 있다.
- 분산 락은 동시 실행 가능성을 줄이는 도구이지, DB 정합성을 완전히 대체하지 않는다.
동작 원리
- 작업 시작 전
SET key value NX PX milliseconds로 lock key를 저장한다. - 저장에 성공한 요청만 작업을 수행한다.
- lock key에는 TTL과 소유자 token을 함께 둔다.
- 작업이 끝나면 Lua script 등으로 token 확인과 key 삭제를 원자적으로 수행한다.
- 작업 중 서버가 죽으면 TTL 이후 lock key가 만료된다.
실무 판단 기준
| 상황 | 분산 락 판단 | 이유 |
|---|---|---|
| 중복 실행되어도 재시도 가능 | 적합 | 락 실패 시 나중에 다시 처리할 수 있다 |
| 결제 승인처럼 정합성이 매우 중요 | 보조 수단 | DB 제약, 멱등키, 상태 체크가 함께 필요하다 |
| 작업 시간이 예측 가능 | 적합 | TTL을 합리적으로 정할 수 있다 |
| 작업 시간이 길고 변동이 큼 | 주의 | TTL 연장, 작업 분할, 큐 기반 처리 검토가 필요하다 |
| 단일 DB row 갱신 경쟁 | DB 락 우선 검토 | 데이터 정합성은 DB가 더 직접적으로 보장한다 |
| Redis 장애 중에도 반드시 한 번만 실행 | 부적합 | 락 저장소 장애와 네트워크 분리를 완전히 제거할 수 없다 |
자주 나는 실수
SETNX후 별도 명령으로EXPIRE를 걸어 원자성이 깨진다.- 락 value 없이 key만 삭제해서 다른 요청의 락을 지운다.
- token 확인과 삭제를 별도 명령으로 실행해 race condition을 만든다.
- 작업 시간보다 짧은 TTL을 설정한다.
- 락 획득 실패를 성공처럼 처리한다.
- 분산 락만 믿고 DB unique constraint나 상태 검증을 제거한다.
- Redis 장애나 failover 중 락의 안전성이 어떻게 달라지는지 검토하지 않는다.
확인 방법
- 테스트: 동시에 같은 요청을 여러 번 보내 중복 처리가 없는지 확인한다.
- 장애 실험: 락 획득 후 프로세스를 종료해 TTL 이후 복구되는지 확인한다.
- 로그: lock acquire success/fail, lock wait time, lock release fail을 남긴다.
- 메트릭: 락 획득 실패율, 대기 시간, 작업 수행 시간, TTL 초과 비율을 본다.
핵심 요약
Redis 분산 락은 여러 애플리케이션 인스턴스가 같은 작업을 동시에 실행하지 않게 줄여주는 도구다. 락 획득은 NX와 TTL을 원자적으로 설정해야 하고, 해제는 소유자 token 확인과 삭제를 원자적으로 수행해야 한다. TTL은 서버 장애 시 락이 영원히 남지 않게 하지만, 작업 시간보다 짧으면 중복 실행을 만들 수 있다. 중요한 비즈니스 정합성은 분산 락만으로 보장하지 말고 DB 제약, 멱등키, 상태 전이 조건과 함께 설계한다.
꼬리 질문
SETNX와EXPIRE를 따로 실행하면 어떤 문제가 생기는가?- 락 TTL보다 작업 시간이 길어지면 어떤 일이 생기는가?
- 분산 락과 DB unique constraint는 어떤 차이가 있는가?
- 락 해제 시 소유자 token을 확인해야 하는 이유는 무엇인가?
- 분산 락만으로 중복 처리를 완전히 막을 수 있는가?
- Redis failover 중에는 분산 락의 안전성을 어떻게 판단할 것인가?