- 공유 링크 만들기
- X
- 이메일
- 기타 앱
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
Django에서 Redis 캐싱 전략 구현하기
안녕하세요! 오늘은 Django 프로젝트에서 Redis를 활용한 효율적인 캐싱 전략을 구현하는 방법에 대해 알아보겠습니다.
왜 Redis를 사용할까요?
Redis를 캐싱 솔루션으로 선택하는 이유는 다음과 같습니다:
- 빠른 성능: 인메모리 데이터베이스로 초고속 데이터 접근
- 데이터 구조 다양성: 문자열, 해시, 리스트, 세트 등 다양한 데이터 구조 지원
- 영구성: 데이터를 디스크에 저장하여 서버 재시작 시에도 데이터 유지
- 분산 시스템 지원: 클러스터링을 통한 확장성
- 풍부한 기능: TTL, Pub/Sub, 트랜잭션 등 다양한 기능 제공
1. 기본 설정
1.1 Redis 설치
# Ubuntu/Debian
sudo apt-get install redis-server
# macOS
brew install redis
1.2 Django Redis 설정
# settings.py
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"PARSER_CLASS": "redis.connection.HiredisParser",
"CONNECTION_POOL_CLASS": "redis.BlockingConnectionPool",
"CONNECTION_POOL_CLASS_KWARGS": {
"max_connections": 50,
"timeout": 20
},
"MAX_CONNECTIONS": 1000,
"COMPRESSOR_CLASS": "django_redis.compressors.zlib.ZlibCompressor",
}
}
}
# 세션 저장소로 Redis 사용
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
2. 기본 캐싱 패턴
2.1 뷰 레벨 캐싱
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
@method_decorator(cache_page(60 * 15), name='dispatch') # 15분 캐싱
class ProductListView(ListView):
model = Product
template_name = 'products/list.html'
def get_queryset(self):
return Product.objects.filter(is_active=True)
2.2 템플릿 프래그먼트 캐싱
{% load cache %}
{% cache 500 sidebar %}
<div class="sidebar">
{% for category in categories %}
<a href="{{ category.get_absolute_url }}">{{ category.name }}</a>
{% endfor %}
</div>
{% endcache %}
2.3 로우 레벨 캐싱
from django.core.cache import cache
def get_product_data(product_id):
cache_key = f'product_{product_id}'
data = cache.get(cache_key)
if data is None:
data = Product.objects.get(id=product_id)
cache.set(cache_key, data, timeout=3600) # 1시간 캐싱
return data
3. 고급 캐싱 전략
3.1 캐시 버전 관리
def get_cached_data(key, version=1):
cache_key = f'{key}_v{version}'
return cache.get(cache_key)
def invalidate_cache(key, version=1):
cache_key = f'{key}_v{version}'
cache.delete(cache_key)
3.2 캐시 프리패칭
from django.core.cache import cache
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Product)
def prefetch_product_cache(sender, instance, **kwargs):
cache_key = f'product_{instance.id}'
cache.set(cache_key, instance, timeout=3600)
3.3 조건부 캐싱
def get_conditional_cached_data(key, condition_func):
data = cache.get(key)
if data is None or not condition_func(data):
data = fetch_data()
cache.set(key, data, timeout=3600)
return data
4. Redis 특화 기능 활용
4.1 해시 데이터 구조 활용
def cache_product_details(product_id, details):
cache_key = f'product_details:{product_id}'
cache.hmset(cache_key, details)
cache.expire(cache_key, 3600) # 1시간 TTL
def get_product_details(product_id):
cache_key = f'product_details:{product_id}'
return cache.hgetall(cache_key)
4.2 리스트 활용 (최근 조회)
def add_to_recently_viewed(user_id, product_id):
cache_key = f'recently_viewed:{user_id}'
cache.lpush(cache_key, product_id)
cache.ltrim(cache_key, 0, 9) # 최근 10개만 유지
4.3 세트 활용 (유니크 방문자)
def track_unique_visitors(page_id, visitor_id):
cache_key = f'unique_visitors:{page_id}'
cache.sadd(cache_key, visitor_id)
cache.expire(cache_key, 86400) # 24시간 TTL
5. 성능 최적화
5.1 캐시 압축
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"COMPRESSOR_CLASS": "django_redis.compressors.zlib.ZlibCompressor",
"COMPRESSOR_CLASS_KWARGS": {
"level": 5
}
}
}
}
5.2 연결 풀링
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CONNECTION_POOL_CLASS": "redis.BlockingConnectionPool",
"CONNECTION_POOL_CLASS_KWARGS": {
"max_connections": 50,
"timeout": 20
}
}
}
}
6. 모니터링 및 디버깅
6.1 캐시 히트율 모니터링
from django.core.cache import cache
from django.db import connection
def get_cache_stats():
info = cache.client.info()
return {
'hits': info.get('keyspace_hits', 0),
'misses': info.get('keyspace_misses', 0),
'hit_rate': info.get('keyspace_hits', 0) /
(info.get('keyspace_hits', 0) + info.get('keyspace_misses', 0))
}
6.2 캐시 키 관리
def get_cache_keys(pattern='*'):
return cache.client.keys(pattern)
def delete_cache_keys(pattern='*'):
keys = cache.client.keys(pattern)
if keys:
cache.client.delete(*keys)
7. 실전 예제
7.1 상품 목록 캐싱
from django.core.cache import cache
from django.db.models import Prefetch
def get_cached_products(category_id):
cache_key = f'products_category_{category_id}'
products = cache.get(cache_key)
if products is None:
products = Product.objects.filter(
category_id=category_id,
is_active=True
).select_related(
'category'
).prefetch_related(
Prefetch('images', queryset=ProductImage.objects.filter(is_primary=True))
)
cache.set(cache_key, products, timeout=3600)
return products
7.2 사용자 세션 관리
from django.core.cache import cache
from django.contrib.auth import get_user_model
def get_user_sessions(user_id):
cache_key = f'user_sessions:{user_id}'
sessions = cache.get(cache_key)
if sessions is None:
sessions = Session.objects.filter(
session_data__contains=str(user_id)
).values_list('session_key', flat=True)
cache.set(cache_key, sessions, timeout=300)
return sessions
결론
Django에서 Redis를 활용한 캐싱 전략을 구현하는 방법을 알아보았습니다. 적절한 캐싱 전략을 통해 애플리케이션의 성능을 크게 향상시킬 수 있습니다. 추가적인 질문이나 궁금한 점이 있으시면 댓글로 남겨주세요!
댓글
댓글 쓰기