Projects/hub-eleven

Redisson은 왜 Redis Pub/Sub을 이용해 재시도(Retry) 로직을 구현할 수 있을까?

annovation 2026. 6. 24. 23:36

Redis와 Redisson

Redis는 메모리 기반 Key-Value NoSQL 데이터베이스이다.

데이터를 메모리에 저장하기 때문에 매우 빠른 읽기/쓰기 성능을 제공하며 캐시, 세션 저장소, Pub/Sub, 분산 락 등에 자주 사용된다.

Redisson은 Java 환경에서 Redis를 쉽게 사용할 수 있도록 제공하는 Client 라이브러리이다.

Client 라이브러리란 애플리케이션과 외부 시스템 사이의 통신을 추상화하여 개발자가 쉽게 사용할 수 있도록 도와주는 라이브러리를 의미한다.

예를 들어 개발자는

lock.lock();

만 호출하지만 실제로는 Redisson이 Redis 명령어를 생성하여 Redis 서버와 통신한다.

Java Application
       ↓
    Redisson
       ↓
 Redis Command
       ↓
     Redis

참고 문서


Redis 분산 락과 SET NX

Redis 분산 락은 일반적으로 SET NX 명령을 이용하여 구현된다.

SET lock:product:1 serverA NX

NX(Not Exists)는

“해당 Key가 존재하지 않을 때만 저장”

이라는 의미이다.

A 서버와 B 서버가 동시에 락 획득을 시도하면

A 서버 → 성공

B 서버 → 실패

가 된다.

이미 A가 Key를 생성했기 때문이다.

Key 생성 성공
=
락 획득 성공

으로 이해할 수 있다.

참고 문서


EX(PX)를 사용하는 이유

만약 TTL 없이 락을 생성했다면

SET lock:product:1 serverA NX

A 서버가 장애로 종료되었을 때 락이 영구적으로 남을 수 있다.

A 서버 락 획득

↓

서버 장애

↓

unlock() 실패

↓

락 영구 유지

이를 방지하기 위해 TTL을 설정한다.

SET lock:product:1 serverA NX EX 30

EX는 초(second),

PX는 밀리초(milliseconds) 단위 TTL을 의미한다.

TTL이 지나면 Redis가 자동으로 락을 제거한다.

참고 문서


Redisson Watchdog

TTL만 설정하면 또 다른 문제가 발생한다.

TTL : 30초

실제 작업 시간 : 60초

작업이 끝나기 전에 TTL이 만료되면 다른 서버가 락을 획득할 수 있다.

이를 해결하기 위해 Redisson은 Watchdog 기능을 제공한다.

Watchdog은 락을 보유한 스레드가 살아있는 동안 TTL을 자동으로 연장한다.

작업 중

↓

TTL 연장

↓

작업 중

↓

TTL 연장

덕분에 작업 시간이 예상보다 길어져도 락이 중간에 해제되지 않는다.

참고 문서


Polling이란?

Polling은 특정 자원의 상태를 주기적으로 확인하는 방식이다.

예를 들어

문 열렸어?

↓

아직

↓

문 열렸어?

↓

아직

처럼 계속 확인하는 것이다.

여기서 Resource는 상태를 확인하려는 대상이다.

Redis 분산 락에서는

lock:123

이라는 락 자체가 Resource가 된다.

참고 문서


Redis를 계속 조회한다는 의미

Polling 방식에서는 락 획득에 실패하면 반복적으로 Redis에 명령을 보낸다.

예를 들어

while(true){

    tryLock();

    Thread.sleep(100);

}

와 비슷한 형태이다.

실제로는

SET lock:123 NX

명령을 계속 보내면서 락 획득을 시도한다.

즉 “Redis를 계속 조회한다”는 말은

Redis에 반복적으로 명령을 보내 락 상태를 확인하거나 락 획득을 시도한다는 의미이다.

참고 문서


Redis Pub/Sub

Redis는 Publish / Subscribe 메시징 모델을 제공한다.

구성 요소는 다음과 같다.

Publisher

메시지를 발행하는 주체

Subscriber

메시지를 구독하는 주체

Channel

메시지가 전달되는 통로

Subscriber는

SUBSCRIBE lock:123

명령을 통해 채널을 구독한다.

이후 Publisher가

PUBLISH lock:123 unlock

명령을 실행하면 Redis는 해당 채널을 구독하고 있는 클라이언트에게 메시지를 전달한다.

참고 문서


락 채널을 구독한다는 의미

Redisson은 락 획득에 실패하면 Polling 방식으로 Redis를 계속 조회하지 않는다.

대신 해당 락과 연결된 Pub/Sub 채널을 구독한다.

락 획득 실패

↓

"락이 해제되면 알려줘"

↓

대기

상태가 된다.

이것이 “락 채널을 구독한다”는 의미이다.

참고 문서


Publish는 누가 수행하는가?

많은 사람들이 Redis가 Publish를 수행한다고 생각하지만 정확히는 다르다.

실제 흐름은 다음과 같다.

lock.unlock();

Redisson

PUBLISH lock-channel unlock

명령 실행

Redis

구독자에게 메시지 전달

Publish 명령 실행
=
Redisson

메시지 전달
=
Redis

이다.

참고 문서


Redisson이 재시도 로직을 구현할 수 있는 이유

Redisson은 락 획득에 실패하면 Polling 방식으로 Redis를 계속 조회하지 않는다.

대신 Pub/Sub 채널을 구독하고 대기한다.

이후 락을 보유한 클라이언트가 unlock()을 호출하면 Redisson이 Publish를 수행한다.

Redis는 해당 메시지를 구독 중인 클라이언트에게 전달한다.

메시지를 받은 클라이언트는 다시 SET NX 기반의 락 획득을 시도한다.

락 획득 실패

↓

Subscribe

↓

대기

↓

unlock()

↓

Publish

↓

메시지 수신

↓

SET NX 재시도

↓

락 획득 성공

결국 Redisson은 Redis Pub/Sub을 이용하여 Polling 없이 효율적인 재시도 구조를 구현할 수 있다.

참고 문서