
서론
분산 락(distributed lock)은 실제 프로덕션 환경에서 의존하게 되기 전까지는 아주 간단해 보입니다.
하나의 프로세스가 특정 리소스에 대한 독점적 접근이 필요하고, 여러 대의 서버가 실행 중이며, 그 사이에 Redis가 위치합니다. 개념 자체는 단순합니다. Redis에 락을 걸고 넘어가면 될 것 같으니까요.
한동안은 이 방식이 잘 작동하는 것처럼 보입니다. 하지만 어느 날 프로세스가 크래시되거나, 네트워크 지연이 발생하거나, 레이턴시가 급증하는 순간 문제가 시작됩니다. 두 프로세스가 같은 락을 동시에 획득한다거나, 아무도 락을 소유하지 않거나, 락이 영원히 해제되지 않는 상황이 벌어지는 것이죠.
대부분의 Redis 락 문제는 Redis 자체 때문이 아닙니다. 분산 락에 대한 오해에서 비롯됩니다. Redis는 완벽한 배타성을 보장해 주는 도구가 아니라, 조율(coordination)을 위한 도구를 제공할 뿐입니다.
분산 락의 본질
분산 락은 인메모리 뮤텍스(mutex)와 다릅니다. 절대적인 보장을 제공하지 않으며, 장애를 없애주지도 못합니다.
분산 락은 신뢰할 수 없는 환경에서 동작하는 조율 메커니즘입니다. 네트워크는 끊기고, 프로세스는 크래시되며, 시계는 어긋납니다. 완벽한 동작을 가정하는 어떤 락 전략이든 결국에는 무너집니다.
Redis 락은 '최선 노력(best-effort)' 방식의 락입니다. 올바르게 설계하면 놀라울 정도로 효과적이지만, 성의 없이 구현하면 미묘한 경쟁 상태(race condition)와 데이터 손상을 초래합니다.
Redis 락을 안전하게 사용하기 위한 첫걸음은 기대치를 조정하는 것입니다.
Redis 락이 적합한 경우
Redis 분산 락이 적절한 상황은 다음과 같습니다.
임계 영역(critical section)의 동시 실행을 막아야 할 때
여러 서버에 걸친 작업 조율이 필요할 때
작업 수명이 짧을 때
재시도가 허용될 때
대표적인 사용 사례로는 작업 중복 제거(job deduplication), 스케줄링된 작업 조율, 캐시 재구축, 이중 처리 방지 등이 있습니다.
반면 오랫동안 실행되는 비즈니스 트랜잭션, 사용자에게 직접 노출되는 중요한 워크플로, 재시도가 불가능한 작업에는 Redis 락이 부적합합니다. 재시도가 허용되지 않는다면 Redis 락은 잘못된 도구 선택입니다.
Redis에서 유일하게 안전한 락 프리미티브
가장 안전한 Redis 락 프리미티브는 단일 원자적(atomic) 명령어 하나입니다.
SET key value NX EX ttl
이 명령어는 락이 아직 존재하지 않을 때만 락을 생성하고, 고유한 소유자 값을 할당하며, TTL을 설정해 락이 자동으로 만료되도록 합니다.
그 외의 모든 대안은 경쟁 상태를 유발합니다. TTL 없이 SETNX만 사용하거나 만료 시간을 별도 단계에서 설정하면 장애 발생 시 무너집니다. TTL은 필수이며, 프로세스가 예기치 않게 크래시될 때 시스템을 보호해 줍니다.
락 TTL이 필수인 이유
TTL이 없으면 Redis 락은 영원히 남아 있을 수 있습니다. 프로세스가 락을 잡은 상태로 크래시되면 시스템은 아무 알림 없이 멈춰 버립니다.
TTL은 락을 자가 치유(self-healing) 가능하게 만듭니다. 장애가 발생하더라도 락은 결국 만료되어 작업 진행이 재개됩니다. 이 과정에서 짧은 중복 실행이 생길 수 있지만, 그것은 의도된 트레이드오프입니다.
영원히 만료되지 않는 락은 락이 아예 없는 것보다 더 위험합니다.
락 소유권과 안전한 해제
Redis 락은 반드시 획득한 프로세스 본인만 해제할 수 있어야 합니다. 그렇기 때문에 락 값은 고정된 문자열이 아니라 고유 식별자여야 합니다.
락을 해제하려면 소유권 확인이 선행되어야 합니다. 안전한 방법은 Lua 스크립트를 사용해 저장된 값이 예상 소유자와 일치할 때만 락을 삭제하는 것입니다.
이렇게 하면 락이 만료되어 다른 프로세스가 새로 획득한 직후, 원래 소유자가 그 락을 실수로 삭제해 버리는 경쟁 상태를 예방할 수 있습니다.
안전한 락 지속 시간 선택
락 TTL은 보호하려는 작업의 최대 예상 실행 시간보다 길어야 합니다. 평균 실행 시간만으로는 충분하지 않습니다.
작업이 아직 진행 중인데 락이 먼저 만료되면, 다른 프로세스가 해당 락을 획득해 동일한 작업을 동시에 수행할 수 있습니다. 이는 중복 처리나 데이터 손상으로 이어질 수 있습니다.
반대로 지나치게 긴 TTL은 문제가 발생했을 때 회복을 지연시킵니다. 락 지속 시간은 시스템 변화에 따라 계속 조정해야 하는 균형의 문제입니다.
가장 안전한 접근은 락으로 보호되는 작업을 짧고 한정적으로 유지하는 것입니다.
락 연장과 하트비트
예상보다 오래 걸리는 작업도 있습니다. TTL을 주기적으로 갱신해 락을 연장할 수는 있지만, 그만큼 복잡도와 새로운 실패 지점이 늘어납니다.
TTL 연장은 반드시 락 소유자만 수행할 수 있어야 하며, 소유권을 잃는 즉시 연장을 중단해야 합니다.
많은 경우 락 연장 로직을 구현하는 것보다 작업을 더 작은 단위로 나누어 재설계하는 편이 안전합니다.
Redlock 논쟁
Redlock은 여러 Redis 인스턴스를 활용해 락 안전성을 높이는 알고리즘입니다. 동시에 논란이 많고 운영 복잡도도 높은 편입니다.
대부분의 시스템에서 Redlock은 얻는 이점보다 추가되는 복잡도가 더 큽니다. 현실적인 환경에서 보장하기 어려운 타이밍 가정에 의존하기 때문입니다.
Redlock 수준의 보장이 필요하다면 애초에 Redis가 적합한 도구가 아닐 수 있습니다. 트랜잭셔널 락을 지원하는 데이터베이스나 ZooKeeper, etcd 같은 전문 조율 시스템이 더 나은 선택일 수 있습니다.
대부분의 Redis 사용 사례에서는 적절한 TTL 기반 락을 갖춘 단일 Redis 인스턴스면 충분합니다.
락은 트랜잭션이 아니다
Redis 락은 작업을 트랜잭션으로 만들어 주지 않습니다. 자동 롤백을 제공하지 않으며, 작업 도중 장애가 발생했을 때 일관성을 보장하지도 않습니다.
락은 동시성을 줄여줄 뿐, 장애를 없애지 못합니다. 임계 영역은 멱등성(idempotent)을 갖도록 설계해야 반복 실행되더라도 피해가 없습니다.
이 설계 원칙만 지켜도 락 관련 버그의 위험을 크게 줄일 수 있습니다.
Redis가 다운되면 어떻게 될까?
Redis가 다운되거나 재시작되면 모든 락이 사라집니다. 이는 예상된 동작입니다.
Redis가 온라인으로 돌아오면 여러 프로세스가 동시에 락을 획득하고 작업을 시작할 수 있습니다. 시스템은 이런 가능성을 견딜 수 있어야 합니다.
Redis 재시작 중 락이 사라지는 것만으로 데이터 손상이 발생한다면, 그 락 설계는 안전하지 않은 것이므로 다시 검토해야 합니다.
프로덕션 환경에서의 락 모니터링
Redis 락을 눈에 보이지 않는 상태로 두면 안 됩니다. 팀은 현재 존재하는 락의 수, 락의 수명, 락 획득 실패 빈도를 모니터링해야 합니다.
비정상적으로 오래 살아 있는 락은 멈춘(stalled) 프로세스를 의심하게 합니다. 획득 실패가 잦다면 경합(contention) 또는 잘못된 락 설계를 시사합니다.
안전한 운영을 위해서는 가시성 확보가 필수입니다.
흔한 Redis 락 안티패턴
흔히 저지르는 실수로는 TTL 없이 SETNX 사용, 고정 문자열을 락 소유권 값으로 사용, 검증 없이 무조건 락 삭제, 장기 실행 작업에 락을 오래 들고 있는 것, 락이 정확성을 보장한다고 믿는 것 등이 있습니다.
이런 안티패턴들은 실제 프로덕션 장애 사례에서 매우 자주 발견됩니다.
실전 락 체크리스트
안전한 Redis 락 구현에는 다음 요소들이 포함되어야 합니다.
TTL이 설정된 락 키
고유한 락 소유권 값
해제 시 소유권 검증
짧은 수명의 임계 영역
멱등성을 갖춘 작업
테스트를 거친 장애 시나리오
이 중 하나라도 빠져 있다면 락 설계를 다시 점검해 봐야 합니다.
Redis 락을 바라보는 건강한 관점
Redis 락은 에어백이 아니라 안전벨트입니다. 피해를 줄여주지만, 사고 자체를 완전히 막아주지는 못합니다.
신중하게 사용하면 분산 시스템의 조율을 크게 단순화해 줍니다. 대충 사용하면 미묘하고 지속적인 버그를 낳습니다.
요약
분산 락이 어려운 이유는 장애가 불가피하기 때문입니다. Redis는 완벽한 락이 아니라 빠르고 단순하며 실용적인 락 메커니즘을 제공합니다.
장애를 전제로 설계하고, 락을 짧게 유지하며, TTL을 일관되게 사용하고, 작업이 안전하게 재시도될 수 있도록 하세요. 올바르게 사용하면 Redis 분산 락은 프로덕션 시스템에서 신뢰할 수 있는 강력한 도구가 됩니다.