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의 핵심 차이점은 메시지 라우팅 방식입니다.

  • 기존 PubSub: 메시지를 모든 노드로 전파

  • ShardedPubSub: 메시지를 특정 샤드에만 전파

  • 명령어 차이:

    • 기존: subscribe, publish
    • Sharded: ssubscribe, spublish
  • 성능 차이:

    • 네트워크 부하: 기존 PubSub은 높음 ⬆️, ShardedPubSub은 낮음 ⬇️
    • 확장성: 기존 PubSub은 제한적, ShardedPubSub은 우수
  • 꼬리질문: 명령어 사용법은 어떻게 다른가요?

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

    • 브로드캐스트 루프가 대폭 감소합니다 🔄
    • 노드 간 통신 오버헤드가 줄어듭니다
    • 특히 노드 수가 많을수록 성능 향상이 두드러집니다
    • 메시지 전파 지연시간이 감소합니다

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)