Distributed Lock

분산 락 (Distributed Lock)

서버가 여러 대인 상황에서 동일한 데이터에 대한 동기화를 보장하기 위해 사용

필요한 이유

서버가 한 대가 아니라 여러 대인 경우, 여러 서버로 API가 분산 호출된다.

서버들간에 동기화된 처리가 필요하고, 여러 서버에 공통된 락을 적용해야 하기 때문에 redis를 이용하여 분산 락을 이용한다.

분산 락 같은 경우 db 등 공통된 데이터 저장소를 이용해 자원이 사용중인지 확인하기 때문에 전체 서버에 동기화된 처리가 가능하다.

스핀 락

Redis에서 분산 락을 구현할 때, 스핀 락에 대해서 먼저 알아야한다.

스픽 락은 다른 스레드가 Lock을 소유하고 있다면 그 Lock이 반환될 때까지 계속 확인하며 기다리는 것이다.

Lock 을 점유하는 시간이 짧을 경우 유용하지만 스레드가 Lock 을 오래 유지하는 경우 CPU 에 부담을 줄 수 있다.

Lock의 타임아웃 지정

스핀 락을 구현했을 때, 다른 스레드가 락을 점유하면 또 다른 스레드는 락을 획득할 때까지 확인하며 기다린다.

이 때 만약 특정한 애플리케이션에서 tryLock을 성공했는데 불운하게도 어떤 오류 때문에 애플리케이션이 종료되어버리면 어떻게 될까?

다른 모든 애플리케이션까지 영원히 락을 획득하지 못한 채 락이 해제되기만을 기다리는 무한정 대기상태가 되어 전체 서비스의 장애가 발생하게 될 것이다.

그래서 일반적인 로컬 스핀 락과는 다르게 일정 시간이 지나면 락이 만료되도록 구현해야 한다.

그럴려면 expire time을 설정해주어야한다.

또한 무한정으로 락의 획득을 시도한다면 문제가 될 수 있다.

만약 연산이 오래 걸릴 경우 대부분의 스레드가 락을 대기하는 상태가 되어 클라이언트에 응답하는 속도가 늦어지고, 동시에 레디스에 엄청난 트래픽을 보낼 수 있기 때문이다.

그래서 락을 획득하는 최대 허용시간을 정해주거나, 최대 허용 횟수를 정해주는 것이 좋다.

만약 락을 획득하는데에 실패한다면 연산을 수행할 수 없는 상태이기에 Exception을 던진다.

레디스에 많은 부하

위의 코드는 스핀 락을 사용했지만 사실 스핀 락을 사용하면 레디스에 엄청난 부담을 주게된다.

스핀 락은 지속적으로 락의 획득을 시도하는 작업이기 때문에 레디스에 계속 요청을 보내게 되고 레디스는 이런 트래픽을 처리하느라 부담을 받게 된다.

또한 일회성이 아니라 모든 작업이 완료될 때까지 지속적으로 레디스에 부하를 가하기 때문에 요청이 지속적으로 들어오는 환경이라면 이러한 비효율성은 더욱 커진다.

만약 레디스에 부담을 덜 주기 위해 sleep 시간을 늘린다면 50ms가 걸리는 작업에 이 동기화를 적용하면 락을 획득하지 못할 경우 50ms 걸리는 작업을 하기 위해 300ms를 대기해야하는 다른 비효율적인 상황이 생기게 된다.

RedLock

레디스에서는 분산 락을 구현하는 방법으로 RedLock 이라는 개념에 대해서 설명한다 .

구현으로 자바에서는 Redission, 고 언어에서는 Redsync, Python에서는 Pottery혹은 Redlock-py를 사용한다.

Node 환경이라면 node-redlock을 이용하면 될 것이다.

Last updated