[ElastiCache] 실시간 알람을 위한 PUB/SUB

2025. 10. 8. 18:44·공부/DATABASE

 

알람 서비스에서 Redis의 PUB/SUB 기능을 사용하여 유저에게 실시간 알람 기능을 구현하였다.

유저 동접수가 증가함에 따라 개발에서 유저별 Redis 커넥션을 생성하였고 Elasticache Redis의 최대 커넥션 수 인 65,000에 가깝게 사용하여 스케일아웃을 진행하여 이슈 대응을 진행하였는데 PUB/SUB 기능과 해당 사용 목적에 대하여 미리 확인하고 이슈 대응 및 구조 개선을 검토 진행.

 

 

(구조 예시)

 

 

 

REDIS PUB/SUB 기능을 사용하여 실시간 유저 알람을 제공하고 있습니다.

현재 구조는 클라이언트(유저별) 채널(토픽)이 생성되어 있습니다

따라서 유저가 증가함에 따라 레디스의 커넥션과 채널이 추가되는 구조입니다.

REDIS PUB/SUB의 커넥션 풀 사용시 GET/SET 같은 일반적인 명령어와는 달리 Sub 요청이 발생했을 때 요청 즉시 커넥션을 만들고 커넥션 풀 안에 저장한 후 유저가 연결을 종료하면 커넥션 풀에서 제거하여 Close 하는 방식으로 처리가 됩니다.

즉 Poolsize, Pooltimeout, min max idleconns 등등이 동작하지 않음.

 

현재 구성

  • 유저 요청마다 토픽을 만들고, 그 토픽에 대해 REDIS 구독 요청.
    • 장점
      • 서버는 자신이 실제로 처리할 계정만 담당하므로, 불필요한 메시지 수신 최소화 → 서버 I/O, CPU 효율적
      • 메모리/네트워크 사용 최적화 → 연결되지 않은 유저의 메시지는 수신하지 않음
    • 단점
      • Redis 연결 수가 많아질 수 있음 → 서버에서 커넥션 관리 필요
  1. REDIS PUB/SUB의 Topic이 다수 생성됨 (접속한 유저마다 토픽 생성)
  2. 접속하지 않은 유저는 토픽 생성 및 작업이 없으므로 이점이 있음
  3. 커넥션이 다수 생성되는 단점이 있음

 

커넥션 수를 줄이기 위해서는 중간의 SSE 통신을 하는 Pod에서 유저를 관리하는 방안이 있습니다.

  • 서비스 시작시 모든 토픽을 구독하고, 메시지 수신하면, 토픽에 맞는 클라이언트 커넥션에 메시지를 분배
    • 장점
      • 요청 수가 많아져도 레디스 커넥션은 늘어나지 않음. 레디스 커넥션은 통합 알림 서버 대수에 의존
    • 단점
      • 불필요한 메시지 수신 발생 → 연결되지 않은 유저 메시지까지 수신 → 네트워크, CPU 낭비
  1. 토픽을 기능마다 생성하고 관리함
  2. 토픽은 구독은 API 서버 기준으로만 할당됨
  3. API 서버에서 모든 유저에 대하여 작업 처리가됨

 

 

아래는 PUB/SUB 기능을 바탕으로 GPT와 사용 방식에 대하여 확인한 내용입니다.

 

일반적으로 사용자는 Redis에 직접 연결하지 않고, 각 Pod가 Redis와 구독 연결을 맺고 사용자와는 SSE/WebSocket으로 통신합니다.

 

1. 사용자별 채널(토픽) 1:1 라우팅

user:{uid} 같은 채널에만 퍼블리시. 각 Pod는 “자기 Pod에 붙어 있는 사용자들”의 채널만 구독.

장점

  • 네트워크/CPU 낭비 최소화: 타깃에게만 전달→ Redis→Pod 간 불필요한 트래픽이 거의 없음.
  • 격리와 보호: 특정 유저/그룹 폭주가 다른 유저들에 미치는 영향이 작음(핫 유저만 해당 Pod/채널이 바쁨).
  • 권한/프라이버시 단순화: 채널 이름 수준에서 자연스러운 경계(잘못된 수신 위험↓).
  • 프레즌스(presence) 판단 용이: 유저 연결 해제 시 해당 채널 구독이 사라져 “온라인 여부” 캐싱/추론이 쉬움.
  • 세밀한 레이트 리밋: 사용자/채널 단위로 손쉽게 속도 제한·드랍 정책을 두기 좋음.

단점 

  • 구독 churn 비용: 접속/이탈이 잦으면 SUBSCRIBE/UNSUBSCRIBE가 빈번해져 Redis와 애플리케이션 양쪽 모두 부하 증가.
  • 채널/구독 메타데이터 급증: 수십/수백만 사용자 동시 접속 시 Redis의 구독 테이블·Pod의 라우팅 테이블 메모리/관리 비용이 커짐.
  • 운영 난이도↑: 모니터링/디버깅(“누가 무엇을 구독했는가”)과 롤링 배포 시 재구독 스톰 등 운영 이슈.
  • 클러스터 환경에서의 브로드캐스트 비용 이슈: (Redis 7 미만 또는 글로벌 Pub/Sub만 쓸 때) 채널 수가 많아지면 클러스터 전파 비용/라우팅 복잡성이 커짐. → Sharded Pub/Sub(SSUBSCRIBE) 사용을 권장.

2. 통합(소수) 채널 + 서버측 필터링

notifications, chat-events 같은 소수 채널에 모든 이벤트를 퍼블리시. 각 Pod가 공통 채널을 구독한 뒤, 메시지 내 타깃(유저/룸/테넌트)을 보고 Pod에서 필터링/팬아웃.

장점 

  • 단순한 구독 구조: 채널·구독 수가 Pod 수 수준이라 설정·모니터링·배포가 쉽다.
  • 구독 churn 거의 없음: 유저 접속/이탈과 무관하게 Pod의 구독은 고정.
  • Redis 메모리/관리 부담↓: 구독 메타데이터가 작다.
  • 메시지 스키마 진화 용이: 이벤트 형식이 변해도 구독 변경 없이 Pod 코드만 배포하면 됨.

단점 

  • 불필요한 전달/필터 비용: 모든 메시지가 모든 Pod로 가서 N(Pod) 배의 네트워크/디코딩/필터링 오버헤드.
  • “핫 채널” 병목: 통합 채널이 고QPS이면 Redis egress와 각 Pod의 소비 속도에 민감. 느린 Pod는 Pub/Sub 출력 버퍼가 차서 끊길 위험.
  • 멀티 테넌시/격리 취약: 한 테넌트의 트래픽이 전체에 영향(스파이크 전파).
  • 보안/권한은 애플리케이션 책임: 올바른 필터링/권한 체크가 코드 버그 없이 항상 이뤄져야 한다.

 

 

3. Pod‑Inbox + Sharded Pub/Sub

불필요한 브로드캐스트를 줄이면서 Redis 구독 수를 O(Pods)로 고정

  1. Presence(접속 위치) 저장
    • 사용자 연결이 열릴 때 connID를 발급하고, “이 연결이 어느 Pod에 붙어있는지”를 Redis에 기록합니다.
    • 예)
      • SETEX conn:{connID} {podID} 120s (TTL은 주기적으로 갱신)
      • HSET presence:user:{userID} {connID} {podID} (사용자→연결 매핑)
      • SADD presence:pod:{podID} {connID} (Pod가 가진 연결 집합)
  2. 각 Pod는 자기 inbox 채널만 SSUBSCRIBE
    • 채널명: pod:{<podID>} 처럼 해시태그({}) 안에 샤드 키를 넣어 특정 슬롯에 고정합니다.
    • 각 Pod는 SSUBSCRIBE pod:{<podID>} 1개만 유지합니다.
  3. Publish 경로(단일/소수 타깃)
    • 발행자가 대상 사용자들의 현재 Pod를 presence에서 조회 → podID -> [connIDs]로 묶기
    • 각 podID에만 SPUBLISH pod:{podID}로 메시지를 보냅니다(최소 전파).
    • Pod는 수신 메시지의 connIDs를 보고 자신의 SSE/WebSocket 연결로만 팬아웃.
  4. Broadcast/대규모 그룹
    • 전역 1개가 아니라 주제/테넌트/대형 룸 단위로 몇십~몇백 개의 Sharded 토픽(예: topic:{tenantA}, room:{123})을 운용하고 해당 토픽을 SSUBSCRIBE.
    • 진짜 전원 방송이 필요할 때만 소수의 통합 채널을 사용.
  5. 내구성이 필요하면
    • Pub/Sub은 at‑most‑once입니다. 오프라인 보관/재전송이 필요하면 Redis Streams로 저장하고, 온라인 경로는 Pub/Sub로 저지연 팬아웃.

'공부 > DATABASE' 카테고리의 다른 글

[Aurora, Elasticache] 대역폭 관련  (0) 2025.10.08
[Aurora PostgreSQL] Toast 테이블과 VACUUM  (0) 2025.10.08
[Aurora PostgreSQL] 파티션 테이블 전환  (0) 2025.10.08
[AWS] DocumentDB Garbage Collection  (0) 2025.07.05
[PostgreSQL] VACUUM 설정 적용 케이스  (5) 2025.07.05
'공부/DATABASE' 카테고리의 다른 글
  • [Aurora, Elasticache] 대역폭 관련
  • [Aurora PostgreSQL] Toast 테이블과 VACUUM
  • [Aurora PostgreSQL] 파티션 테이블 전환
  • [AWS] DocumentDB Garbage Collection
무는빼주세요
무는빼주세요
내 머리를 믿지 말자
  • 무는빼주세요
    공부, 기록
    무는빼주세요
  • 전체
    오늘
    어제
  • 링크

    • 링크드인 (LinkedIn)
    • 분류 전체보기 (259) N
      • 일상 (0)
      • 코딩 (77)
      • 공부 (181) N
        • DATABASE (129) N
        • 도커,쿠버네티스 (1)
        • 소소한 개발 (38)
        • 클라우드 영역 (1)
        • CS 영역 (11)
      • 포럼 (0)
  • 최근 글

  • 인기 글

  • hELLO· Designed By정상우.v4.10.5
무는빼주세요
[ElastiCache] 실시간 알람을 위한 PUB/SUB
상단으로

티스토리툴바