Post
Redis와 SQL: 캐싱 전략으로 데이터베이스 성능 극대화하기
왜 이 주제가 중요한가?
SQL 데이터베이스만으로는 대규모 트래픽을 감당하기 어렵습니다. Redis를 캐싱 레이어로 추가하면 데이터베이스 부하를 크게 줄이고 응답 속도를 10배 이상 개선할 수 있습니다.
실제 프로젝트에서는 자주 조회되는 데이터(사용자 정보, 상품 목록, 세션 등)를 Redis에 저장해 데이터베이스 쿼리를 최소화합니다.
핵심 개념
-
인메모리 저장소 Redis는 모든 데이터를 메모리에 저장하므로 디스크 I/O 없이 매우 빠른 접근이 가능합니다.
-
캐시 무효화 전략 데이터 변경 시 Redis의 캐시를 즉시 삭제하거나 TTL(Time To Live)을 설정해 자동으로 만료되도록 합니다.
-
SQL과의 조합 패턴 먼저 Redis에서 데이터를 찾고, 없으면 SQL 데이터베이스에서 조회한 후 Redis에 저장하는 “Look-Aside” 패턴이 가장 일반적입니다.
-
데이터 타입 활용 String(단순 값), Hash(객체), List(순서 있는 목록), Set(중복 없는 집합) 등 다양한 자료구조를 지원합니다.
-
동시성 문제 여러 요청이 동시에 같은 데이터를 캐시할 때 “캐시 스탬피드” 현상이 발생할 수 있으므로 주의가 필요합니다.
실전 예제: 사용자 정보 캐싱
기본 구조
import redis
import json
import time
from datetime import datetime
redis_client = redis.Redis(host='localhost', port=6379, db=0)
def get_user_info(user_id):
# 1단계: Redis에서 캐시 확인
cache_key = f"user:{user_id}"
cached_data = redis_client.get(cache_key)
if cached_data:
print(f"캐시 히트: user_id={user_id}")
return json.loads(cached_data)
# 2단계: 캐시 미스 시 SQL 데이터베이스에서 조회
print(f"캐시 미스: user_id={user_id}")
user_data = query_database(user_id) # SQL 쿼리
# 3단계: 결과를 Redis에 저장 (TTL: 3600초)
redis_client.setex(
cache_key,
3600,
json.dumps(user_data)
)
return user_data
데이터 변경 시 캐시 무효화
def update_user_info(user_id, new_data):
# 1단계: SQL 데이터베이스 업데이트
update_database(user_id, new_data)
# 2단계: Redis 캐시 삭제
cache_key = f"user:{user_id}"
redis_client.delete(cache_key)
print(f"캐시 무효화: user_id={user_id}")
return True
상품 목록 캐싱 (Hash 사용)
def get_product_list(category):
cache_key = f"products:{category}"
# Redis Hash에서 모든 상품 조회
products = redis_client.hgetall(cache_key)
if products:
print(f"캐시 히트: category={category}")
return {k.decode(): json.loads(v) for k, v in products.items()}
# 캐시 미스 시 데이터베이스에서 조회
products = query_products_by_category(category)
# Hash로 저장 (product_id를 필드로 사용)
for product in products:
redis_client.hset(
cache_key,
product['id'],
json.dumps(product)
)
# 1시간 후 자동 만료
redis_client.expire(cache_key, 3600)
return products
자주 하는 실수
-
TTL 설정 없이 캐시 저장 Redis 메모리가 무한정 증가하면 서버가 다운될 수 있습니다. 모든 캐시에 적절한 TTL을 설정하세요.
-
캐시 무효화 누락 데이터베이스는 업데이트했지만 Redis 캐시는 그대로 두면 사용자가 구 데이터를 계속 보게 됩니다.
-
대용량 객체를 문자열로 저장 복잡한 객체는 JSON 직렬화 오버헤드가 크므로 Hash나 Set 구조를 활용하는 것이 효율적입니다.
-
캐시 스탬피드 미처리 인기 있는 데이터의 캐시가 만료되면 수천 개의 요청이 동시에 데이터베이스를 조회합니다. 락(Lock) 메커니즘을 추가하세요.
-
Redis 연결 풀 미설정 매번 새로운 연결을 만들면 성능이 급격히 떨어집니다. 연결 풀을 사용하세요.
오늘의 실습 체크리스트
- 로컬 환경에 Redis 설치 및 실행 확인
- Python redis 라이브러리 설치 (
pip install redis) - get_user_info() 함수 구현 및 테스트
- update_user_info() 함수로 캐시 무효화 동작 확인
- redis-cli를 이용해 저장된 데이터 직접 조회
- TTL 설정 후 시간 경과에 따른 자동 만료 확인
- Hash 구조로 상품 목록 캐싱 구현
- 캐시 히트/미스 로그 출력으로 동작 검증
댓글