이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- Redis Stream을 이벤트 처리에 쓸 때 어떤 한계가 Kafka보다 빨리 드러나는가?
- 메모리, trim, persistence, failover, pending entry가 신뢰성에 어떤 영향을 주는가?
- Redis 기반 이벤트 처리가 적합한 범위와 위험한 범위는 어떻게 나누는가?
- 개인 프로젝트에서 Redis Stream을 쓰더라도 어떤 전환 기준을 문서화해야 하는가?
개요
Redis Stream은 가볍고 빠르게 내부 이벤트 처리를 만들 수 있다.
하지만 Redis는 기본적으로 메모리 중심 시스템이다.
Stream entry도 보관 정책과 메모리 압박의 영향을 받는다.
consumer group과 ack가 있다고 해서 Kafka 같은 장기 event backbone이 되는 것은 아니다.
한계를 알고 쓰면 좋은 도구가 되고, 한계를 숨기면 장애 때 복구 근거가 사라진다.
메모리 기반 운영
Redis Stream은 Redis memory를 사용한다.
Stream이 계속 커지면 Redis 전체 memory usage가 증가한다.
Redis가 cache, rate limit, session storage도 함께 맡고 있다면 이벤트 적재가 다른 기능을 압박할 수 있다.
메모리 정책이 잘못 설정되어 있으면 중요한 Stream entry가 eviction 위험에 놓일 수 있다.
이 때문에 Redis Stream을 쓸 때는 stream length보다 memory usage와 maxmemory policy를 함께 봐야 한다.
Trim의 의미
Stream은 XTRIM이나 MAXLEN으로 길이를 제한할 수 있다.
XADD order-events MAXLEN ~ 100000 * eventType OrderPaid orderId 10042trim은 운영상 필요하다.
하지만 trim은 replay 가능한 과거를 줄이는 결정이다.
7일 전 event를 다시 처리해야 하는데 Stream은 최근 10만 건만 남아 있다면 복구가 불가능하다.
trim 정책은 “메모리 절약”이 아니라 “보관 기간 계약”으로 문서화해야 한다.
Persistence와 Failover
Redis persistence 설정도 이벤트 신뢰성에 영향을 준다.
RDB snapshot만 쓰면 마지막 snapshot 이후의 Stream entry가 장애 시 사라질 수 있다.
AOF를 쓰면 내구성이 높아지지만 fsync 설정에 따라 성능과 유실 범위가 달라진다.
replica failover 중에는 client가 중복 publish하거나 잠깐 실패할 수 있다.
따라서 Redis Stream을 반드시 처리해야 하는 이벤트 원본으로 쓸 때는 persistence 설정과 장애 복구 목표를 확인해야 한다.
Partition 한계
Kafka는 topic partition으로 병렬성과 순서 범위를 설계한다.
Redis Stream은 key 단위로 나뉜다.
하나의 Stream key가 hot spot이 되면 consumer group을 늘려도 Redis key 자체의 병목이 남을 수 있다.
여러 Stream key로 shard할 수는 있지만, routing, ordering, 재처리 범위를 application이 직접 관리해야 한다.
이 지점부터는 Kafka가 더 자연스러운 선택일 수 있다.
Consumer 운영 한계
Redis Stream consumer group은 pending entry를 제공하지만, 운영 기능을 application이 많이 책임져야 한다.
오래된 pending claim, 실패 entry 격리, delivery count 기준, 재처리 tool, DLQ 비슷한 구조를 직접 설계해야 한다.
Kafka ecosystem에서 제공되는 consumer lag, retry topic, DLT, connector, schema registry 같은 운영 구성과 비교하면 Redis Stream은 단순한 만큼 직접 만들 부분이 많다.
작게 시작할 때는 장점이고, 조직 전체 event backbone으로 쓰려면 부담이 된다.
적합한 범위
Redis Stream은 다음에 적합하다.
- 같은 서비스 내부의 짧은 비동기 처리
- 몇 분에서 몇 시간 수준의 짧은 replay
- 운영자가 직접 볼 수 있는 소규모 consumer group
- 이미 Redis를 운영하고 있고 메시지량이 제한적인 경우
- Kafka cluster를 두기에는 과한 개인 프로젝트나 작은 팀 서비스
이 범위를 넘으면 전환 기준을 세워야 한다.
위험한 범위
다음 요구가 있으면 Kafka를 먼저 검토한다.
- 여러 팀이 같은 event log를 장기간 독립적으로 소비한다.
- 며칠 또는 몇 주 단위 replay가 필요하다.
- topic partition 기반 확장이 필요하다.
- schema evolution과 connector ecosystem이 중요하다.
- event가 감사, 정산, 데이터 warehouse 적재의 기준 원본이다.
Redis Stream으로 못 하는 것은 아니지만 운영 책임이 application과 팀에 많이 올라온다.
Java/Spring 관점
Spring 서비스에서 Redis Stream을 쓰면 구현은 단순해 보인다.
하지만 중요한 것은 장애 시 어떤 좌표로 복구하는가다.
Stream ID, event ID, consumer group, pending owner, 처리 이력 table이 함께 있어야 한다.
또한 Redis 장애가 API 주요 기능과 같은 Redis instance를 공유하는지 확인해야 한다.
이벤트 처리가 Redis memory를 잠식해 session이나 cache 장애로 번지면 설계 실패다.
운영 지표
- memory usage and fragmentation: Redis 메모리 압박이다.
- stream length by key: Stream별 누적량이다.
- trim count: 삭제된 entry 수다.
- oldest entry age: 남아 있는 replay 범위다.
- pending entry count: 처리 완료 전 entry 수다.
- Redis command latency: Redis 자체 지연이다.
- failover count: Redis HA 이벤트다.
이 지표 중 memory와 oldest entry age가 특히 중요하다.
Redis Stream의 한계는 보통 “느려졌다”보다 “복구할 과거가 없다”로 드러난다.
개인 프로젝트 기준
개인 프로젝트에서는 Redis Stream을 써도 좋다.
대신 README에 전환 기준을 적는다.
- Stream 보관 기간이 하루를 넘기면 Kafka 검토
- consumer group이 세 개 이상이면 Kafka 검토
- 정산이나 감사 기준 event가 되면 outbox와 Kafka 검토
- 재처리 범위가 Redis trim보다 길어지면 원본 DB 기반 backfill로 전환
작게 시작하되 어디서 멈출지 쓰는 것이 중요하다.
위험 신호!
- Redis Stream을 영구 event log로 설명한다.
- trim 정책이 없거나 replay 요구와 연결되어 있지 않다.
- Redis memory usage를 event 처리 지표와 함께 보지 않는다.
- pending claim과 실패 격리 구조가 없다.
- Kafka가 필요한 요구를 “Redis가 빠르다”로 밀어붙인다.
확인 질문
확인 질문
- 이 Stream에서 몇 시간 또는 며칠 전 event를 다시 읽을 수 있는가?
- trim 정책과 oldest entry age로 답해야 한다.
- Redis 장애나 failover 때 event 유실 허용 범위는 무엇인가?
- persistence 설정과 재처리 원본을 함께 봐야 한다.
- 어떤 조건이 되면 Kafka나 outbox 기반 구조로 전환할 것인가?
- 보관 기간, consumer 수, replay 범위, event 중요도를 기준으로 정해야 한다.