Python 데코레이터로 API 응답 캐싱 처리하기
문제 상황
사내 통계 대시보드에서 같은 API를 짧은 시간 내에 반복 호출하면서 DB 커넥션 풀이 고갈되는 문제가 발생했다. 특히 집계 쿼리가 많아 응답 시간도 느렸다.
Redis를 도입할까 고민했지만, 일단 간단하게 메모리 캐싱으로 시작하기로 했다.
구현
import functools
import time
from typing import Any, Callable
def cache_response(ttl: int = 300):
"""TTL 기반 메모리 캐시 데코레이터"""
cache = {}
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs) -> Any:
key = f"{func.__name__}:{str(args)}:{str(kwargs)}"
now = time.time()
if key in cache:
result, timestamp = cache[key]
if now - timestamp < ttl:
return result
result = func(*args, **kwargs)
cache[key] = (result, now)
return result
return wrapper
return decorator
Flask 뷰 함수에 적용:
@app.route('/api/stats/daily')
@cache_response(ttl=60)
def get_daily_stats():
date = request.args.get('date')
# 무거운 집계 쿼리
return jsonify(calculate_daily_stats(date))
결과
- 응답 시간: 평균 300ms → 20ms
- DB 커넥션 사용량: 70% → 30%
- 코드 변경 최소화 (데코레이터 1줄 추가)
개선 포인트
현재는 프로세스 메모리에만 캐시가 저장되어 멀티 프로세스 환경에서는 각자 캐시를 가진다. 트래픽이 더 늘어나면 Redis나 Memcached로 전환할 예정이다.
또한 캐시 키 생성 방식이 단순해서 복잡한 객체는 제대로 구분하지 못할 수 있다. 필요하면 hashlib으로 개선할 수 있다.