Redis 활용 사례: 캐싱, 큐, 속도 제한
트랙션을 얻고 있는 웹 앱을 구축했지만, 이제 모든 페이지 로드가 데이터베이스에 부딪히고, 백그라운드 작업이 쌓이고 있으며, 몇몇 사용자가 API를 과도하게 호출하고 있습니다. 이러한 문제를 해결하려면 빠른 인메모리 데이터 저장소가 필요합니다. Redis는 캐싱, 큐, 속도 제한을 위한 최적의 솔루션입니다. 이 글에서는 실용적인 예제와 모범 사례를 통해 이 세 가지 핵심 활용 사례를 살펴보겠습니다.
캐싱, 큐, 속도 제한에 Redis를 사용하는 이유
Redis는 속도와 다재다능함으로 유명한 인메모리 키-값 저장소입니다. 문자열, 리스트, 세트, 정렬된 세트, 해시와 같은 풍부한 데이터 구조를 지원하여 다양한 작업에 이상적입니다. 원자적 연산과 pub/sub 기능은 유용성을 더욱 확장합니다. 데이터베이스 부하를 줄이거나, 서비스를 분리하거나, API를 보호하든 Redis는 간단하면서도 강력한 도구 모음을 제공합니다.
1. Redis를 사용한 캐싱
캐싱은 Redis의 가장 일반적인 사용 사례입니다. 자주 액세스하는 데이터를 메모리에 저장하여 지연 시간과 데이터베이스 부하를 줄입니다. Redis의 TTL(수명) 기능은 오래된 데이터를 자동으로 만료시킵니다.
캐싱 구현 방법
- 캐시 확인: 데이터베이스를 쿼리하기 전에 Redis에 데이터가 있는지 확인합니다.
- 캐시 미스 시: 데이터베이스에서 가져와 만료 시간과 함께 결과를 Redis에 저장합니다.
- 캐시 히트 시: 캐시된 데이터를 직접 반환합니다.
redis-py를 사용한 Python 예제입니다:
import redis
import json
r = redis.Redis(host='localhost', port=6379, db=0)
def get_user(user_id):
cache_key = f"user:{user_id}"
cached = r.get(cache_key)
if cached:
return json.loads(cached)
# Simulate DB fetch
user = fetch_user_from_db(user_id)
r.setex(cache_key, 3600, json.dumps(user)) # Cache for 1 hour
return user
캐싱 모범 사례
- 적절한 TTL 설정: 신선도와 적중률의 균형을 맞춥니다. 변동이 심한 데이터에는 짧은 TTL, 정적 콘텐츠에는 더 긴 TTL을 사용합니다.
- 캐시 무효화 사용: 데이터가 변경되면 캐시 키를 삭제하거나 업데이트하여 오래된 읽기를 방지합니다.
- 캐시 스탬피드 처리: 잠금 또는 확률적 조기 만료를 사용하여 캐시 미스 시 많은 요청이 동시에 데이터베이스에 도달하는 것을 방지합니다.
- 적중률 모니터링: 캐싱이 효과적인지 확인하기 위해 높은 적중률(예: >80%)을 목표로 합니다.
2. Redis를 사용한 큐
Redis 리스트와 정렬된 세트는 간단하면서도 강력한 메시지 큐를 가능하게 합니다. 백그라운드 작업, 작업 큐, 이벤트 처리에 완벽합니다. 전용 메시지 브로커와 달리 Redis 큐는 가볍고 설정하기 쉽습니다.
기본 큐 구현
LPUSH를 사용하여 작업을 추가하고 BRPOP을 사용하여 차단 방식으로 소비합니다:
# Producer
r.lpush('job_queue', json.dumps({'task': 'send_email', 'to': 'user@example.com'}))
# Consumer
while True:
_, job = r.brpop('job_queue', timeout=30)
if job:
process_job(json.loads(job))
정렬된 세트를 사용한 고급 큐
지연 작업이나 우선순위 큐의 경우 점수로 타임스탬프를 사용하는 정렬된 세트를 사용합니다. 소비자는 점수가 있는 작업을 가져옵니다