Redis 스터디 중에 Pub/Sub이라는 메시징 패턴이 나왔다.
생각보다 여러 곳에서 쓰이는 중요한 개념이라서 제대로 정리해보려고 한다.
Pub/Sub이란?
Pub/Sub은 Publish/Subscribe의 약자로, 발행-구독 패턴을 의미한다.
쉽게 말하면 유튜브 구독 시스템과 비슷하다:
- Publisher (발행자): 유튜버가 영상을 올린다
- Channel (채널): 유튜브 채널
- Subscriber (구독자): 구독자가 알림을 받는다
핵심은 발행자와 구독자가 서로를 모른다는 것이다. 유튜버는 누가 구독하는지 일일이 알 필요 없고, 구독자는 그냥 채널만 구독하면 된다.
왜 필요한가?
강한 결합의 문제
일반적인 방식은 A가 B에게 직접 메시지를 보낸다:
A → B
문제
- A는 B의 존재를 알아야 함
- B가 추가되거나 삭제되면 A의 코드 수정 필요
- C, D가 추가되면? A가 모두 관리해야 함
느슨한 결합
Pub/Sub을 사용하면:
A → [Channel] ← B
← C
← D
장점
- A는 채널에만 메시지 발행하면 됨
- B, C, D는 원하면 구독, 취소 자유로움
- 새로운 구독자 추가해도 A는 코드 수정 불필요
동작 방식
1. 구독 (Subscribe)
구독자가 관심 있는 채널을 구독한다.
"chat:room1 채널 구독할게요"
2. 발행 (Publish)
발행자가 채널에 메시지를 보낸다.
"chat:room1 채널에 '안녕하세요' 발행"
3. 전달 (Deliver)
해당 채널을 구독 중인 모든 구독자에게 메시지 전달
→ 구독자들이 동시에 메시지 받음
Pub/Sub vs 메시지 큐
둘 다 메시징 패턴이지만 차이가 있다:
Pub/Sub
- 실시간 전달: 지금 구독 중인 사람한테만
- 저장 안 함: 메시지 휘발성
- 1:N 구조: 여러 구독자가 동시에 받음
- 용도: 실시간 알림, 채팅, 이벤트 브로드캐스트
메시지 큐 (Message Queue)
- 비동기 처리: 나중에 처리해도 됨
- 저장함: 메시지 영속성
- 1:1 구조: 하나의 소비자만 처리
- 용도: 작업 큐, 백그라운드 처리
Redis Pub/Sub 예시
Redis로 간단하게 구현할 수 있다.
구독하기
SUBSCRIBE chat:room1
발행하기
PUBLISH chat:room1 "안녕하세요"
실행 결과
chat:room1을 구독 중인 모든 클라이언트가 "안녕하세요" 메시지를 받는다.
주의사항: 메시지 유실 가능성
Redis Pub/Sub의 특징:
1. 메시지 비저장성
메시지를 디스크에 저장하지 않는다. 발행되는 순간 활성 구독자에게 전달되고 끝.
2. 구독자가 없으면?
메시지가 발행될 때 구독자가 아무도 없으면 그 메시지는 사라진다.
발행: "안녕하세요"
구독자: 0명
→ 메시지 유실
3. 연결 끊김
구독 중이던 클라이언트의 연결이 끊어지면, 그 사이에 발행된 메시지는 받을 수 없다.
해결책
메시지를 잃어버리면 안 되는 경우:
- Redis Streams 사용 (메시지 저장됨)
- Kafka 같은 메시지 브로커 사용
- 별도 DB에 메시지 저장
사용 사례
1. 실시간 채팅
채팅방마다 채널 생성
→ 사용자가 입장하면 해당 채널 구독
→ 메시지 발행하면 모든 참여자가 받음
2. 실시간 알림
사용자별 알림 채널 생성
→ 사용자가 로그인하면 자기 채널 구독
→ 알림 발생 시 해당 채널에 발행
3. 실시간 데이터 업데이트
주식 가격, 게임 점수 등
→ 구독자들에게 실시간으로 브로드캐스트
다른 사례
Pub/Sub 패턴을 구현한 다양한 기술들:
- Redis Pub/Sub: 간단하고 빠름, 메시지 유실 가능
- Kafka: 대용량 처리, 메시지 저장, 복잡함
- RabbitMQ: 메시지 큐 + Pub/Sub 둘 다 지원
- AWS SNS: 클라우드 Pub/Sub 서비스