이 글에서 얻는 것

  • Redis Streams가 “Redis로 Kafka 흉내”가 아니라, 작은 이벤트 파이프라인/워크큐로 어디에 적합한지 판단할 수 있습니다.
  • Consumer Group/PEL(Pending Entries List)의 의미를 이해하고, “컨슈머가 죽었을 때” 어떤 메시지가 어떻게 복구되는지 설명할 수 있습니다.
  • at-least-once 처리에서 반드시 필요한 멱등성(idempotency)과 재처리 설계를 기본 형태로 구현할 수 있습니다.

0) Redis Streams는 언제 쓰면 좋은가

Redis Streams는 보통 아래 같은 상황에서 강점이 있습니다.

  • 트래픽/규모가 Kafka까지는 과한데, “이벤트 기반 처리”가 필요하다
  • 같은 Redis를 이미 운영 중이고, 운영 복잡도를 크게 늘리고 싶지 않다
  • 워크큐(비동기 작업) + 재처리(ack, pending)가 필요하다

반대로, 아래가 중요하면 Kafka 같은 로그 기반 시스템이 더 자연스러울 수 있습니다.

  • 장기 보관(리플레이를 오랫동안 해야 함)
  • 파티션 기반의 강한 확장/순서 제어
  • 생태계(커넥터/스트림 처리/스키마 레지스트리 등)

1) 핵심 모델: Append-only 로그 + Consumer Group

Streams는 append-only 로그입니다.

  • XADD로 스트림에 이벤트를 추가
  • XREAD 또는 XREADGROUP으로 읽기

Consumer Group을 쓰면:

  • 여러 컨슈머가 같은 그룹에 속해서 작업을 나눠 처리하고
  • 컨슈머가 “처리 완료”를 XACK으로 알립니다

2) PEL(Pending Entries List): “처리 중” 목록이 핵심이다

Consumer Group은 “읽었지만 아직 ack되지 않은 메시지”를 PEL에 기록합니다.

  • 컨슈머가 죽으면, PEL에 남은 메시지는 영원히 ack되지 않습니다
  • 그래서 운영에서는 PEL을 주기적으로 관찰하고,
  • 일정 시간 이상 처리되지 않은 메시지를 다른 컨슈머가 가져가도록 XCLAIM/XAUTOCLAIM을 설계합니다

이게 Redis Streams가 “그냥 pub/sub”과 다른 가장 큰 차이입니다.

3) 처리 보장: at-least-once → 멱등 처리가 필수

Streams + Consumer Group은 기본적으로 at-least-once입니다.

  • 네트워크/컨슈머 장애로 동일 메시지가 다시 전달될 수 있습니다.
  • 따라서 “중복 처리되어도 안전”해야 합니다.

대표 멱등 전략(실무에서 자주 쓰는 것):

  • 비즈니스 키 기준으로 “처리 완료 마커” 저장(예: orderId)
  • 마커는 TTL을 두거나, 영속 저장소(DB)에서 유니크 제약으로 강제

4) ID 전략: *와 비즈니스 키를 구분하라

  • Redis Stream ID는 보통 *로 생성(타임스탬프 기반)
  • 비즈니스 중복 제거는 Stream ID가 아니라 비즈니스 키(orderId 같은 것) 로 하는 편이 안전합니다

Stream ID는 전달/재처리 추적에 유용하지만, “중복 처리 방지 키”로 쓰기에는 도메인 의미가 약합니다.

5) 백로그/보관: 무한 성장 방지(XTRIM)와 비용

Stream이 무한히 커지면 메모리가 터집니다. 그래서 보통:

  • XTRIM으로 길이를 제한하거나,
  • 특정 보관 정책(최근 N개/최근 T시간)으로 자릅니다.

주의할 점:

  • 너무 공격적으로 trim하면 “느린 컨슈머”가 필요한 메시지를 잃을 수 있습니다.
  • “재처리 가능 기간”을 정의하고 그 안에서만 보관하는 게 현실적입니다.

6) 운영 루틴(최소 세트)

  • 처리 지연: consumer group lag(대기 중인 메시지 수), PEL 크기
  • 재처리: 오래된 pending(예: 5분 이상)을 주기적으로 claim
  • 실패 처리: DLQ(별도 스트림)로 빼거나, 실패 횟수 기준으로 격리

Streams는 “큐를 만들고 끝”이 아니라, 재처리/관측 루프가 있어야 안정적으로 운영됩니다.

연습(추천)

  • 주문 이벤트 스트림 orders를 만들고 Producer/Consumer를 작성해보기(XADD/XREADGROUP/XACK)
  • 컨슈머를 강제로 죽여 PEL에 메시지가 남는 것을 확인한 뒤, XAUTOCLAIM으로 재처리 루프를 만들어보기
  • orderId를 멱등 키로 잡고, 중복 메시지가 들어와도 결과가 한 번만 반영되게 만들어보기