INSIGHTS · Technology
여러 서버에서 중복 결제 방지를 위한 Redis 분산 락 활용 방안
BLICT · 2026. 10. 11. · 수정 2026. 10. 11.
여러 서버에서 동일한 스케줄러가 실행될 때 중복 결제가 발생할 수 있습니다. Redis 분산 락을 통해 이를 해결할 수 있는지, 작업 중 서버가 죽거나 락 만료 후에도 중복 실행을 방지하는 방법을 알아봅니다.
Redis 분산 락의 이해와 필요성
여러 서버에서 동일한 스케줄러가 실행되는 환경에서는 중복 결제나 중복 정산이 발생할 수 있는 위험이 큽니다. 특히, 여러 인스턴스가 동시에 같은 작업을 수행하려 할 경우 데이터의 무결성을 해치는 결과를 초래할 수 있습니다. 이러한 문제는 금융 서비스와 같이 정밀한 처리가 요구되는 시스템에서 치명적입니다.
Redis는 인메모리 데이터 구조 저장소로, 빠른 속도와 높은 가용성 덕분에 많은 기업들이 분산 시스템에서의 상태 관리에 활용하고 있습니다. Redis의 분산 락 기능은 이러한 중복 실행 문제를 해결하는 데 매우 유용합니다. 분산 락을 사용하면 한 서버가 특정 자원에 대한 잠금을 획득했을 때, 다른 서버는 해당 자원에 접근하지 못하게 하여 중복 작업을 방지할 수 있습니다.
Redis 분산 락 구현 방법
Redis의 분산 락을 구현하는 방법은 여러 가지가 있지만, 가장 많이 사용되는 방법은 SETNX 명령어를 이용하는 것입니다. 이 명령어는 주어진 키가 존재하지 않을 때만 값을 설정하고, 성공적으로 설정되면 락을 획득한 것으로 간주합니다. 아래는 Redis를 이용한 분산 락의 간단한 구현 예시입니다.
import redis.clients.jedis.Jedis;
public boolean acquireLock(Jedis jedis, String lockKey, String lockValue, int expireTime) {
String result = jedis.set(lockKey, lockValue, "NX", "EX", expireTime);
return "OK".equals(result);
}
위의 코드는 Redis에 락을 획득하기 위한 메서드로, lockKey에 락을 설정하고, lockValue는 락을 획득한 서버의 식별자입니다. expireTime은 락이 만료되는 시간을 설정하여, 서버가 죽거나 작업이 오래 걸릴 경우 자동으로 락이 해제되도록 합니다.
중복 실행 방지 전략
락을 획득한 서버가 작업 도중 죽거나, 락 만료 후에도 작업이 계속되는 경우 중복 실행을 방지하기 위한 추가 전략이 필요합니다. 이를 위해서는 상태 관리를 통해 작업의 진행 상황을 Redis에 저장하는 방법이 효과적입니다. 예를 들어, 작업이 시작될 때 Redis에 상태를 "IN_PROGRESS"로 업데이트하고, 작업이 완료되면 "COMPLETED"로 업데이트합니다.
이러한 상태 관리는 다음과 같은 방식으로 구현할 수 있습니다. 작업을 시작하기 전에 상태를 확인하여 이미 진행 중인 작업이 있다면 새로운 작업을 실행하지 않도록 방지할 수 있습니다.
public boolean startJob(Jedis jedis, String jobKey) {
String status = jedis.get(jobKey);
if ("IN_PROGRESS".equals(status)) {
return false; // 이미 진행 중인 작업이 있음
}
jedis.set(jobKey, "IN_PROGRESS");
return true; // 작업 시작 가능
}
락 만료 관리
Redis 분산 락의 만료 시간은 매우 중요합니다. 너무 짧으면 작업이 진행 중일 때 락이 해제되어 중복 실행이 발생할 수 있고, 너무 길면 자원 낭비가 발생할 수 있습니다. 이를 해결하기 위해서는 동적 갱신 기법을 사용할 수 있습니다. 작업이 진행되는 동안 주기적으로 락의 만료 시간을 연장함으로써, 작업이 완료될 때까지 락이 유지되도록 할 수 있습니다.
작업 중에 주기적으로 락을 갱신하는 방법은 다음과 같습니다.
public void renewLock(Jedis jedis, String lockKey, String lockValue, int newExpireTime) {
String currentLockValue = jedis.get(lockKey);
if (lockValue.equals(currentLockValue)) {
jedis.expire(lockKey, newExpireTime);
}
}
위의 코드는 락이 획득된 서버가 주기적으로 호출하여 락의 만료 시간을 연장하는 메서드입니다.
결론 및 체크리스트
Redis 분산 락은 여러 서버에서 중복 결제를 방지하는 효과적인 방법이 될 수 있습니다. 그러나 락을 획득한 서버가 작업 도중에 죽거나 락 만료 후에도 중복 실행을 방지하기 위해서는 추가적인 상태 관리와 락 만료 관리가 필요합니다. 이러한 방법들을 적절히 조합하여 사용하면 안정적인 시스템을 구축할 수 있습니다.
- Redis 분산 락을 설정할 때 기본 키와 값을 명확히 설정하라.
- 작업 상태를 Redis에 저장하여 중복 실행을 방지하라.
- 락 만료 시간을 적절히 설정하고, 필요 시 갱신하라.
- 예외 상황에 대비한 로깅 및 모니터링 체계를 구축하라.
- 성능 저하를 피하기 위해 Redis 클러스터 환경을 고려하라.