Redis 사용시 주의사항
O(N) 명령어
대부분의 명령어는 O(1)의 시간복잡도를 갖고 있지만, 일부 명령어의 경우 O(N)의 시간복잡도를 갖고 있는데요..!
Redis
는 Single Thread
로 동작하기 때문에, 오래 걸리는 명령어 수행시 전체적으로 애플리케이션 성능이 저하될 수 있습니다.
- keys
- smembers
- hgetall
- sort
KEYS
지정된 패턴과 일치하는 모든 key 조회하는 명령어로 prod 환경에서는 사용하지 않는 것이 권장 됩니다.
$ keys *
1) "jobs"
2) "member"
3) "java-station:burgers"
4) "fruits"
5) "result"
6) "user:2:fruits"
7) "points"
8) "user:log-in:25-01-02"
9) "k1"
10) "seoul:station"
11) "events"
12) "abc"
13) "user:1:fruits"
14) "k2"
15) "today:users"
16) "user:log-in:25-01-01"
scan
명령어로 대체하여 사용하는 것이 권장 됩니다.
$ scan 0 match user:* count 5
1) "10"
2) 1) "user:1:fruits"
SMEMBERS
sets 타입의 모든 멤버를 조회하는 명령어로 O(N)의 시간복잡도를 갖고 있습니다.
(일반적으로 하나의 sets에 10,000개의 아이템을 추가하지 않는 것이 권장)
$ smembers user
1) user1
2) user2
3) user3
...
HGETALL
hashes의 모든 필드를 반환하는 명령어로 O(N)의 시간복잡도를 갖고 있습니다.
$ hgetall user
1) "name"
2) "ralph"
3) "age"
4) 31
5) "email"
6) "ralph@teuida.net"
...
SORT
Lists, Sets, ZSets 의 item 을 정렬하여 반환하는 명령어로 O(N)의 시간복잡도를 갖고 있습니다.
$ sort name alpha
1) "harry"
2) "jason"
3) "jay"
4) "kwai"
5) "liz"
6) "luke"
7) "luna"
8) "mia"
9) "nelson"
10) "ralph"
11) "ray"
12) "sam"
13) "somi"
Thundering herd Problem
Redis에서 Thundering Herd 발생 원인
- 동시에 여러 클라이언트가 같은 키를 요청
- 캐시 키가 만료되면 모든 요청이 백엔드(DB)로 몰려 Redis 부하 증가
- DB 부하 증가로 인해 장애 발생 가능
병렬 요청이 공유 자원에 대해서 접근할 때, 급격한 과부하가 발생하는 문제
풀어서 이야기하면 Thundering Herd Problem이 발생하는 주요 원인은 동시에 많은 요청이 동일한 키에 접근하여 캐시가 만료되는 순간 부하가 집중되기 때문 입니다.
(주로 대규모 트래픽을 다루는 서비스에서 발생)
Redis에서 Thundering Herd 문제 해결 방법
1️⃣ 캐시 만료 시간(Random Expiration) 조정
동일한 시간에 다수의 키가 동시에 만료되지 않도록 만료 시간을 랜덤화 합니다.
이렇게 하면 특정 순간에 집중되는 만료 요청을 방지 가능 합니다.
SET key value EX 300 + (RANDOM % 30) # 300~330초 사이의 만료 시간 설정
2️⃣ Cache Stampede 방지 (Soft TTL & Lazy Refill)
캐시가 만료되더라도 즉시 삭제하지 않고, 만료된 데이터를 일정 시간 유지하며 새로운 데이터 로드를 제어 합니다.
이를 Redis Lua Script나 Async Cache Update Pattern으로 구현 가능
GET key
IF key 만료 임박
백그라운드에서 데이터 갱신 (비동기)
ELSE
기존 데이터 반환
3️⃣ 분산 락(Distributed Lock) 사용
캐시가 만료될 때 한 개의 요청만 DB에서 새로운 데이터를 가져오도록 제한
SETNX
를 활용한 락 구현
if SETNX lock_key "1" EX 3 # 락이 없으면 설정 (3초 TTL)
데이터 갱신 후 Redis에 저장
DEL lock_key # 락 해제
else
일정 시간 후 다시 요청
- 분산 락은 강력한 해결책이지만, 트래픽이 많을수록 성능 저하를 유발할 수 있습니다.
- 대신 Soft TTL + Read-Through 캐싱 + 비동기 갱신 같은 기법을 적용하면 더 효율적으로 Thundering Herd 문제를 해결 가능 합니다.
참고
Stale Cache Invalidation
캐시의 유효성이 손실되었거나 변경되었을 때, 캐시를 변경하거나 삭제하는 기술 입니다.
There are only two hard things in computer science:
”cache invalidation and naming things.”
— Phil Karlton
Cache Invalidation (캐시 무효화)
- 캐시는 성능 최적화에 필수적이지만, 언제 데이터를 갱신해야 하는지가 어렵습니다.
- e.g) Redis, CDN 캐시, 브라우저 캐시
- 데이터가 최신인지 보장해야 합니다.
- 너무 자주 무효화하면 성능 저하, 너무 늦으면 오래된 데이터 제공합니다.
참고
'데이터베이스 > 0 + Redis' 카테고리의 다른 글
[Redis] 데이터 타입 활용 (0) | 2025.02.02 |
---|---|
[Redis] 특수 명령어 (1) | 2025.01.28 |
[Redis] Redis 특징과 데이터 타입 소개 (0) | 2025.01.28 |