도입
처음 Redis를 접하면 보통 “메모리 캐시” 정도로 이해하기 쉽습니다. 물론 그 설명도 맞지만, 실무에서는 그보다 훨씬 넓게 쓰입니다.
세션 저장소, 조회수 카운터, 랭킹 보드, 분산 락, 작업 큐, 이벤트 스트림, Pub/Sub, 실시간 집계, 심지어 최근 공식 문서 기준으로는 문서형/벡터형 활용까지 포함됩니다. 그래서 Redis를 제대로 이해하려면 “빠른 키-값 저장소”를 넘어서 어떤 자료구조를 어떤 패턴으로 다루는 시스템인가를 함께 봐야 합니다.
필요성
대부분의 서비스는 몇 가지 전형적인 병목을 만납니다. 자주 조회되는 데이터가 계속 DB를 때리고, 세션이나 토큰 같은 짧은 수명의 상태를 저장해야 하며, 실시간 카운터와 랭킹이 필요하고, 사용자 요청과 백그라운드 작업을 분리해야 합니다.
Redis는 이런 문제를 한 번에 다룰 수 있는 도구입니다. 메모리 기반이라 빠르고, 자료구조가 풍부하며, TTL·복제·퍼시스턴스·고가용성·클러스터링까지 이어집니다. 그래서 Redis를 잘 쓰면 “애플리케이션 코드로 우회 구현하던 문제”를 저장소 레벨에서 훨씬 단순하게 풀 수 있습니다.
- 캐시, 세션, 인증 토큰 저장
- 카운터, rate limiting, 실시간 랭킹
- 작업 큐, 이벤트 로그, 스트림 처리
- 분산 락과 짧은 수명의 상태 공유
- DB offload가 필요한 읽기 집중 서비스
정의
관계형 데이터베이스에서는 보통 테이블과 행을 중심으로 생각합니다. 반면 Redis는 키와 자료구조를 중심으로 사고하는 편이 더 자연스럽습니다.
대표적으로 문자열(String), 해시(Hash), 리스트(List), 셋(Set), 정렬 셋(Sorted Set), 스트림(Stream)을 많이 사용합니다. 최근 공식 문서 기준으로는 JSON, Time series, Probabilistic data type, Vector set 같은 확장형 타입도 함께 다루고 있어, Redis는 더 이상 “문자열 캐시 서버”라고만 부르기 어려운 단계에 와 있습니다.
핵심 원리
Redis가 빠른 이유를 단순히 “메모리라서”라고만 설명하면 절반만 맞습니다. 중요한 것은 데이터를 메모리에 두는 것뿐 아니라, 그 데이터에 대한 연산도 Redis가 직접 제공한다는 점입니다.
예를 들어 해시 필드 갱신, 카운터 증가, 정렬 셋 점수 기반 랭킹 계산, 스트림 append 같은 동작을 애플리케이션이 여러 round-trip으로 조합하지 않아도 됩니다. 여기에 파이프라이닝을 더하면 여러 명령을 한 번에 밀어 넣어 RTT 비용까지 줄일 수 있습니다.
기본 구조
| 요소 | 역할 | 실무 포인트 |
|---|---|---|
| Key Space | 모든 데이터는 key 기반으로 접근 | 키 설계가 캐시 hit, tenant 분리, invalidation의 출발점 |
| Native Data Types | 문자열, 해시, 리스트, 셋, 정렬 셋, 스트림 등 | 문제를 자료구조 단위로 직접 풀 수 있음 |
| Persistence | RDB, AOF, 둘 다, 또는 없음 | 캐시인지 주 저장소인지에 따라 전략이 달라짐 |
| Replication | primary-replica 복제 | 읽기 분산과 장애 대비의 기초가 됨 |
| Sentinel | 비클러스터 환경의 모니터링, 알림, 자동 failover | standalone + replica 구성의 HA를 담당 |
| Cluster | hash slot 기반 수평 확장과 replica failover | 용량과 처리량을 노드 단위로 확장할 때 사용 |
| ACL / Security | 사용자별 명령/키 접근 제한 | Redis를 인터넷에 직접 노출하지 말고 trusted network 안에서 운영하는 쪽이 기본 |
기본 구현
# 연결 확인
PING
# 문자열 저장 / 조회
SET user:1:name "Kim"
GET user:1:name
# 세션처럼 TTL 있는 값 저장
SET session:abc123 "{\"userId\":1}" EX 1800
# 해시로 객체 비슷하게 저장
HSET product:100 name "Keyboard" price 99000 stock 21
# 카운터
INCR pageview:home
이 예시만 봐도 감이 잡힙니다. 세션은 문자열과 TTL로, 간단한 객체는 해시로, 조회수는 카운터로 표현하면 됩니다. Redis는 결국 데이터를 “테이블”보다 “용도별 자료구조”로 표현하는 감각이 중요합니다.
패턴 1. 캐시와 세션 저장소
캐시로 Redis를 쓸 때 가장 흔한 패턴은 Cache-Aside입니다. 애플리케이션이 먼저 Redis를 보고, miss면 DB를 조회한 뒤 결과를 Redis에 넣고 반환합니다. 세션과 토큰 저장도 매우 비슷한 방식으로 많이 구성됩니다.
이때 정말 중요한 것은 TTL과 eviction policy입니다. TTL이 없으면 오래된 값이 남아 무효화 버그가 오래 숨고, maxmemory와 eviction 정책이 없으면 메모리 압박 시 운영이 불안정해질 수 있습니다. 즉, 캐시 전략은 “어디에 저장할까”보다 “언제 사라질까”를 먼저 정해야 합니다.
user:v1:123: 버전이 포함된 사용자 캐시session:abc123: 세션 키product:list:page:1: 페이지 단위 목록 캐시rate-limit:ip:1.2.3.4: 제한용 카운터
maxmemory와 eviction policy를 반드시 함께 봐야 합니다. 캐시 운영에서 가장 흔한 장애는 “데이터가 안 들어간다”보다 “언제 어떻게 밀려 나가는지 몰랐다”에서 시작됩니다.패턴 2. 영속성, 복제, 고가용성
Redis persistence는 크게 네 가지 선택지로 볼 수 있습니다. RDB, AOF, 둘 다, 또는 아예 없음입니다. 캐시 용도라면 persistence를 끄기도 하지만, 데이터 유실을 어느 정도라도 줄이고 싶다면 적어도 어떤 방식으로 디스크에 남길지부터 정해야 합니다.
RDB는 특정 시점 스냅샷이라 백업과 복구, 빠른 재시작에 유리합니다. 반면 AOF는 쓰기 명령을 로그처럼 기록하므로 더 높은 내구성을 기대할 수 있고, 기본 정책 기준으로는 보통 최대 1초 안팎의 손실 가능성을 전제로 성능과 내구성의 균형을 잡습니다. 둘 다 켜면 재시작 시 AOF가 더 완전한 원본으로 간주되는 쪽에 가깝습니다.
| 항목 | RDB | AOF |
|---|---|---|
| 방식 | 시점 스냅샷 | 쓰기 명령 로그 |
| 장점 | 백업과 복구가 편하고 재시작이 빠른 편 | 더 높은 내구성 전략을 취하기 쉬움 |
| 주의점 | 스냅샷 사이 구간의 손실 가능성 | 로그 관리, 재작성, 디스크 비용 고려 필요 |
복제(replication)는 primary가 쓰기를 받고 replica가 이를 따라가는 구조입니다. replica는 연결이 끊겨도 다시 붙으려 하고, 최신 backlog가 남아 있으면 부분 재동기화도 가능합니다. 하지만 replication만으로는 durability가 완전히 해결되지 않습니다. 따라서 고가용성이 필요하면 Sentinel 또는 Cluster를, 데이터 안전성이 중요하면 persistence와 백업 전략을 같이 봐야 합니다.
# 더 강한 쓰기 확인이 필요할 때의 개념 예시
SET order:1001:status "PAID"
WAIT 1 1000
패턴 3. Pub/Sub와 Streams
Redis Pub/Sub는 실시간 알림에는 간단하고 빠릅니다. 하지만 전달 semantics는 at-most-once라서, 구독자가 그 순간 연결되어 있지 않거나 메시지를 놓치면 다시 받을 수 없습니다. 그래서 채팅 알림, 캐시 무효화 브로드캐스트처럼 “지금 보는 쪽에게 바로 알리기”에는 잘 맞지만, 작업 큐처럼 놓치면 안 되는 처리에는 취약합니다.
반대로 Streams는 append-only log에 가깝습니다. 이벤트를 쌓아 두고, 소비자 그룹을 통해 읽고, 읽은 위치를 관리하며, 더 강한 전달 보장을 설계할 수 있습니다. 즉, 실시간 알림엔 Pub/Sub, 내구성과 재처리가 필요한 이벤트 처리엔 Streams가 더 자연스럽습니다.
# Pub/Sub
PUBLISH chat:room:1 "hello"
# Streams
XADD order-events * orderId 1001 status created
XADD order-events * orderId 1001 status paid
| 구분 | Pub/Sub | Streams |
|---|---|---|
| 핵심 성격 | 실시간 브로드캐스트 | append-only 로그 기반 이벤트 저장 |
| 전달 특성 | at-most-once | 재처리/추적이 가능한 쪽으로 설계 가능 |
| 적합한 용도 | 알림, invalidate broadcast, 짧은 실시간 이벤트 | 작업 큐, 이벤트 로그, consumer group 처리 |
클러스터와 스케일아웃
Redis Cluster는 데이터를 여러 노드에 나눠 저장하고, 노드 간 상태를 교환하며, 필요하면 replica를 승격시켜 계속 서비스를 유지하려는 구조입니다. 여기서 핵심 단위는 16384 hash slot입니다.
중요한 제약도 있습니다. Redis Cluster는 standalone과 달리 여러 database를 지원하지 않고 DB 0만 사용합니다. 또한 multi-key 연산은 관련 키들이 같은 slot으로 해시될 때만 자연스럽게 처리됩니다. 그래서 클러스터 도입은 “인프라 확장”인 동시에 “키 설계 재검토”이기도 합니다.
성능 포인트
명령 하나하나가 빠르더라도 네트워크 왕복이 반복되면 전체 성능은 쉽게 떨어집니다. 이때 pipelining은 여러 명령을 답변 하나하나 기다리지 않고 한 번에 밀어 넣어 RTT 비용을 줄입니다. 특히 짧은 명령을 많이 보낼 때 체감 차이가 큽니다.
또한 공식 문서는 server-assisted client-side caching도 별도 주제로 다룹니다. 즉, Redis 앞에 애플리케이션 로컬 메모리 캐시를 두고 인기 조회를 더 빠르게 재사용할 수 있습니다. 다만 이 경우 캐시 일관성, invalidation, hot key 집중을 같이 설계해야 합니다.
# 파이프라이닝 개념 예시
SET counter:1 1
INCR counter:1
INCR counter:1
GET counter:1
# 위 같은 짧은 명령을 개별 RTT로 보내지 않고 배치로 보내면 효과가 큼
한계와 주의점
Redis는 기본적으로 메모리 중심 시스템이므로, 데이터 크기와 키 수가 빠르게 비용으로 연결됩니다. 따라서 모든 데이터를 Redis에 넣는다고 자동으로 좋은 설계가 되지는 않습니다.
또한 replication은 훌륭한 가용성 수단이지만, 그 자체가 완전한 durability를 뜻하는 것은 아닙니다. Pub/Sub도 실시간 알림에는 훌륭하지만 durable queue가 아닙니다. 결국 Redis를 쓸 때는 “빠른가?”보다 “이 데이터에 어떤 수준의 보장과 제약이 필요한가?”를 먼저 따져야 합니다.
- Redis를 신뢰할 수 없는 네트워크에 직접 노출하지 않기
- 용도에 맞는 persistence 전략 없이 “기본값”으로만 운영하지 않기
- Cluster 도입 후에도 standalone처럼 multi-key를 자유롭게 쓸 수 있다고 착각하지 않기
- Pub/Sub를 durable work queue로 착각하지 않기
- TTL·eviction 없이 캐시로만 쓰다 메모리 압박을 맞지 않기
자주 하는 실수
- Redis = 캐시라고만 생각하고 자료구조 장점을 전혀 쓰지 않음
- 캐시인데 TTL과 maxmemory를 설계하지 않음
- 주 저장소처럼 쓰면서 RDB/AOF trade-off를 이해하지 않음
- replication만 켜고 durability가 해결됐다고 생각함
- Pub/Sub를 큐처럼 사용하다 메시지 유실을 겪음
- MULTI/EXEC를 관계형 DB의 full rollback transaction처럼 착각함
- Cluster에서 multi-key 제약과 slot locality를 무시함
- ACL, TLS, 네트워크 분리 없이 외부에 그대로 노출함
실무 루틴
- 이 데이터가 캐시인지, 주 저장소인지 먼저 결정한다.
- String / Hash / List / Set / ZSet / Stream 중 어떤 자료구조가 자연스러운지 고른다.
- TTL, invalidation, maxmemory, eviction policy를 함께 정한다.
- Persistence를 RDB / AOF / 둘 다 / 없음 중 어떤 수준으로 가져갈지 정한다.
- 고가용성이 필요하면 Sentinel인지 Cluster인지 분리해서 선택한다.
- 보안은 ACL, TLS, 네트워크 접근 제어를 기준으로 잡는다.
- 운영 시작 전부터 INFO 기반 모니터링과 백업 전략을 같이 설계한다.
디버깅
INFO memory, INFO stats, INFO persistence, INFO replication을 먼저 본다.# 가장 먼저 자주 확인하는 것들
PING
INFO memory
INFO stats
INFO persistence
INFO replication
요약
- ✅ Redis는 단순 캐시가 아니라 자료구조 서버이자 인메모리 데이터 스토어다.
- ✅ 문자열, 해시, 리스트, 셋, 정렬 셋, 스트림 등 다양한 자료구조를 직접 지원한다.
- ✅ 캐시로 쓸 때는 TTL, invalidation, maxmemory, eviction policy를 반드시 함께 봐야 한다.
- ✅ persistence는 RDB, AOF, 둘 다, 또는 없음 중에서 용도에 맞게 골라야 한다.
- ✅ replication은 가용성의 기초이고, Sentinel은 non-cluster HA, Cluster는 수평 확장의 해법이다.
- ✅ Pub/Sub는 실시간 브로드캐스트, Streams는 더 내구성 있는 이벤트 로그/큐에 가깝다.
- ✅ pipelining과 client-side caching은 Redis 성능을 더 끌어올리는 중요한 운영 포인트다.
- ✅ Redis는 빠르지만, 그만큼 메모리 비용·정합성·보안·클러스터 제약을 함께 관리해야 한다.