블로킹/비블로킹, 동기/비동기 관점에서 본 Redis 메시지 큐
2025. 8. 6. 12:56

1. Redis 메시지 Queue 구조

:   Spring Boot 프로젝트에서 메일 전송 작업을 큐로 처리하는 예시

  • 구성요소
    • Producer : 작업 요청을 생성해 Redis 큐에 삽입 (`LPUSH`)
    • Redis : 중간의 Queue 역할 (List 자료 구조)
    • Consumer : 큐에서 작업을 꺼내서 처리 (`BRPOP`)
[사용자 또는 서비스 요청]
      ↓
[Producer: 작업 생성]
      ↓  LPUSH taskQueue "이메일 전송 요청"
[Redis Queue]
      ↑  BRPOP taskQueue 0
[Consumer: 작업 처리 → 이메일 전송 등]
  • 동작 흐름
    • LPUSH : 작업을 큐에 넣음
    • BRPOP : 큐가 비어있으면 기다림(blocking) -> 작업이 들어오면 꺼냄
    • Consumer가 처리하면, 큐에서 삭제됨
  • 메시지 큐의 장점
    • 비동기 처리
      • 요청과 실제 작업 처리를 분리
      • 사용자 응답과 백엔드 로직이 독립적으로 실행
      • 예 : 사용자가 이메일 전송 버튼을 클릭해도, 실제 전송은 나중에 처리됨
    • 빠른 사용자 응답
      • Redis는 인메모리 DB이므로 삽입 속도가 매우 빠름
      • 사용자에게 바로 응답(작업은 나중에) -> UX 향상 
    • 재시도 및 복구
      • 작업이 Redis 큐에 저장되어 있기 때문에, Consumer가 잠시 중단되더라도 데이터가 유실되지 않음
      • 예외 발생 시 재처리하거나, 장애 복구 후 다시 실행 가능
    • 확장성 (수평 확장)
      • 여러 Consumer가 동시에 큐를 병렬 처리
      • 작업량 증가 시, Consumer만 늘리면 처리량 증가 

2. 관점별 분석 - 블로킹 / 비블로킹 관점

: 블로킹/비블로킹은 스레드 단위의 동작 방식 차이를 설명하는 개념

  • Producer : LPUSH
    • 비블로킹
    • 데이터를 Redis 큐에 즉시 삽입한 후 리턴. 스레드는 멈추지 않고 계속 다음 코드 실행
  • Consumer : BRPOP
    • 블로킹
    • 데이터가 없으면 스레드는 대기 상태로 멈춤. 데이터가 들어오면 바로 처리

✍🏻Redis에서 Blocking/Non-blocking 명령어

  • 블로킹 명령어 : BLPOP / BRPOP
    • Blocking List POP
    • 리스트가 비어있으면 데이터가 들어올 때까지 기다림
    • `BRPOP myQueue 0`
      • myQueue가 비어있으면 0초( == timeout 무제한) 동안 대기
      • 누군가 `LPUSH myQueue "작업1"`하면 즉시 리턴
  • 논블로킹 명령어 : LPOP / RPOP
    • 리스트가 비어있으면 즉시 null 반환
    • 대기하지 않고 바로 반환하므로, 논블로킹 방식

3. 관점별 분석 - 동기 / 비동기 관점

: 동기/비동기는 함수 호출 흐름 관점에서 결과를 기다리는지 아닌지 설명하는 개념

  • Producer : LPUSH
    • 동기
    • Producer는 LPUSH를 호출하고 결과를 확인한 뒤에야 다음 로직으로 넘어감
  • Consumer : BRPOP
    • 비동기
    • Consumer는 백그라운드에서 독립된 흐름으로 별도의 스레드에서 대기하며 처리함

4. 정리

Redis 메시지 큐 구조는 비동기 + 블로킹 구조임

(Producer는 동기+비블로킹, Consumer는 비동기+블로킹)

  • Producer와 Consumer가 독립적으로 처리 (작업이 동시에 진행 가능) -> 비동기
  • Consumer가 데이터를 기다리며 대기 -> 블로킹
LIST