Redis 메시징 대결 - 이벤트 기반 아키텍처를 위한 Pub/Sub vs Streams
James Reed
Infrastructure Engineer · Leapcell

소개
현대 소프트웨어 아키텍처의 역동적인 환경에서 이벤트 기반 시스템은 확장 가능하고 탄력적이며 반응성이 뛰어난 애플리케이션을 구축하는 초석으로 부상했습니다. 이러한 시스템의 핵심에는 효율적인 메시지 전달이 있으며, 이를 통해 분산된 구성 요소가 통신하고 변경 사항에 반응할 수 있습니다. 뛰어난 성능과 다재다능한 데이터 구조로 유명한 Redis는 메시지 브로커링을 위해 두 가지 매력적인 옵션, 즉 Pub/Sub와 Streams를 제공합니다. 둘 다 통신을 촉진하지만 근본적으로 다른 메시징 패러다임을 제공합니다. Pub/Sub는 '발행 후 즉시 잊어버리는' 브로드캐스트를 위한 것이고, Streams는 영구적이고 순서가 지정된 이벤트 로그를 위한 것입니다. 이러한 미묘한 차이를 이해하는 것은 이벤트 기반 설계에서 Redis의 잠재력을 최대한 활용하려는 모든 개발자에게 중요합니다. 이 기사에서는 이러한 두 메커니즘을 분석하고, 원칙, 구현 및 이상적인 사용 사례를 탐구하여 정보에 입각한 아키텍처 결정을 내릴 수 있도록 지원합니다.
Redis의 메시징 패러다임
세부 사항에 들어가기 전에 논의의 기초가 되는 핵심 개념을 명확히 이해해 봅시다.
발행-구독(Pub/Sub) 모델: 이는 발신자(발행자)가 메시지를 특정 수신자(구독자)에게 직접 보내지 않는 고전적인 비동기 메시징 패턴입니다. 대신, 누가 듣고 있는지 알지 못한 채 카테고리 또는 주제로 메시지를 발행합니다. 구독자는 하나 이상의 카테고리에 관심을 표현하고 해당 카테고리에 발행된 모든 메시지를 수신합니다. 이는 브로드캐스트 메커니즘입니다.
메시지 큐 / 로그: 메시지 큐 또는 더 일반적으로 메시지 로그는 서버리스 및 마이크로서비스 아키텍처에서 사용되는 비동기 서비스 간 통신 형식입니다. 메시지는 소비자에 의해 처리되고 삭제될 때까지 큐 또는 로그에 영구적으로 저장됩니다. 이를 통해 안정성을 보장하고 생성자가 오프라인 상태인 경우에도 여러 소비자가 메시지를 처리할 수 있습니다.
이제 Redis가 이러한 패러다임을 어떻게 구현하는지 살펴보겠습니다.
Redis Pub/Sub: 발행 후 즉시 잊어버리는 브로드캐스트
Redis Pub/Sub는 실시간 알림 및 브로드캐스트를 위해 설계된 직관적이고 메모리 내 메시징 시스템입니다.
원칙: 클라이언트가 채널에 메시지를 PUBLISH할 때 Redis는 즉시 해당 메시지를 해당 채널에 현재 구독 중인 모든 클라이언트로 보냅니다.
주요 특징:
- 발행 후 즉시 잊어버림: 메시지가 지속되지 않습니다. 메시지가 발행될 때 채널에 구독 중인 클라이언트가 없으면 메시지는 손실됩니다.
- 분리: 발행자와 구독자는 서로를 전혀 알지 못합니다.
- 확장성: 네트워크 대역폭과 클라이언트 처리 속도로만 제한되는 대규모 구독자 및 메시지 처리량을 처리할 수 있습니다.
구현 예시:
간단한 redis-cli 명령으로 설명해 보겠습니다.
-
구독자 1:
redis-cli SUBSCRIBE chat_room_1이제 이 클라이언트는
chat_room_1에 대한 메시지를 기다리고 있습니다. -
구독자 2 (다른 터미널에서):
redis-cli SUBSCRIBE chat_room_1이 클라이언트도 동일한 채널에 구독합니다.
-
게시자 (세 번째 터미널에서):
redis-cli PUBLISH chat_room_1 "Hello everyone in chat_room_1!"구독자 1과 구독자 2 모두 즉시 다음을 수신합니다.
1) "message" 2) "chat_room_1" 3) "Hello everyone in chat_room_1!"PUBLISH명령 이후에 클라이언트가 구독하는 경우, "Hello everyone..." 메시지를 받지 못합니다.
애플리케이션 시나리오:
- 실시간 채팅 애플리케이션: 온라인 사용자에게 즉시 메시지 전달.
- 실시간 점수판/피드: 활성 사용자에게 업데이트 푸시.
- 캐시 무효화: 기본 데이터 변경 시 로컬 캐시를 새로고침하도록 애플리케이션 인스턴스에 알림.
- 이벤트 알림: 일시적인 처리를 위해 관심 있는 서비스에 즉시 경고(예: "새 주문 접수") 전송.
Redis Streams: 영구적이고 순서가 지정된 이벤트 로그
Redis 5.0에 도입된 Redis Streams는 append-only 로그 역할을 하는 보다 강력하고 내구성 있는 메시징 솔루션을 제공합니다.
원칙: 메시지(엔트리)는 고유 ID가 태그된 순서대로 스트림의 끝에 추가됩니다. 소비자는 스트림의 어느 지점에서든 읽을 수 있으며 자체 읽기 진행 상황을 제어합니다.
주요 특징:
- 영구성: 메시지는 명시적으로 제거되거나 트리밍될 때까지 스트림에 저장되어 내구성을 제공합니다.
- 순서 지정: 엔트리는 진입 ID별로 순서가 보장됩니다.
- 다중 소비자/소비자 그룹: 여러 독립적인 소비자가 동일한 메시지를 처리할 수 있으며, 소비자 그룹은 작업자 간의 처리를 조정하여 내결함성과 로드 밸런싱을 제공합니다.
- 인지된 처리: 소비자는 메시지를 처리된 것으로 표시하여 인지함으로써 안정적인 전달에 필수적입니다.
- 히스토리 재생: 새 소비자는 스트림 시작부터 전체 이벤트 히스토리를 읽을 수 있습니다.
Streams의 핵심 용어:
- 엔트리 ID: 스트림의 각 메시지의 고유 식별자이며, 일반적으로 타임스탬프-시퀀스 쌍(예:
1678886400000-0)입니다. 순서를 결정합니다. - 소비자: 스트림에서 메시지를 읽는 클라이언트입니다.
- 소비자 그룹: 스트림 처리를 협력하는 소비자들의 논리적 그룹입니다. 소비자 그룹에 전달된 메시지는 멤버 간에 분배되며, 한 멤버만 특정 메시지를 처리합니다.
- 보류 중인 엔트리 목록(PEL): 소비자 그룹의 경우, 이 목록은 전달되었지만 아직 인지되지 않은 엔트리를 보유합니다. 소비자 실패로부터 복구하는 데 필수적입니다.
구현 예시:
-
스트림에 메시지 추가:
redis-cli XADD mystream * sensor_id 123 temperature 25.5 # '*'는 Redis가 새 고유 엔트리 ID를 생성함을 의미합니다. # 응답: "1678886400000-0" (예시 ID)각
XADD명령은 키-값 쌍으로 엔트리를 추가합니다. -
스트림에서 읽기 (소비자 그룹 사용):
먼저 소비자 그룹을 생성합니다.
redis-cli XGROUP CREATE mystream mygroup 0-0 MKSTREAM # '0-0'은 스트림 시작부터 읽음을 의미합니다. # 'MKSTREAM'은 스트림이 존재하지 않는 경우 생성합니다.이제
mygroup의 소비자가 읽을 수 있습니다.redis-cli XREADGROUP GROUP mygroup consumer1 mystream > COUNT 1 # 'consumer1'은 이 특정 소비자의 이름입니다. # '>'는 이 소비자 그룹에 아직 전달되지 않은 새 메시지를 읽음을 의미합니다. # 'COUNT 1'은 최대 1개의 메시지를 요청합니다.예시 응답 (메시지가 추가된 후):
1) 1) "mystream" 2) 1) 1) "1678886400000-0" 2) 1) "sensor_id" 2) "123" 3) "temperature" 4) "25.5" -
메시지 인지: 처리 후 소비자는 메시지를 인지합니다.
redis-cli XACK mystream mygroup 1678886400000-0 # 'mygroup'에 대해 지정된 ID의 메시지를 승인합니다.
애플리케이션 시나리오:
- 이벤트 소싱: 애플리케이션의 모든 상태 변경에 대한 완전한 순서가 지정된 로그 저장.
- 변경 데이터 캡처(CDC): 데이터베이스 변경 사항을 이벤트 스트림으로 기록.
- 안정적인 작업 큐: 소비자 실패 시에도 작업이 정확히 한 번 처리되도록 보장.
- 마이크로서비스 통신: 서비스 간의 내구성 있고 순서가 지정된 메시지 교환.
- IoT 데이터 수집: 센서 데이터 스트림 수집 및 처리.
Pub/Sub 와 Streams 선택하기
Redis Pub/Sub와 Streams 간의 선택은 메시지 영구성, 전달 보장 및 소비 패턴에 대한 특정 요구 사항에 달려 있습니다.
| 기능 / 측면 | Redis Pub/Sub | Redis Streams |
|---|---|---|
| 영구성 | 없음 (발행 후 즉시 잊어버림) | 영구적 (메시지 저장) |
| 순서 | 여러 발행자 간에 보장되지 않음 | 진입 ID로 보장됨 |
| 전달 | 최대 한 번 (구독자가 없으면 메시지 손실) | 최소 한 번 (인지 및 소비자 그룹 사용) |
| 소비자 추적 | 없음 (구독자는 익명) | 고급 (소비자 그룹은 오프셋 및 보류 중인 메시지 추적) |
| 소비자 복구 | 손실된 메시지 복구 불가 | 보류 중인 메시지 다시 읽기 가능 |
| 확장성 | 실시간 브로드캐스트를 위한 높은 팬아웃 | 영구 이벤트 로그를 위한 높은 처리량; 소비자 그룹과 함께 확장 |
| 복잡성 | 간단한 API | 더 복잡한 API (소비자 그룹, PEL, 트리밍) |
| 이상적인 사용 사례 | 실시간 알림, 일시적인 이벤트, 채팅 | 이벤트 소싱, CDC, 안정적인 큐, IoT 데이터 처리 |
메시지 손실이 허용 가능하고 영구성이 필요 없으며 간단하고 가벼운 알림의 경우, Pub/Sub는 단순성과 높은 성능으로 인해 훌륭한 선택입니다. 내구성, 전달 보장, 재생 가능성 및 여러 소비자와 내결함성을 갖춘 복잡한 소비 패턴을 요구하는 시나리오의 경우 Redis Streams가 명백한 승자입니다. 이렇게 하면 보다 강력하고 기능이 풍부한 이벤트 기반 아키텍처 구축 기반을 제공합니다.
결론
Redis Pub/Sub와 Streams 모두 프로세스 간 통신에 강력한 도구이지만 뚜렷한 목적을 제공합니다. Pub/Sub는 최소한의 오버헤드로 일시적인 이벤트를 브로드캐스트하는 데 뛰어나 실시간, 발행 후 즉시 잊어버리는 시나리오에 적합합니다. 반면에 Streams는 내구성이 있고 순서가 지정된 유연한 이벤트 로그를 제공하여 탄력적이고 이벤트 소싱되며 데이터 집약적인 애플리케이션을 구축하는 데 필수적입니다. 개별 강점과 약점을 이해함으로써 개발자는 Redis를 효과적으로 활용하여 효율적이고 확장 가능한 이벤트 기반 시스템을 구축할 수 있습니다. 작업에 맞는 도구(빠른 브로드캐스트 또는 영구 이벤트 로그)를 선택하는 것은 견고한 시스템 설계를 위해 매우 중요합니다.

