Redis 야무지게 사용하기
Redis의 데이터 타입, 캐싱 전략, 아키텍처까지 실무에서 꼭 알아야 할 내용을 정리했습니다.
Redis 야무지게 사용하기
1. Redis가 뭐야?
Redis는 인메모리 데이터 저장소로, 다양한 형태로 구성해서 사용할 수 있습니다.
- Simple Database : 단일 인스턴스로 빠르게 구성
- HA Database : 고가용성이 보장되는 구성
- Redis Cluster : 샤딩 기반 분산 구성
- Redis Sentinel : 자동 장애복구를 지원하는 모니터링 구성
전통적인 Redis 사용 방식
클라이언트가 캐시를 먼저 조회하고:
- Cache Hit → 캐시에서 바로 데이터 반환
- Cache Miss → Persistent Datastore(MySQL 등)를 조회 후 캐시에 프라임(적재)하여 반환
이 패턴이 Redis를 활용하는 가장 기본적인 방식입니다.
지원 데이터 타입
Redis는 아래와 같은 다양한 데이터 타입을 지원합니다.
String / Bitmap / Bitfield / Hash / List / Set / Sorted Set / Geospatial / HyperLogLog / Stream
2. Redis 컬렉션
2-1. String
Redis의 가장 기본 타입으로, 이진 데이터도 저장 가능합니다(이미지 저장도 가능).
| 명령어 | 설명 |
|---|---|
SET | 데이터를 문자열로 저장 |
SETNX | 키가 존재하지 않을 때만 저장, 일반 SET보다 성능 우수 |
MSET | Bulk Write 방식으로 네트워크 IO를 줄여 성능 향상 (MSETNX도 활용 가능) |
INCRBY / DECRBY | 정수형 데이터에 유효, 원자적 증감 처리 가능 |
2-2. List
일반적인 Linked List 형태로 Head/Tail 삽입에서 압도적인 성능을 보장합니다.
- Job Queue 또는 Pub/Sub 모델 구현에 일부 사용됨
BRPOP,BLPOP과 함께 사용하여 blocking 방식의 큐도 구현 가능
2-3. Set
특정 Key에 대해 여러 개의 고유한 Value를 저장할 때 사용합니다.
- 일반 Set:
SADD,SREM,SSCAN,SMISMEMBER - Sorted Set: 랭킹 기능처럼 순서가 필요한 경우에 매우 효과적.
ZADD,ZRANGE활용
2-4. Hashes
RDB와 유사한 구조로 데이터를 저장합니다.
- Key → PK, Field → Column, Value → Row 에 대응
- 대표 명령어:
HSET,HGET,HSCAN,HEXISTS
주의:
KEYS명령어는 프로덕션에서 절대 사용하면 안 됩니다. 카카오, 쿠팡에서 실제 장애가 발생한 사례가 있습니다. 반드시SCAN을 사용하세요.
2-5. Bitmaps
쿠폰 발급 여부 확인 등 플래그 성격의 데이터를 저장할 때 매우 효과적입니다.
- 일반 String에 비해 압도적으로 적은 메모리를 사용
- 단, 메모리 절약 효과는 **사용 범위(offset 크기)**에 따라 달라지므로 주의해서 사용해야 합니다
3. MemCached vs Redis
Redis와 자주 비교되는 MemCached, 어떤 차이가 있을까요?
| 항목 | MemCached | Redis |
|---|---|---|
| 속도 | 더 빠름 | 빠름 |
| 분산 처리 | 가능 | 가능 |
| 메모리 소비 | 적음 (메타데이터 적음) | 상대적으로 많음 |
| 데이터 타입 | 단순 (String만) | 다양함 |
| 데이터 영속성 | 미보장 | RDB / AOF로 보장 가능 |
| 생태계 | 작음 | 큼 |
결론: 생태계 규모 차이로 업데이트 및 버그 수정이 느린 MemCached보다는 Redis를 선택하는 것이 권장됩니다.
4. 캐싱 전략
4-1. Look-Aside (읽기 최적화)
읽기 작업에 최적화된 전략입니다.
1. 캐시 조회
├── Cache Hit → 캐시 데이터 반환
└── Cache Miss → DB 조회 → 캐시 저장 → 데이터 반환
Thundering Herd 주의: 과도한 트래픽 상황에서 캐시가 동시에 만료되면 DB에 갑작스러운 부하가 몰릴 수 있습니다. TTL 확인 및 재할당, 또는 별도 방어 로직이 필요합니다.
4-2. Write 전략
Write-Back
- Redis를 InMemory DB로 활용하는 대표적인 방법
- 보통 Cron과 함께 사용하여 Bulk로 데이터 처리
- Redis 부하를 줄이기 위해
KEYS보다는SCAN활용 권장
Write-Through
- 데이터를 DB와 Redis에 동시에 저장하는 방법
- Look-Aside와 가장 많이 조합해서 사용되는 형태
파레토 법칙(20:80) 을 절대 무시하면 안 됩니다. 자주 조회되는 20%의 데이터가 전체 트래픽의 80%를 차지하므로, 이 구간을 캐시로 적극 커버해야 합니다.
5. 데이터 영속성: RDB vs AOF
Redis는 두 가지 방식으로 데이터 영속성을 보장합니다.
| 항목 | RDB | AOF |
|---|---|---|
| 방식 | 스케줄러(Cron) 기반 스냅샷 | 모든 요청을 커맨드 형태로 기록 |
| 데이터 유실 가능성 | 있음 (스냅샷 사이 데이터 유실) | 없음 (절대적 영속성 보장) |
| 성능 | 빠름 | 빈번한 처리로 리소스 소모 큼 |
| 적합한 상황 | 빠른 복구 / 약간의 유실 허용 | 데이터 유실이 허용되지 않는 경우 |
어떤 걸 선택할지는 저장하는 데이터의 특성에 따라 결정해야 합니다.
6. 아키텍처
고가용성(HA)이란?
장애 상황에 대해 자동으로 조치해주는 환경을 의미합니다.
동기화 과정
- ID 그룹과 Offset을 통해 동기화 진행 여부를 결정
- ID가 다를 경우 → 전체 동기화 (Full Sync)
- ID가 같고 Offset 차이가 있을 경우 → 부분 동기화 (Partial Sync)
구성 방식별 비교
단일 인스턴스
- 가장 빠르고 적용이 쉬움
- RDB / AOF 활용 가능해 데이터 유실 걱정은 덜함
- 고가용성은 보장되지 않음
Replication
- Replica(복제본)를 통해 Offset 기반 비동기 복제
- 장애 시 수동 복구 필요 (
REPLICAOF NO ONE커맨드로 연결 제거 후 앱 코드 수정) - 읽기 작업 분산처리에 유리
Sentinel
- Redis 인스턴스들을 모니터링하는 시스템
- 장애 시 쿼럼(Quorum) 합의 과정을 통해 Replica를 자동으로 Primary로 승격
- 고가용성 보장
Cluster
- 샤딩 기법으로 데이터를 분산 저장
- 해시 슬롯(Hash Slot) 을 통해 샤드 키의 위치를 효과적으로 관리
- 대규모 데이터 처리에 적합
7. Redis Pub/Sub
Redis의 Pub/Sub은 몇 가지 중요한 특성을 알고 사용해야 합니다.
- 휘발성: 메시지 수신을 보장하지 않고 유실 가능
- 브로드캐스트: 구독 중인 모든 인스턴스에 메시지 전달
추천: Pub/Sub보다는 Stream 형태를 사용하는 것이 좋습니다. 더 고도화된 기능이 필요하다면 Kafka도 함께 고려해보세요.
8. Redis Script (Lua Script)
Lua Script를 활용하면 여러 요청을 **Atomic(원자적)**으로 처리할 수 있습니다.
- 주로 비동기식으로 요청을 받는 상황에서 유용
EVAL커맨드를 통해 실행
EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 mykey myvalue
Race Condition이 발생할 수 있는 로직에서 Lua Script를 활용하면 안전하게 처리할 수 있습니다.
마무리
Redis는 단순한 캐시 저장소를 넘어, 다양한 데이터 타입과 아키텍처 패턴을 제공하는 강력한 도구입니다. 중요한 점은:
- 컬렉션 타입을 목적에 맞게 선택할 것
- KEYS 명령어는 절대 사용하지 말 것 (SCAN 사용)
- 캐싱 전략은 읽기/쓰기 패턴을 고려해서 선택할 것
- 고가용성이 필요하다면 Sentinel 또는 Cluster 구성을 적극 검토할 것
- 파레토 법칙을 염두에 두고 캐시 적용 범위를 설계할 것