다수의 서버가 동시에 같은 자원에 접근할 때 발생할 수 있는 동시성 문제를 해결하기 위해 사용되는 동기화 메커니즘이다. 분산 락의 핵심은 '하나의 자원에 대해 한번 에 하나의 서버만 작업을 수행할 수 있다'는 것이다.
서버가 1대라면 서버의 내부 자원 잠금(Lock) 기능으로 동시성을 제어할 수 있다. 하지만 서버가 n대로 늘어나면 어떨까
상황: 남은 쿠폰이 딱 1장인 상태.
문제: 서버 A, B, C에 각각 사용자가 동시에 요청을 보낸다
결과: 각 서버는 "어? 아직 1장 남았네?"라고 판단하고 동시에 쿠폰을 지급해 버립니다. 결국 1장 남은 쿠폰이 3명에게 나가는 사고가 발생한다.
Redis는 속도가 매우 빠르고, 모든 서버가 공통으로 바라볼 수 있는 저장소이기 때문에 분산락을 구현하기에 최적이다.
분산 락은 마치 공용 화장실의 열쇠와 같다.
락 획득: 서버 A가 작업을 시작하기 전, Redis에 coupon_lock이라는 키를 생성한다. (열쇠를 가져감)
상호 배제: 서버 B와 C가 Redis를 확인했을 때 이미 키가 존재하면, "누군가 사용 중이구나"라고 판단하고 대기한다.
락 해제: 서버 A가 쿠폰 지급을 완료하면 Redis에서 해당 키를 삭제한다 (열쇠를 반납함)
다음 차례: 대기하던 서버 중 하나가 다시 열쇠를 차지하고 작업을 수행한다.
Redis로 구현할 때는 주로 두가지 라이브러리를 사용한다.

만약 서버 A가 열쇠를 가져갔는데, 갑자기 서버가 다운되면 어떻게 될까? 열쇠를 영영 반납하지 않아 시스템이 멈출 수 있다. 이를 방지하기 위해 유효시간을 반드시 설정해야 한다. 시간이 지나면 열쇠가 자동으로 소멸된다.
성능과 속도
Redis 락은 메모리(RAM)기반이어서 읽고 쓰는 속도가 압도적으로 빠르기 때문에 락을 잡고 해제하는 과정이 매우 가볍다.
반면 DB락은 디스크 기반이다. 락 정보를 기록하는 관리과정이 Redis보다 무겁고 느리다.
DB서버의 CPU와 메모리 점유율 부담
모든 요청이 DB에 직접 락을 걸면 CPU와 메모리 점유율이 올라간다. DB락이 길어지면 다른 일반적인 조회 업무까지 느려지는 병목 현상이 발생한다.
왜 DB락은 CPU와 메모리가 힘들어 할까?
OS는 계속 스케쥴링을 한다. 1번 요청이 락을 잡고 있는 상황에서, 1번->2번->3번->1번 순서로 스케쥴링이 되었다고 해보자.
1번 요청은 트랜잭션을 끝마치지 못하고 CPU를 2번에게 넘겨준다. 2번 요청의 첫번째 작업은 안타깝게도 락을 확인하는 것. 락이 없으니 CPU를 3번에게 넘겨준다. 3번 요청의 시작도 락을 확인하는 것이다. 할 수 있는게 없으니 다시 CPU는 1번 작업을 한다.
이 과정에서 CPU는 context-switching을 하는데 이 자체가 CPU에게는 엄청난 에너지 소모이다.
CPU는 가만히 있지 못하는 성격이다. 1번 요청이 락을 잡고 작업하는 동안, CPU는 놀지 않으려고 2번,3번 요청을 살짝 쳐다본다.하지만 '아직 락이 안풀렸네?'하고 1번으로 돌아온다. 이 과정을 수만 번 반복하면서 CPU는 '기다리는 것 자체'에 엄청난 에너지를 소모한다.
redis 분산 락은 context-switching을 안하나요?
DB와 통신하려면 연결 통로가 필요하다. 그런데 1000명이 락이 풀리기만을 기다리면서 통로를 하나씩 차지하고 있다면? 락과 상관없는 조회업무를 하려는 일반 사용자의 요청도 들어올 통로가 없어서 입구컷을 당한다.
정상 상황이라면 0.01초만에 락이 풀려 대기 줄이 금방 줄어든다. 하지만 네트워크나 복잡한 로직때문에 락이 1초동안 유지된다면? 그 1초 사이에 새로운 요청이 500개 더 들어와 대기열기 기하급수적으로 늘어난다. DB가 수많은 연결을 관리하다가 메모리 부족으로 뻗어버릴 수 있다.