Posted 2025.06.20 19:00
By recoma
약 2주 전, 회사 내에서 꽤 심각한 이슈가 발생했다. CeleryBeat 기반의 배치 프로세스가 동작 중 서버 리빌드로 인해 프로세스가 일시적으로 종료되었고, 이 과정에서 삭제되어야 할 분산락 캐시 데이터가 그대로 남게 되었다. 그 결과, 다음 배치 프로세스가 분산락을 확인하고 “작업이 아직 진행 중”이라 판단하며 실행되지 않는 문제가 생겼다.
다행히 문제는 해결됐지만, 이를 계기로 분산락 사용에 대해 다시 생각하게 되었고, 그 내용을 정리해 보려 한다.
회사 내 결제 서비스에서는 외부 업체로부터 카드 사용 승인을 받아야 한다. 어느 날, 이 승인 절차가 갑자기 작동하지 않기 시작했다. 보통은 외부 API 문제라면 하루 이내에 해결되는데, 이번엔 3일이 지나도 해결되지 않았다.
문제는 외부 API가 아니라 내부에 있었다. 디버깅 과정에서, 작업 후 삭제되어야 할 분산락 캐시 데이터가 남아 있었고, 이 데이터를 삭제하자 승인 프로세스가 정상적으로 작동하기 시작했다.
즉, 분산락이 남아 있어 이후 작업이 영원히 대기 상태에 빠졌던 것이다.
컴퓨터공학과 출신 또는 비전공이지만 CS를 공부해 봤다면 “동시성”이란 단어를 한번 씩 들어봤을 것이다. 그리고 그 다음에 생각나는 단어는 mutex
라는 단어를 생각할 것이다. 그렇다면 이런 의문이 들을 것이다. 동시성 제어를 할 거면 mutex
를 쓰면 되지 굳이 왜 분산락 얘기가 나오나요?
mutex
는 단일 프로세스 내에서만 유효하다. 프로세스 간에는 메모리를 공유하지 않기 때문에, 여러 서버나 인스턴스에서 동시에 접근하는 상황에서는 무용지물이다.
이럴 때, 다중 시스템 간 자원 접근을 제어하기 위한 방법이 필요하며, 그 역할을 하는 것이 분산락이다.
제약조건(예: UNIQUE)으로 해결할 수 있는 경우도 있지만, 구조적으로 제약조건을 걸 수 없는 상황에서는 분산락이 실질적인 해결책이 된다.
분산락을 사용하는 방법은 여러가지가 있으나 여기서는 Redis 기반의 분산락에 대해서 설명을 한다. 분산락에 있어서 가장 많이 쓰이는데 주된 이유는 다음과 같다.
과거에는SETNX
명령어를 사용해 락을 구현하곤 했다
SETNX mykey "Hello" # 성공하면 1 반환
SETNX mykey "World" # 이미 존재하면 0 반환
하지만 SETNX
는 이미 deprecated 되었으며, 가장 큰 문제는 만료 기한 설정이 불가능하다는 것이다. 락을 획득한 후 프로세스가 예기치 않게 종료되면, 해당 키가 무한히 남아 시스템을 교착 상태에 빠뜨릴 수 있다. 공식 사이트 조차도 이 명령어 대신 SET
을 사용하는 것을 권장하고 있다.
그래서 SETNX
대신 SET
을 권장하고 있다.
SET hello "world" NX EX 60
NX
플래그를 사용해 SETNX
와 동일한 기능을 낼 수 있고. 추가로 EX
를 통해 유효 기간을 설정할 수 있다. 유효기간을 설정하게 되면, 어떠한 이슈로 프로세스가 Shutdown이 되더라도, 특정 시간이 지나면 사라지기 때문에 분산락 알고리즘을 구현할때, 캐시가 영구적으로 남는 이슈에 대한 부담을 덜을 수 있다. 그래도 PID등 여러 부분들을 체크해야 하기 때문에 여전히 복잡하다.
직접 구현하려고 하지 말고, 검증된 라이브러리를 사용하는 것이 좋다.
cache.lock()
redis.lock()
코드를 직접 구현하려다 분산락 때문에 또 다른 장애를 만들 수도 있다.
여타 기술들, 좁게는 라이브러리에서 그렇듯, 분산락은 특적 문제에 대한 해결방안을 제공해 주는 도구일 뿐이지 만병통치약은 아니다. 분산락은 멀티 프로세스가 동일한 시스템의 자원을 사용하는 방식이다. 즉 다른 시스템에 접속은 무조건 필수이기 대문에 둘 중 하나가 이상이 생기면 일관성에 문제가 일어나기 시작한다. 아래의 항목에 대해 조심해야 한다.
작업 중 서버가 재시작되면 락 해제가 되지 않으며, 이후 작업들이 교착 상태에 빠진다. try-catch로도 방지 불가하다.
직업 예상 시간을 기준으로 만료 시간을 설정하면 쉽게 해결을 할 수 있다. 단, 설정된 시간 동안 후속 작업이 지연될 수 있다는 점은 감수해야 한다.
Redlock, 락 감시자 등의 고급 알고리즘도 있으나 구현 복잡도가 높고, 안정성을 확보하려면 추가적인 설계가 필요하다.
나도 아직 경험해 보지 않은 이슈이고, 또 어차피 AWS ElastiCache 같은 외부 서비스를 사용하는 경우가 많아 거의 드물지만 반대로 캐시 시스템이 Shutdown 되는 경우 가 있다. 실제로 발생하면 1번보다 더 큰 재앙이 될 수 있다.
분산락은 단순한 기술처럼 보일 수 있지만, 결국 시스템 전반의 신뢰성과 안정성을 좌우하는 요소다. 철저한 예외 처리가 요구되며, 도입 전에 반드시 설계와 운영 비용을 고려해야 한다.