Redis 분산락

Redis 분산락

생성일
Apr 5, 2024 07:15 AM
태그
redis
lock

분산 락

필요성

분산 환경에서 하나의 공유 리소스를 서로 다른 클라이언트가 사용하는 경우가 있다. Redis는 기본적으로 싱글 스레드로 동작하다 보니 Redis를 이용해 분산 락을 구현하는 경우가 많은 것 같다.
 

Redlock 알고리즘

Redis를 싱글 인스턴스로 사용하는 경우는 실무에서 드물다. 대개 클러스터나 센티넬 형태로 사용할 텐데, master에 문제가 생겨 failover가 발생할 때, 경우에 따라서는 Race condition이 발생할 수 있다.
 
Redlock 알고리즘은 이런 케이스를 방지한다.
 
N개의 Redis master node가 있다고 가정한다. 만약 과반이 넘는 master로부터 lock을 획득하면, 락을 획득했다고 판단한다. 다만, 유효시간이 정해져 있어 유효시간 내에 master로부터 락 획득을 하지 않으면 자동으로 락 획득에 실패한 것으로 간주한다.
 
따라서 DOWN된 master의 응답을 무한정 기다리는 케이스를 방지하면서도 quorum 기반으로 합리적으로 락을 관리할 수 있게 된다.
 

Redis를 이용한 분산 락 직접 구현 예제

Spin Lock

특정 리소스를 key로, 리소스를 사용하는 client를 value로 관리한다면 간단하게 Redis로 분산 락을 구현할 수 있다.
 
SET resource_name my_random_value NX PX 30000
 
여기서 my_random_value는 모든 클라이언트와 잠금 요청에 대해 unique해야 하며, 락 해제시 검증을 위해 사용된다.
 
클라이언트는 GET으로 해당 리소스가 점유되어 있는지 확인하고, 잠겨 있다면 대기하게 된다.
 
그리고 DEL 명령어로 Lock을 해제하면 된다.
 
if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
 
다만 이 경우, 문제가 있다.
클라이언트가 락을 획득하지 못했을 때, 재시도 로직이 별도로 필요하다.
 
지금 구조에서는 Redis가 따로 분산 락을 획득하려고 하는 클라이언트를 저장하지 않기 때문에, 클라이언트는 락을 획득할 때까지 계속 retry를 하게 된다. retry를 위해서는 계속 GET 명령을 하게 되기 때문에 시스템이 복잡해질수록 부하가 커지게 된다.
 
이런 형태의 락을 spin lock이라고 한다.
 

Pub/Sub 방식의 락

알다시피 Redis도 메시지 브로커 기능을 제공한다. Redisson과 같은 라이브러리는 PubSub을 이용해 Lock의 획득과 분배를 관리한다. Lock이 해제되면, 구독 중인 클라이언트들에게 Lock 해제 알림이 전달되고, 클라이언트들은 재차 Lock 획득을 시도하게 된다.
 
 

더 공부할 것

  • Go를 이용한 간단한 lock 구현 (redsync)
  • PubSub을 이용한 Redisson 과 유사한 방식의 분산 락 구현
 

더 읽을거리

redsync
go-redsyncUpdated Apr 7, 2024