Redis Key 설계와 데이터 관리
Redis 데이터 관리는 key를 어떻게 만들고, 얼마나 오래 보관하고, 메모리가 부족할 때 무엇을 버릴지를 정하는 일입니다.
용어
| 용어 | 의미 |
|---|---|
| Key 설계 | key 이름, 식별자, TTL, 삭제 범위를 정하는 설계 |
| SCAN | 운영 중 key를 점진적으로 찾는 명령 |
| TTL | key 만료 시간 |
| Expiration | TTL이 지난 key가 삭제되는 과정 |
| Maxmemory | Redis가 사용할 수 있는 최대 메모리 |
| Eviction | 메모리 부족 시 정책에 따라 key를 제거하는 동작 |
| Persistence | RDB / AOF 방식으로 메모리 데이터를 디스크에 남기는 기능 |
| DR | 장애 후 복구를 위한 백업·복원 전략 |
질문
Key 설계를 왜 먼저 해야 하나?
Redis는 key-value 저장소라 key가 곧 데이터 모델입니다. key가 흔들리면 삭제 범위, TTL 정책, 장애 분석, cluster hash slot, hot key 분석이 모두 어려워집니다.
TTL과 Eviction은 같은가?
아닙니다.
| 구분 | 의미 |
|---|---|
| TTL | 시간이 지나면 key가 만료되는 규칙 |
| Eviction | 메모리가 부족할 때 Redis가 key를 제거하는 정책 |
TTL이 남아 있어도 메모리가 부족하고 eviction 정책이 허용하면 먼저 제거될 수 있습니다.
Key 설계
| 설계 기준 | 예시 | 이유 |
|---|---|---|
| 도메인 먼저 | product:1001:summary |
삭제·검색 범위가 명확함 |
| 용도 분리 | lock:coupon:100, rate-limit:login:user-1 |
장애 시 성격 파악이 쉬움 |
| 날짜 포함 | rank:daily:20260427 |
기간별 만료와 집계가 쉬움 |
| hash tag 사용 | cart:{user-1}:items |
Cluster 다중 key 명령을 같은 slot에 배치 |
| 버전 포함 | product:v2:1001 |
캐시 구조 변경 시 충돌 방지 |
주의: key 이름이 너무 길면 메모리 비용이 늘어난다. 의미가 드러나되 불필요하게 장황하지 않게 잡는다.
Key Scan 전략
운영 환경에서 KEYS *는 전체 key를 한 번에 훑어 Redis를 오래 붙잡을 수 있습니다.
# 위험: 운영에서 전체 blocking 가능
KEYS *
# 권장: 점진 탐색
SCAN 0 MATCH product:* COUNT 100
HSCAN user:1 0 COUNT 100
SSCAN active-users 0 COUNT 100
ZSCAN rank:daily:20260427 0 COUNT 100
| 명령 | 대상 |
|---|---|
SCAN |
전체 keyspace |
HSCAN |
Hash 필드 |
SSCAN |
Set 원소 |
ZSCAN |
Sorted Set 원소 |
SCAN은 같은 key가 중복 반환될 수 있고, 실행 중 변경된 key를 완벽한 스냅샷처럼 보장하지 않습니다. 운영 점검·삭제 후보 수집에는 좋지만, 정확한 트랜잭션 처리에는 맞지 않습니다.
TTL과 만료 정책
| TTL 설계 | 기준 |
|---|---|
| 짧게 | 가격, 재고, 권한처럼 자주 바뀌는 데이터 |
| 길게 | 공지, 카테고리, 설정처럼 변경이 적은 데이터 |
| 랜덤 분산 | 인기 key가 동시에 만료되지 않게 할 때 |
| 무기한 | 명확한 삭제 주체가 있고 원본성이 필요한 경우만 |
만료 데이터 삭제 메커니즘
Redis는 만료된 key를 보통 두 방식으로 제거합니다.
| 방식 | 설명 |
|---|---|
| Lazy Expire | key에 접근했을 때 만료 여부를 확인하고 삭제 |
| Active Expire | Redis가 주기적으로 만료 key를 샘플링해 삭제 |
즉 TTL이 지났다고 모든 key가 정확히 그 순간 삭제되는 것은 아닙니다. 만료된 key가 잠깐 메모리에 남을 수 있으므로, 메모리 여유와 만료량을 함께 봐야 합니다.
메모리 관리와 Maxmemory
Redis 메모리는 value 크기만으로 결정되지 않습니다. key 이름, 자료구조 메타데이터, TTL 정보, replication buffer, client buffer, allocator 단편화까지 포함됩니다.
| 지표 | 의미 |
|---|---|
used_memory |
Redis가 할당한 메모리 |
used_memory_rss |
OS가 실제로 잡고 있는 메모리 |
mem_fragmentation_ratio |
메모리 단편화 비율 |
maxmemory |
Redis 최대 메모리 |
evicted_keys |
eviction으로 제거된 key 수 |
Eviction 정책
| 정책 | 제거 대상 | 언제 고려 |
|---|---|---|
noeviction |
제거하지 않음 | 삭제보다 쓰기 실패가 낫다고 판단할 때 |
allkeys-lru |
전체 key 중 덜 최근에 사용한 key | 일반 캐시 |
allkeys-lfu |
전체 key 중 덜 자주 사용한 key | 인기 데이터가 뚜렷할 때 |
volatile-lru |
TTL 있는 key 중 덜 최근에 사용한 key | TTL 없는 key 보호 |
volatile-lfu |
TTL 있는 key 중 덜 자주 사용한 key | TTL 기반 캐시 |
volatile-ttl |
TTL이 짧은 key | 곧 만료될 key 우선 제거 |
allkeys-random |
전체 key 중 랜덤 | 접근 패턴 예측이 어려울 때 |
주의: volatile-* 정책은 TTL이 있는 key만 제거한다. TTL 없는 key가 많으면 메모리 부족 상황에서 기대처럼 제거되지 않을 수 있다.
Persistence
Redis는 메모리 저장소지만 RDB / AOF 방식으로 복구용 데이터를 디스크에 남길 수 있습니다.
| 방식 | 설명 | 장점 | 단점 |
|---|---|---|---|
| RDB | 특정 시점 스냅샷 | 파일이 작고 복구가 빠름 | 마지막 스냅샷 이후 데이터 유실 가능 |
| AOF | 쓰기 명령 로그 | 더 적은 유실 가능 | 파일 증가, rewrite 비용 |
| RDB + AOF | 둘 다 사용 | 복구 안정성 향상 | 운영 비용 증가 |
AOF fsync
| 설정 | 의미 | 장애 시 |
|---|---|---|
appendfsync always |
매 쓰기마다 fsync | 가장 안전하지만 느림 |
appendfsync everysec |
보통 1초마다 fsync | 성능과 안전성 균형 |
appendfsync no |
OS flush에 맡김 | 빠르지만 유실 범위가 커질 수 있음 |
Backup / Restore / DR
| 항목 | 확인할 것 |
|---|---|
| Backup | RDB / AOF 파일을 어디에 얼마나 자주 보관하는가 |
| Restore | 실제 복구 시간이 서비스 요구사항을 만족하는가 |
| DR | 장애 지역·노드가 사라졌을 때 어디에서 재기동하는가 |
| 검증 | 백업 파일이 있는 것과 복구 가능한 것은 다르므로 복구 훈련 필요 |
베스트 프랙티스
| 권장 방식 | 이유 |
|---|---|
| key prefix 기준 TTL 정책 문서화 | 운영 중 삭제와 장애 분석이 쉬움 |
| 모든 캐시에 TTL 부여 | 무한 증가 방지 |
| TTL에 jitter 추가 | 동시 만료 방지 |
KEYS 대신 SCAN 사용 |
운영 blocking 방지 |
maxmemory와 eviction 정책 명시 |
장애 시 동작 예측 가능 |
| backup restore 훈련 | 백업 신뢰성 확인 |
실무에서는?
| 상황 | 판단 |
|---|---|
| 조회 캐시 | TTL + allkeys-lru 또는 allkeys-lfu 검토 |
| 세션 저장 | TTL 필수, eviction으로 날아가도 되는지 정책 결정 |
| 원장성 데이터 | Redis 단독 저장 피하고 DB 기준 복구 |
| 대규모 삭제 | UNLINK, SCAN 기반 배치 삭제 |
| 장애 복구 | RDB / AOF 복원 시간과 유실 범위를 미리 측정 |
관련 파일: - 기본 사용과 자료구조 - 성능 최적화 - 장애 대응과 트러블슈팅