[Redis] Redis를 메시지 브로커로 사용하기

연유라떼·2025년 8월 25일
post-thumbnail

Message Broker

비동기 통신과 확장성이 중요해진 요즘의 개발에서, 다양한 메시지 브로커가 존재한다.

메시지 브로커는 메시지(데이터)를 송신자(생산자)로부터 수신자(소비자)에게 전달하는 중간 매개체 역할을 하는 소프트웨어이다.

이에 대한 구체적인 내용은 넘어가고 전반적인 흐름만 짚고 넘어가자!


Message Broker의 주요 개념 및 동작 방식

  • 생산자(Producer): 메시지를 생성하여 메시지 브로커에게 보내는 역할

  • 소비자(Consumer): 메시지 브로커로부터 메시지를 수신하고 처리하는 역할

  • 메시지 큐(Message Queue): 생산자가 보낸 메시지가 저장되는 임시 저장소로, 소비자는 이 큐에서 메시지를 가져와 처리하며, 이는 순서대로 쌓이고 순서대로 나간다. 이를 통해 생산자와 소비자의 속도 차이를 조절하고, 메시지 유실을 방지한다.


메시지 브로커의 필요성

메시지 브로커가 없다면, 애플리케이션들은 서로 직접 통신을 해야하고, 이는 동시성의 문제를 직면하거나, 서비스의 부하나 MSA와 같은 구조가 많아지는 요즘의 개발에 여러 문제를 직면할 수 있다.

메시지 브로커의 장점

메시지 브로커의 장점을 다음과 같이 정리할 수 있다.

  • 비동기 통신: 생산자가 메시지를 보내고 즉시 다른 작업에 들어갈 수 있다. 생산자의 입장에서는 메시지 발행 여부만 중요하고, 소비자는 메시지를 나중에 처리한다.

  • 느슨한 결합(Loose Coupling): 생산자와 소비자가 서로를 알 필요 없이 메시지 브로커를 통해 독립적으로 통신이 가능하다.

  • 확장성: 새로운 소비자를 쉽게 추가하여 메시지 처리량 늘리기에 좋다. (소비자 그룹으로 처리하기 때문)

  • 내구성 및 신뢰성: 메시지를 큐에 저장하여 소비자가 메시지를 성공적으로 처리할 때까지 보존하므로, 데이터 유실에 있어서 안정적이다.



이런 메시지 브로커로 대표적인 것에는
RabbitMQ, Kafka, Redis 등이 존재하는데,
이번에는 메시지 브로커로서의 Redis에 대하여 알아볼 것이다.

Redis란?

Redis는 인메모리(In-Memory) 기반 데이터 저장소로서, 속도가 빠르다는 장점을 갖고 있다.

이미지 출처: https://blog.bytebytego.com/p/a-crash-course-in-redis


그리고 데이터의 안전한 보관과 백업을 위해 다른 서버의 메모리에 실시간으로 복사본을 남길 수 있고, 디스크에 저장하는 방법도 제공하는 등 확장성이 높다.

기본적으로 key-value 저장 방식이지만, Lists, Sets, Sorted Sets, Hashes, Streams 같은 다양한 저장 방식을 제공하여 다양한 방식으로 데이터를 활용이 가능하다는 점이 큰 특징이다!




1. Redis Pub/Sub (게시/구독)

레디스 Pub/Sub은 발행-구독 모델을 구현하는 가장 기본적이고 단순한 모델이다.

메시지 발행자(Publisher)는 특정 채널(Channel)에 메시지를 보내고,
구독자(Subscriber)는 해당 채널을 구독해 메시지를 수신한다.


특징

  • 비동기적 통신: 발행자는 구독자의 존재를 알지 못하며, 메시지는 즉시 구독자에게 전달
  • 1:N 통신: 하나의 메시지를 여러 구독자에게 동시에 전달 가능(동일한 채널을 구독한다면 상관 없음)
  • 메시지 유실 가능성: 구독자가 연결이 끊기거나 오프라인 상태일 경우, 해당 기간 동안 발행된 메시지는 유실된다. 메시지의 내구성은 보장되지 않는다.

장점

  • 매우 빠르고 가벼움
    • 별도의 큐나 저장 과정 없이 메시지를 즉시 전달하므로 매우 낮은 지연 시간을 가져 실시간 서비스나 SSE 등 잦은 전달이 필요할 때 사용한다.
  • 간단한 구현
    • 복잡한 설정 없이 채널을 구독하고 메시지를 발행하는 간단한 명령어로 사용 가능하다

단점

  • 메시지 유실: 메시지 유실 가능성 때문에 중요한 메시지를 다루는 데는 적합하지는 않다.
  • 영속성 없음: 메시지가 저장되지 않고 실시간으로 전달되기 때문에 과거 메시지를 조회할 수 없다. 이는 유실과 직결된다.


2. Redis List (리스트)

레디스 List선입선출(FIFO) 구조의 큐(Queue)로 사용될 수 있다.


Lists는 key와 value가 1:N(일대다) 관계로,
value는 입력된 순서대로 저장된다. value 위주로 작동하기에, value가 있으면 키(리스트)가 생성되고, value가 전부 삭제되면 키(리스트)도 알아서 삭제되므로, 별도의 작업이 필요가 없다.

Lists는 주로 큐(Queue)와 스택(Stack)으로 사용된다.

큐(Queue)는 들어오는 데이터를 순서대로 처리할때 사용되며,
스택(Stack)은 웹브라우져의 백버튼 처럼 주로 되돌아 갈때 사용된다.


LPUSH/RPUSH 명령어로 리스트의 앞/뒤에 메시지를 넣고, LPOP/RPOP 명령어로 메시지를 가져오는 방식으로 구현

블로킹 큐를 구현하기 위해 BLPOP/BRPOP 명령어를 사용하면, 메시지가 들어올 때까지 대기할 수 있다.


특징

  • 큐(Queue) 방식: 메시지가 들어온 순서대로 처리
  • 메시지 영속성: 레디스가 재시작되더라도 RDB나 AOF를 통해 메시지가 보존됨
  • 처리 보장: 소비자가 메시지를 명시적으로 가져가서 처리하므로 메시지 유실 가능성이 낮음

장점

  • 간단한 구현: Pub/Sub과 마찬가지로 명령어가 간단하고 직관적
  • 메시지 유실 방지: 소비자가 메시지를 명시적으로 가져가기 때문에 Pub/Sub 방식에 비해 메시지 유실 위험이 적음

단점

  • 단일 소비자: 메시지를 가져가는 순간 리스트에서 삭제되므로, 하나의 메시지를 여러 소비자가 동시에 처리할 수 없음 -> 이것이 느린 컨슈머의 문제로 이어져 서비스 지연의 위험이 존재
  • 단점: 메시지 처리 보장 문제: 소비자가 메시지를 가져간 후 처리에 실패하면, 해당 메시지는 영원히 유실되어 AT-LEAST-ONCE 보장이 어려울 수 있음




3. Redis Stream (스트림)

Redis Stream은 레디스 5.0 버전부터 도입된, 메시지 큐를 위한 가장 진보된 자료구조이다.
메시지 그룹(Consumer Group), 메시지 ID, 메시지 확인(ACK) 등 복잡한 메시징 시스템을 구현하는 데 필요한 기능을 제공하는 등 전형적인 메시지 브로커의 특징을 갖고있다.


특징

  • 다중 소비자: 하나의 스트림에 여러 소비자가 메시지 그룹을 통해 메시지를 가져갈 수 있다. (그룹 기준)
  • 메시지 영속성: 모든 메시지는 스트림에 추가되며, 메시지 ID를 통해 특정 메시지를 조회 가능
  • 메시지 처리 보장: 소비자가 메시지를 처리한 후 XACK 명령을 통해 확인(ACK)을 보내야만 메시지가 완료된 것으로 간주되어, 메시지 유실을 방지하고 AT-LEAST-ONCE 의미론을 지원
  • 메시지 그룹: 여러 소비자가 하나의 메시지 그룹에 속해 메시지를 분산 처리 가능

장점

  • 메시지 유실 방지: 메시지 처리 확인(ACK) 메커니즘을 통해 메시지가 정상적으로 처리되었는지 확인할 수 있어 안정성이 높다.
  • 다중 소비자 지원: 하나의 메시지를 여러 소비자가 병렬로 처리할 수 있어 처리량 제고 가능
  • 재처리 기능: 메시지 처리에 실패한 경우, XPENDING 명령어를 통해 미처리 메시지를 확인하고 재처리 가능

단점

  • 복잡한 명령어: Pub/Sub이나 List에 비해 명령어가 복잡하고 다양한 옵션 필요하여 러닝커브




REF

profile
일단 공부해보겠습니다..

0개의 댓글