왜 필요한가?
- MSA 환경에서는 여러 서비스가 각자 독립적으로 동작함
- 동시에 같은 데이터에 접근하거나, 수정하려는 시도가 발생할 수 있음
- Lock을 이용해서 한번에 한 서비스만 데이터 관련 작업을 할 수 있게 방지해야 함
분산 락 (Distributed Lock)
- 여러 서버 또는 인스턴스가 동시에 같은 자원에 접근하지 않도록 막는 방법
- MSA에서는 여러 서비스 인스턴스가 동일 자원(DB row, 파일, 재고정보 등)에 접근할 수 있으므로 데이터 충돌 방지용으로 락이 필요함
Redis와 Lock
왜 Redis로 Lock을 거는가?
- Redis는 속도가 빠르고 중앙에서 관리 가능한 인메모리 저장소이기에, 분산 환경에서 락 관리용으로 적합함
기본 아이디어
- 어떤 리소스를 사용할 때
- Redis에 'Lock을 걸었다'는 키를 먼저 저장
- 다른 서비스는 키를 먼저 확인하고, 키가 있을 경우 대기하거나 실패 처리
- 작업이 끝날 시 키를 삭제해서 락을 해제함
SET lock_key lock_value NX EX 10
NX: 키가 없을 때만 설정(중복 방지)
EX 10: 10초 후 자동 만료(장애 발생 시 락이 영원히 유지되는 것 방지)
락의 종류
1. 단순 락(SETNX 기반)
Boolean isLocked = redisTemplate.opsForValue().setIfAbsent("lock:order:123", "uuid", 10, TimeUnit.SECONDS);
- 간단하고 빠른 방법
- 클라이언트가 죽으면 락이 안 풀릴 수도 있음(만료시간 설정 필수), 여러 노드에서 동시에 락을 걸려고 하면 race condition 발생 가능
race condition
- 경쟁 상태
- 여러 작업(스레드/프로세스)이 공유 자원에 동시에 접근하거나 수정할 때, 실행 순서에 따라 결과가 달라지는 상황
- 누가 먼저 실행되느냐에 따라 결과가 달라지기에 예측 불가능하고 오류가 발생할 위험이 큼. 아주 소름돋는 상황이다.
- 멀티스레드나 분산 환경에서 자주 발생하는 문제로, 동시성 이슈의 대표적인 사례
race condition 발생 조건
- 공유 자원이 있을 때(변수, DB row, 파일 등)
- 둘 이상의 실행 흐름(스레드, 인스턴스, 프로세스)이 동시에 접근할 때
- 접근 순서에 따라 결과가 달라질 수 있을 때
2. RedLock(레드락 알고리즘)
작동 방식
- 최소 3개 이상의 Redis 인스턴스 필요
- 클라이언트가 동일한 키를 N개의 Redis 중 과반수(Majority) 이상에서 락을 획득해야 유효
- 락 획득 실패 시 전체 롤백
특징
- 장애에 강함
- 네트워크 분리나 Redis 일부 다운 시에도 안전하게 락을 관리할 수 있음
3. Redisson 기반 분산 락
Redisson : Java용 Redis 클라이언트. 분산 락을 쉽게 구현할 수 있게 도와줌
- 분산 락을 안정적으로 구현할 수 있음
- 락 재시도, 만료, 해제 등 자동 처리
- 클러스터/ 싱글 Redis 모두 지원