Blog
Anki
Redis

Redis 7.x ShardedPubSub 핵심 정리

Redis 7.x에서 새로 도입된 ShardedPubSub이 무엇이고 왜 필요한가요?

꼬리 질문
  • 기존 PubSub의 한계점은 무엇이었나요?
  • ShardedPubSub은 어떤 환경에서 특히 유용한가요?

답변 보기

✅ ShardedPubSub은 Redis Cluster 환경에서 메시지를 특정 샤드(슬롯) 그룹으로만 제한하여 브로드캐스팅하는 새로운 Pub/Sub 메커니즘입니다.

  • 메시지가 모든 노드가 아닌 특정 샤드에만 전파되어 네트워크 오버헤드를 크게 감소시킵니다 📉
  • CRC16 해싱을 사용하여 채널이 속할 슬롯을 결정하고, 해당 슬롯을 담당하는 노드들에게만 메시지를 전달합니다
  • 꼬리질문: 기존 PubSub의 한계점은 무엇이었나요?
    • 기존 PubSub은 메시지를 클러스터의 모든 노드에 브로드캐스팅했습니다 📡
    • 노드 수가 증가할수록 네트워크 트래픽이 기하급수적으로 증가하는 문제가 있었습니다
    • 불필요한 메시지 전파로 인한 성능 저하가 발생했습니다
  • 꼬리질문: ShardedPubSub은 어떤 환경에서 특히 유용한가요?
    • 대규모 Redis Cluster 환경에서 매우 효과적입니다 🏢
    • 특정 데이터와 관련된 이벤트를 처리할 때 유용합니다
    • 채널별로 메시지 격리가 필요한 멀티테넌트 환경에 적합합니다

ShardedPubSub과 기존 PubSub의 주요 차이점은 무엇인가요?

꼬리 질문
  • 명령어 사용법은 어떻게 다른가요?
  • 성능상 어떤 개선이 있나요?

답변 보기

✅ ShardedPubSub과 기존 PubSub의 핵심 차이점은 Redis Cluster 환경에서의 메시지 라우팅 방식입니다.

기존 PubSub의 동작 방식 📡

  • Redis Cluster 환경에서 PUBLISH를 실행하면 클러스터의 모든 노드로 메시지가 브로드캐스팅됩니다
  • 예시: 노드 A, B, C가 있는 클러스터에서
    1. 클라이언트가 노드 C에 PUBLISH channel1 "hello" 실행
    2. 노드 C가 메시지를 노드 A, B에도 전달 (브로드캐스트)
    3. 각 노드에 연결된 channel1 구독자 모두가 메시지 수신
  • 장점: 구독자가 어느 노드에 연결되어 있든 모든 메시지를 받을 수 있음
  • 단점: 노드 간 불필요한 네트워크 트래픽 발생, 노드 수에 비례하여 부하 증가

ShardedPubSub의 동작 방식 🎯

  • 채널 이름이 특정 해시 슬롯에 매핑되고, 해당 슬롯을 소유한 샤드에만 메시지 전달
  • 예시: 동일한 노드 A, B, C 클러스터에서
    1. channel1이 슬롯 5000에 매핑되고, 노드 B가 슬롯 5000 소유
    2. 클라이언트가 노드 C에 SPUBLISH channel1 "hello" 실행
    3. 메시지가 노드 B에만 전달 (노드 A로는 전달 안됨)
    4. 노드 B에 연결된 channel1 구독자만 메시지 수신
  • 장점: 네트워크 효율성 극대화, 확장성 우수
  • 단점: 구독자는 올바른 샤드에 연결해야 메시지를 받을 수 있음

명령어 차이:

  • 기존: SUBSCRIBE, PUBLISH
  • Sharded: SSUBSCRIBE, SPUBLISH

성능 차이:

  • 네트워크 부하: 기존 PubSub은 높음 ⬆️ (모든 노드로 브로드캐스트), ShardedPubSub은 낮음 ⬇️ (특정 샤드만)

  • 확장성: 기존 PubSub은 제한적 (노드 수 증가 시 부하 급증), ShardedPubSub은 우수 (부하 일정 유지)

  • 꼬리질문: 명령어 사용법은 어떻게 다른가요?

    • 기존 PubSub: SUBSCRIBE channel, PUBLISH channel message
    • ShardedPubSub: SSUBSCRIBE channel, SPUBLISH channel message
    • 's' 접두사가 붙은 것 외에는 사용법이 동일합니다
    • 채널 이름에 따라 자동으로 적절한 샤드로 라우팅됩니다
  • 꼬리질문: 성능상 어떤 개선이 있나요?

    • 노드 간 브로드캐스트가 제거되어 네트워크 트래픽이 대폭 감소합니다 🔄
    • 노드 수가 10개인 경우: 기존 PubSub은 10배 전파 vs ShardedPubSub은 1개 샤드만 전파
    • 특히 노드 수가 많을수록 성능 향상이 두드러집니다
    • 메시지 전파 지연시간이 감소합니다

ShardedPubSub은 클러스터에서 어떻게 동작하나요?

꼬리 질문
  • MOVED 리다이렉션은 어떻게 처리되나요?
  • Primary와 Replica 노드에서의 동작은 어떻게 다른가요?

답변 보기

✅ ShardedPubSub은 CRC16 해싱을 통해 채널을 특정 슬롯에 매핑하고, 해당 슬롯을 담당하는 샤드 그룹 내에서만 메시지를 전파합니다.

  • 동작 과정:
  1. 채널 이름을 CRC16으로 해싱하여 슬롯 번호 결정 (0-16383) 🎯
  2. 해당 슬롯을 담당하는 Primary 노드 식별
  3. Primary와 그 Replica들로 구성된 샤드 그룹 내에서만 메시지 전파
  4. 다른 샤드의 노드들은 메시지를 받지 않음
  • 꼬리질문: MOVED 리다이렉션은 어떻게 처리되나요?
    • 클라이언트가 잘못된 노드에 연결하면 -MOVED 응답을 받습니다
    • 예: -MOVED 12539 127.0.0.1:6382
    • 클라이언트는 이 정보로 올바른 노드로 재연결해야 합니다
    • Smart Client는 이를 자동으로 처리합니다
  • 꼬리질문: Primary와 Replica 노드에서의 동작은 어떻게 다른가요?
    • Primary: 직접 메시지를 받고 Replica들에게 전파합니다
    • Replica: Primary로부터 메시지를 받아 구독자에게 전달합니다
    • 동일 샤드 내의 모든 노드가 메시지를 처리할 수 있습니다
    • Failover 시에도 메시지 전달이 유지됩니다

ShardedPubSub을 사용할 때 주의사항과 한계점은 무엇인가요?

꼬리 질문
  • 언제 ShardedPubSub을 사용하고, 언제 기존 PubSub을 사용해야 하나요?
  • 패턴 구독(Pattern Subscribe)은 지원되나요?

답변 보기

✅ ShardedPubSub은 강력한 기능이지만 모든 상황에 적합한 것은 아니며, 몇 가지 제약사항이 있습니다.

  • 주요 한계점:
    • 채널이 특정 샤드에 고정되어 유연성이 제한됩니다 🔒
    • 패턴 구독을 지원하지 않습니다 ❌
    • 클라이언트가 클러스터 토폴로지를 알아야 합니다
    • 여전히 대규모 Pub/Sub 시스템에는 구조적 한계가 있습니다
  • 주의사항:
    • 샤드 간 메시지 격리로 인해 글로벌 브로드캐스트가 불가능합니다
    • 채널명 설계 시 해시 분산을 고려해야 합니다
    • Hot Shard 문제가 발생할 수 있습니다 🔥
  • 꼬리질문: 언제 ShardedPubSub을 사용하고, 언제 기존 PubSub을 사용해야 하나요?
    • ShardedPubSub 사용:
      • 대규모 클러스터 환경 ✅
      • 채널별 격리가 필요한 경우 ✅
      • 네트워크 오버헤드를 줄여야 할 때 ✅
    • 기존 PubSub 사용:
      • 모든 노드에 브로드캐스트가 필요한 경우 ✅
      • 패턴 구독이 필요한 경우 ✅
      • 작은 규모의 클러스터 ✅
  • 꼬리질문: 패턴 구독(Pattern Subscribe)은 지원되나요?
    • ShardedPubSub은 패턴 구독을 지원하지 않습니다 ❌
    • SPSUBSCRIBE 같은 명령어는 존재하지 않습니다
    • 패턴 구독이 필요하다면 기존 PubSub을 사용해야 합니다
    • 이는 샤드 기반 라우팅과 패턴 매칭의 기술적 충돌 때문입니다

ShardedPubSub 사용 예시와 실제 구현 시 고려사항은 무엇인가요?

꼬리 질문
  • 실제 코드에서는 어떻게 사용하나요?
  • 마이그레이션 전략은 어떻게 세워야 하나요?

답변 보기

✅ ShardedPubSub은 기존 PubSub과 유사한 인터페이스를 제공하지만, 클러스터 환경에 최적화된 사용 패턴이 필요합니다.

  • 기본 사용 예시:
# 구독
SSUBSCRIBE user:1234:events
 
# 발행
SPUBLISH user:1234:events "login successful"
  • 구현 시 고려사항:
    • 채널명에 데이터 키를 포함시켜 동일 샤드 보장 🎯
    • Connection Pool을 샤드별로 관리
    • Retry 로직과 Failover 처리 구현
    • 모니터링과 메트릭 수집 체계 구축 📊
  • 꼬리질문: 실제 코드에서는 어떻게 사용하나요?
    • Python 예시 (redis-py):
    # ShardedPubSub 사용
    pubsub = redis_client.sharded_pubsub()
    pubsub.ssubscribe("channel:123")
     
    # 메시지 발행
    redis_client.spublish("channel:123", "message")
    • 클라이언트 라이브러리가 ShardedPubSub을 지원하는지 확인 필요
    • 자동 재연결과 에러 처리 구현 필수
  • 꼬리질문: 마이그레이션 전략은 어떻게 세워야 하나요?
    • 단계적 마이그레이션:
    1. 신규 기능부터 ShardedPubSub 적용
    2. 트래픽이 적은 채널부터 순차 전환
    3. 듀얼 모드로 일정 기간 운영 후 완전 전환
    • 체크리스트:
      • 클라이언트 라이브러리 업그레이드 ✅
      • 채널명 규칙 재설계 ✅
      • 모니터링 대시보드 준비 ✅
      • 롤백 계획 수립 ✅

분산락을 사용하는 경우, 락이 풀렸을 때 어떤 방식으로 동작하게 되나요? (락을 획득하게 되나요?)

답변 보기
  • ✅ wait queue에서 대기하다가 이벤트를 받으면 락 획득을 시도한다는 이해는 맞습니다 (Redisson 기준)

  • ❌ thread pool이 반환되면 queue에서 순차적으로 처리한다는 설명은 틀렸습니다

  • 분산락 대기 방식은 구현체에 따라 다릅니다 📚

Lettuce (스핀락 방식) 🔄

  • 99개의 대기 요청들이 실제 큐에서 기다리지 않음
  • 각 요청이 개별적으로 Redis에 반복 요청 (폴링)
  • 1초 동안 50ms마다 시도하면 100개 요청이 약 10,000번 Redis 호출
  • 매우 비효율적이며 Redis에 큰 부하 발생

Redisson (Pub/Sub 방식) 📡

  • 락 획득 실패한 클라이언트들이 Redis 채널을 구독

  • 실제 "대기 큐" 개념에 가까운 구조

  • 락 해제 시 구독자들에게 알림 전송

  • Redis 부하를 크게 줄임

  • 꼬리질문: 이벤트가 발생하면 어떻게 처리되는걸까요?

    • Redisson의 실제 처리 과정은 다음과 같습니다:
      • 락 획득 실패 → threadId를 채널로 구독
      • 락 보유자가 락 해제 → 해당 채널에 메시지 발행
      • 모든 구독자가 동시에 알림 수신
      • 모든 대기 클라이언트가 동시에 락 획득 재시도
      • 결국 경쟁을 통해 하나만 락 획득 성공
  • 꼬리질문: thread pool이 반환되면 queue에서 다음 작업을 꺼내서 처리하는 방식으로 동작하는게 맞나요?

    • ❌ 이 설명은 틀렸습니다
    • 분산락은 순차적 처리가 아닌 경쟁적 처리 방식입니다
      • 일반 작업 큐: FIFO 순서로 하나씩 순차 처리 🏃‍♂️→🏃‍♀️→🚶‍♂️
      • 분산락: 모든 대기자가 동시에 경쟁하여 처리 🏃‍♂️🏃‍♀️🚶‍♂️ (경쟁!)
    • Thread pool은 단일 프로세스 내 스레드 관리 개념
    • 분산락은 여러 서버/프로세스 간 동기화 메커니즘
    • 두 개념은 서로 다른 계층에서 동작하는 별개의 기술입니다

핵심 포인트 💡

  • 분산락의 대기자들은 "순서 보장된 큐"가 아닌 "구독자 집합"
  • 락 해제 시 모든 대기자가 동시에 알림받고 경쟁
  • FIFO 순서를 보장하지 않는 경쟁 기반 시스템

Redis 클러스터의 동작 방식에 대해 설명해주세요

꼬리 질문
  • Redis 클러스터가 Hash 링 대신 Hash Slot을 사용하는 이유는 무엇인가요?
  • MOVED 리다이렉션과 ASK 리다이렉션의 차이점은 무엇인가요?
  • 16,384개의 슬롯 개수를 선택한 이유는 무엇인가요?
  • CRC16 모듈로 연산이 무엇이고 어떤 특징을 갖고 있나요?
답변 보기

제시하신 설명 검토 결과 🔍

  • ✅ Gossip 알고리즘으로 노드 상태 확인
  • ❌ Hash 링 기반 동작 (실제로는 Hash Slot 방식)
  • ✅ GET 요청 리다이렉트
  • ❌ PUT 요청 내부 이동 (실제로는 리다이렉트 방식)

정확한 Redis 클러스터 동작 방식 🎯

  • 16,384개의 Hash Slot 기반으로 데이터 분산
    • CRC16 알고리즘으로 키를 해시하여 슬롯 결정
    • Hash 링(Consistent Hashing)이 아닌 고정 슬롯 방식
  • Gossip 프로토콜로 노드 간 상태 모니터링
    • ping/pong 메시지를 통한 헬스체크
    • PFAIL → FAIL 상태로 장애 감지
  • MOVED 리다이렉션으로 요청 처리
    • GET/PUT 모두 동일한 리다이렉트 방식
    • 내부 자동 전달이 아닌 클라이언트 재요청 방식

꼬리질문: Redis 클러스터가 Hash 링 대신 Hash Slot을 사용하는 이유는 무엇인가요?

  • 구현 단순성: CRC16 모듈로 연산이 Consistent Hashing보다 간단
  • 균등 분산: 테스트 결과 키가 슬롯에 고르게 분산됨
  • 노드 추가/제거 용이성: 슬롯 단위로 마이그레이션 가능
  • 설정 전파 효율성: 16K 슬롯은 2KB 비트맵으로 전송 가능 (65K는 8KB 필요)

꼬리질문: MOVED 리다이렉션과 ASK 리다이렉션의 차이점은 무엇인가요?

  • MOVED: 영구적인 슬롯 이동 완료 시 사용
  • 클라이언트가 슬롯 테이블 업데이트 필요
  • ASK: 일시적인 슬롯 마이그레이션 중 사용
  • 리샤딩(resharding) 과정에서 발생
  • 클라이언트가 일회성으로만 다른 노드에 요청

꼬리질문: 16,384개의 슬롯 개수를 선택한 이유는 무엇인가요?

  • 메모리 효율성: 2KB 비트맵으로 슬롯 정보 저장 가능
  • 네트워크 효율성: Gossip 메시지에 슬롯 정보 포함 시 2KB만 필요
  • 클러스터 규모: 최대 1000개 마스터 노드 지원 목표에 적합
  • 성능 최적화: CRC16의 14비트 활용으로 균등 분산 보장

꼬리질문: CRC16 모듈로 연산이 무엇이고 어떤 특징을 갖고 있나요? 🔢

  • CRC16 정의: 16비트 순환 중복 검사(Cyclic Redundancy Check) 알고리즘
  • 다항식 나눗셈을 기반으로 한 해시 함수
  • 원래는 데이터 오류 검출을 위해 개발됨
  • Redis에서의 활용: CRC16(key) mod 16384로 슬롯 계산
  • 16비트 출력값을 16,384로 나눈 나머지 사용
  • 14비트만 실제 활용 (2^14 = 16,384)
  • 모듈로 2 연산 특징:
  • 일반 뺄셈 대신 XOR 연산 사용
  • 캐리(carry) 비트 무시하여 계산 단순화
  • 하드웨어 구현에 최적화됨
  • 분산 성능:
  • 균등 분포 보장: 다양한 키 패턴에서 고른 분산
  • 빠른 계산: 단순한 비트 연산으로 고속 처리
  • 결정적 결과: 같은 키는 항상 같은 슬롯에 할당

Redis Cluster의 Gossip Protocol은 어떻게 동작하나요?

꼬리 질문
  • PFAIL과 FAIL 상태의 차이점과 전환 조건은 무엇인가요?
  • Gossip 메시지에는 어떤 정보들이 포함되나요?
  • Split Brain 상황을 어떻게 방지하나요?

답변 보기

Gossip Protocol은 Redis Cluster의 노드 간 상태 정보를 교환하는 P2P 통신 프로토콜입니다.

Gossip Protocol의 핵심 동작 원리 🔄

  • 각 노드는 주기적으로 다른 노드들과 정보를 교환
  • 전체 브로드캐스트가 아닌 일부 노드와만 통신 (효율성)
  • 정보가 점진적으로 전파되어 최종적 일관성 달성
  • 중앙 조정자 없이 분산된 방식으로 동작

메시지 타입과 역할 📨

  • PING: 다른 노드에게 자신의 상태 정보 전송
    • 1초마다 랜덤으로 선택된 노드에게 전송
    • 자신의 상태 + 알고 있는 다른 노드들의 정보 포함
  • PONG: PING에 대한 응답
    • 수신 노드의 현재 상태 정보 포함
    • 정보 동기화의 핵심 메커니즘
  • MEET: 새 노드를 클러스터에 추가
    • CLUSTER MEET 명령으로 트리거
    • 핸드셰이크 프로세스 시작
  • FAIL: 노드 장애 확정 메시지
    • 과반수가 동의한 장애를 전체에 알림
    • 즉시 전파 (긴급 메시지)

장애 감지 프로세스 🚨

  1. 타임아웃 감지 (NODE_TIMEOUT/2)
  • 기본값: 15초의 절반인 7.5초
  • 응답이 없으면 PFAIL 상태로 마킹
  1. PFAIL (Possible Fail) 상태
  • 단일 노드의 주관적 판단
  • "이 노드가 문제있는 것 같다"
  • 아직 확정되지 않은 상태
  1. FAIL 확정 조건
  • 과반수 이상의 마스터가 PFAIL로 판단
  • NODE_TIMEOUT 시간 내에 과반수 동의
  • FAIL 메시지가 전체 클러스터에 즉시 전파

꼬리질문: PFAIL과 FAIL 상태의 차이점과 전환 조건은 무엇인가요?

  • PFAIL (Possible Fail) 🤔
    • 개별 노드의 주관적 판단
    • "A가 B를 PFAIL로 본다"는 의미
    • 실제 네트워크 파티션일 수도 있음
    • 복구 가능한 일시적 상태
  • FAIL (Confirmed Fail)
    • 클러스터 전체의 객관적 합의
    • 과반수 마스터가 동일 노드를 PFAIL로 판단
    • Failover 프로세스 자동 시작
    • 해당 노드는 클러스터에서 제외됨
  • 전환 조건 (과반수 감지 메커니즘):
    • 각 노드는 Gossip 메시지로 PFAIL 정보 수집
    • Gossip에 "송신자가 보는 다른 노드들의 상태" 포함
    • PFAIL 보고 수 > 전체 마스터 수 / 2 시 FAIL 확정
    • NODE_TIMEOUT 시간 내 과반수 달성 필요
    • 예: 5개 마스터 중 3개 이상이 PFAIL 판단
    • FAIL 확정 시 즉시 전체 클러스터에 브로드캐스트

꼬리질문: Gossip 메시지에는 어떤 정보들이 포함되나요?

  • 노드 식별 정보 🆔
    • Node ID (40자리 16진수)
    • IP 주소와 포트 번호
    • 클러스터 버스 포트 (기본: 데이터 포트 + 10000)
  • 상태 정보 📊
    • 노드 플래그 (master/slave/pfail/fail)
    • 현재 epoch (클러스터 설정 버전)
    • 담당 슬롯 비트맵 (2KB)
  • 복제 정보 🔗
    • Master Node ID (Replica인 경우)
    • 복제 오프셋 정보
  • 타이밍 정보
    • 마지막 PING/PONG 시간
    • 노드별 타임스탬프

꼬리질문: Split Brain 상황을 어떻게 방지하나요?

  • 과반수 원칙 (Quorum) ⚖️
    • 과반수 마스터가 동의해야 FAIL 확정
    • 과반수가 없으면 쓰기 거부 (cluster-require-full-coverage)
    • 소수 파티션은 자동으로 읽기 전용 모드
    • 홀수 개 마스터 노드 유지 권장 (Redis 공식 문서)
  • Epoch 메커니즘 🔢
    • 각 설정 변경마다 configEpoch 증가
    • "Last failover wins" 원칙: 높은 epoch가 우선권
    • Failover 시 새 마스터는 더 높은 configEpoch 부여
    • 한계: Split Brain을 크게 줄이지만 완전 방지는 불가
    • 출처: Redis Cluster Specification (redis.io)
  • 투표 메커니즘 🗳️
    • Replica 승격에 과반수 마스터 투표 필요
    • NODE_TIMEOUT * 2 동안 재투표 불가
    • 이전 epoch의 투표는 무시
  • 자동 Failover 제한 🛡️
    • Replica는 과반수 마스터와 연결된 경우만 승격
    • 네트워크 파티션된 Replica는 승격 불가
    • 동시 다발적 failover 방지
  • 실제 시나리오 💡
    • 5노드 클러스터가 3:2로 분할
    • 3노드 그룹: 과반수 확보로 정상 운영
    • 2노드 그룹: 과반수 미달로 쓰기 중단
    • 재연결 시 높은 configEpoch 기준으로 일관성 복구
  • Best Practices 📋

Redis Cluster 구조에서 Replica가 있다면 Master 노드에는 쓰기연산만하고 Replica 노드에는 읽기 연산만 하는 방식으로 동작하나요?

꼬리 질문
  • Replica에서 읽기를 활성화하려면 어떻게 해야 하나요?
  • 일반적인 Master-Slave 구조와 Redis Cluster는 어떤 차이가 있나요?
  • Redis Cluster의 데이터 일관성은 어떻게 보장되나요?

답변 보기

아니요, Redis Cluster는 기본적으로 Master 노드가 읽기와 쓰기를 모두 처리합니다.

  • Redis Cluster의 기본 동작 방식

    • Master 노드 📝: 읽기와 쓰기 연산을 모두 처리
    • Replica 노드 💾: 주로 고가용성을 위한 백업 역할 (failover 대비용)
    • Replica는 자동으로 읽기 작업을 분산하지 않음
  • 꼬리질문: Replica에서 읽기를 활성화하려면 어떻게 해야 하나요?

    • READONLY 명령을 사용하면 Replica 노드에서도 읽기 가능
    • READONLY - Replica에서 읽기 허용 (stale 데이터 허용)
    • READWRITE - 다시 일반 모드로 전환
    • 클라이언트가 명시적으로 설정해야 함 ⚠️
    • 약간 오래된 데이터를 읽을 수 있음을 감수해야 함
  • 꼬리질문: 일반적인 Master-Slave 구조와 Redis Cluster는 어떤 차이가 있나요?

    • 일반 Master-Slave: 자동으로 읽기 분산이 가능
    • Redis Cluster:
      • 주 목적은 데이터 샤딩 (데이터를 여러 노드에 분산 저장)
      • Replica는 읽기 분산이 아닌 고가용성이 주목적
      • 읽기 분산을 원하면 클라이언트가 직접 설정 필요
  • 꼬리질문: Redis Cluster의 데이터 일관성은 어떻게 보장되나요?

    • 비동기 복제 방식 사용 🔄
    • Master가 쓰기를 승인 → 이후 Replica로 전파
    • 네트워크 파티션이나 Master 장애 시 쓰기 손실 가능성 존재 ⚡
    • READONLY 사용 시 최신이 아닌 데이터를 읽을 수 있음
    • 강한 일관성(Strong Consistency)을 보장하지 않음

Redis Stream에서 XREAD와 XREADGROUP의 동작 차이는 무엇인가요?

꼬리 질문
  • 1번 컨슈머가 XREAD key1, 2번 컨슈머가 XREAD key1을 실행하고 XADD key1 "hello world"가 발생하면 어떻게 될까요?
  • Consumer Group을 사용하면 채팅방 서비스 구현이 어려운 이유는 무엇인가요?

답변 보기
  • XREAD: Fan-out(브로드캐스트) 방식으로 동작 📡

    • 같은 Stream에 여러 클라이언트가 접근하면 모든 Consumer가 동일한 메시지를 받음
    • 채팅방처럼 모든 참여자에게 메시지를 전달해야 하는 경우에 적합
  • XREADGROUP: 분산 처리 방식으로 동작 ⚡

    • Consumer Group 내에서 각 Consumer가 서로 다른 메시지를 나눠서 처리
    • 작업 부하 분산이나 병렬 처리가 필요한 경우에 적합
  • 꼬리질문: 1번 컨슈머가 XREAD key1, 2번 컨슈머가 XREAD key1을 실행하고 XADD key1 "hello world"가 발생하면 어떻게 될까요?

    • 두 컨슈머 모두 "hello world" 메시지를 받습니다
    • XREAD는 N-client에 대한 fan-out을 제공하기 때문
  • 꼬리질문: Consumer Group을 사용하면 채팅방 서비스 구현이 어려운 이유는 무엇인가요?

    • ❌ Consumer Group은 분산 처리 방식이므로 한 메시지가 한 Consumer에게만 전달됨
    • 채팅방은 브로드캐스트가 필요한데, Consumer Group은 이와 반대로 동작
    • 해결책: Redis Pub/Sub 사용 권장 💬

참조한 내용 (XREAD와 XREADGROUP 차이) (opens in a new tab)
참조한 내용 (XREAD 공식문서) (opens in a new tab)
참조한 내용 (XREADGROUP 공식문서) (opens in a new tab)


Redis Stream의 PEL과 ACK는 무엇이며 어떤 역할을 하나요?

꼬리 질문
  • ACK를 보내면 다음 Consumer가 읽을 stream 위치가 변경되나요?
  • PEL은 언제 생성되고 언제 제거되나요?
  • XREAD로 받은 메시지도 ACK가 필요한가요?

답변 보기
  • PEL(Pending Entries List): Consumer Group에서 전달되었지만 아직 ACK되지 않은 메시지 목록 📋

    • 각 Consumer별로 개별 관리되는 미처리 메시지 리스트
    • 장애 복구와 메시지 재처리를 위한 핵심 메커니즘
  • ACK의 역할: 메시지 처리 완료를 Redis에 알리는 명령어 ✅

    • XREADGROUP으로 받은 메시지에만 사용
    • PEL에서 해당 메시지를 제거하는 용도
  • 꼬리질문: ACK를 보내면 다음 Consumer가 읽을 stream 위치가 변경되나요?

    • ACK는 읽기 위치에 영향을 주지 않습니다
    • Consumer Group의 last_delivered_id는 ACK와 무관하게 증가
    • ACK는 오직 PEL 관리를 위한 목적으로만 사용
  • 꼬리질문: PEL은 언제 생성되고 언제 제거되나요?

    • 생성 시점: XREADGROUP으로 메시지를 읽었을 때 자동 생성 📥
    • 제거 시점: XACK 명령어로 명시적으로 제거 🗑️
    • 제거하지 않으면 메모리 누수와 장애 복구 문제 발생 가능
  • 꼬리질문: XREAD로 받은 메시지도 ACK가 필요한가요?

    • XREAD는 ACK 불필요
    • XREAD는 PEL을 생성하지 않기 때문
    • 오직 XREADGROUP으로 받은 메시지만 ACK 필요

참조한 내용 (PEL과 ACK) (opens in a new tab)
참조한 내용 (Redis Stream 기본) (opens in a new tab)
참조한 내용 (XACK 명령어) (opens in a new tab)


XPENDING과 XCLAIM은 어떻게 활용하며 어떤 차이가 있나요?

꼬리 질문
  • Consumer가 메시지를 받고 처리하다가 실패했을 때의 복구 과정은?
  • XCLAIM은 "재전송"인가요 "소유권 이전"인가요?
  • XAUTOCLAIM과 XCLAIM의 차이점은?

답변 보기
  • XPENDING: Pending된 메시지들을 조회하는 명령어 🔍

    • Consumer Group 내 미처리 메시지 현황 파악
    • 어떤 Consumer가 어떤 메시지를 얼마나 오래 처리 중인지 확인
  • XCLAIM: 메시지의 소유권을 다른 Consumer로 이전하는 명령어 🔄

    • 실패한 Consumer의 메시지를 정상 Consumer가 대신 처리
    • 장애 상황에서 메시지 처리 연속성 보장
  • 꼬리질문: Consumer가 메시지를 받고 처리하다가 실패했을 때의 복구 과정은?

    1. XPENDING으로 미처리 메시지 발견 🕵️‍♂️
    2. XCLAIM으로 정상 Consumer에게 소유권 이전 📮
    3. 새로운 Consumer가 메시지 처리 후 XACK
    4. PEL에서 완전히 제거되어 복구 완료 🎉
  • 꼬리질문: XCLAIM은 "재전송"인가요 "소유권 이전"인가요?

    • ✅ **"소유권 이전"**이 정확한 표현
    • 메시지 자체는 변하지 않고, 담당 Consumer만 변경됨
    • 원래 Consumer의 PEL에서 제거 → 새 Consumer의 PEL로 이동
  • 꼬리질문: XAUTOCLAIM과 XCLAIM의 차이점은?

    • XCLAIM: 수동으로 특정 메시지 ID를 지정해서 소유권 이전
    • XAUTOCLAIM: 일정 시간 이상 Pending된 메시지를 자동으로 claim (Redis 6.2+)
    • XAUTOCLAIM이 더 편리하고 자동화된 방식

참조한 내용 (XPENDING) (opens in a new tab)
참조한 내용 (XCLAIM) (opens in a new tab)
참조한 내용 (XAUTOCLAIM) (opens in a new tab)


Redis Stream의 내부 자료구조는 어떻게 구성되어 있나요?

꼬리 질문
  • Entry ID는 어떤 구조로 되어 있나요?
  • Radix Tree와 Listpack을 사용하는 이유는 무엇인가요?
  • Redis Stream의 메모리 최적화 전략은?

답변 보기
  • Radix Tree of Listpacks: Redis Stream의 핵심 자료구조 🌳

    • Radix Tree: Entry ID 기반의 효율적인 인덱싱과 범위 검색
    • Listpack: 연속된 메모리 블록에 여러 entry를 압축 저장 (Redis 7.0+)
  • 메모리 최적화: 지연 삭제(Lazy Deletion) 전략 사용 🗑️

    • XDEL로 삭제 시 즉시 메모리 해제하지 않고 "삭제 마크" 표시
    • Macro-node 내 모든 entry가 삭제되었을 때만 메모리 회수
  • 꼬리질문: Entry ID는 어떤 구조로 되어 있나요?

    • 2개 부분으로 구성: 밀리초타임스탬프-시퀀스번호
      • ms: 64비트 밀리초 타임스탬프 (현재 시각)
      • seq: 64비트 시퀀스 번호 (동일 밀리초 내 구분용)
      • 예시: 1640995200000-0
  • 꼬리질문: Radix Tree와 Listpack을 사용하는 이유는 무엇인가요?

    • Radix Tree: ID 기반 빠른 검색과 범위 쿼리 지원 🚀
    • Listpack: 메모리 압축으로 공간 효율성 극대화 💾
    • 조합 효과: 빠른 성능 + 낮은 메모리 사용량 달성
  • 꼬리질문: Redis Stream의 메모리 최적화 전략은?

    • 지연 삭제: 즉시 메모리 해제 대신 삭제 마크 표시
    • Listpack 압축: 연속 메모리 사용으로 단편화 방지
    • 단편화 방지: 50% 이상 삭제되면 재구성 권장

참조한 내용 (Redis Stream 인코딩) (opens in a new tab)
참조한 내용 (메모리 최적화) (opens in a new tab)
참조한 내용 (모듈 API) (opens in a new tab)