1언제 필요해?
- API 응답 캐싱 - DB 쿼리 결과를 캐시해 응답 속도 향상
- 세션 저장 - 로그인 세션을 여러 서버 간 공유
- 실시간 순위/카운터 - 조회수, 좋아요, 리더보드
- Rate Limiting - API 요청 횟수 제한
2주요 서비스
Redis (Upstash)
가장 인기, 서버리스 무료키-값 저장소의 표준. 문자열, 해시, 리스트, 셋, 정렬 셋 등 다양한 자료구조를 지원합니다. Upstash는 서버리스 Redis 서비스입니다.
Memcached
단순 캐싱 전용단순 키-값 캐싱에 특화. Redis보다 기능이 적지만 단순 캐시 용도에서는 약간 더 빠를 수 있습니다.
Valkey
Redis 포크, 오픈소스Redis의 오픈소스 포크. Redis와 API 호환되며 Linux Foundation에서 관리합니다.
3비용
- Upstash Redis - 무료 티어 10K 명령/일, 256MB 스토리지
- Redis Cloud - 무료 티어 30MB (소규모 캐시에 적합)
- 자체 Redis - Docker로 로컬 설치 시 무료 (서버 비용은 별도)
4연결 예제
FastAPI + redis-py (Python)
app/cache.py
# app/cache.py
import redis.asyncio as redis
REDIS_URL = "redis://localhost:6379"
redis_client = redis.from_url(REDIS_URL, decode_responses=True)app/main.py
# app/main.py
import json
from fastapi import FastAPI
from app.cache import redis_client
app = FastAPI()
@app.get("/products/{product_id}")
async def get_product(product_id: str):
# 캐시 확인
cached = await redis_client.get(f"product:{product_id}")
if cached:
return json.loads(cached)
# DB에서 조회 (여기서는 예시)
product = {"id": product_id, "name": "노트북", "price": 1200000}
# 캐시에 저장 (TTL 1시간)
await redis_client.set(
f"product:{product_id}",
json.dumps(product),
ex=3600
)
return product
@app.post("/leaderboard")
async def update_score(user_id: str, score: int):
# Sorted Set으로 실시간 순위
await redis_client.zadd("leaderboard", {user_id: score})
rank = await redis_client.zrevrank("leaderboard", user_id)
return {"user_id": user_id, "score": score, "rank": rank + 1}Hono + @upstash/redis (TypeScript)
src/cache.ts
// src/cache.ts
import { Redis } from '@upstash/redis';
const redis = new Redis({
url: 'https://your-endpoint.upstash.io',
token: 'your-token',
});
export default redis;src/index.ts
// src/index.ts
import { Hono } from 'hono';
import redis from './cache';
const app = new Hono();
app.get('/products/:id', async (c) => {
const id = c.req.param('id');
// 캐시 확인
const cached = await redis.get<string>(`product:${id}`);
if (cached) {
return c.json(JSON.parse(cached));
}
// DB에서 조회 (여기서는 예시)
const product = { id, name: '노트북', price: 1200000 };
// 캐시에 저장 (TTL 1시간)
await redis.set(`product:${id}`, JSON.stringify(product), { ex: 3600 });
return c.json(product);
});
app.get('/leaderboard', async (c) => {
const top10 = await redis.zrange('leaderboard', 0, 9, { rev: true });
return c.json(top10);
});
export default app;캐시는 보조 저장소입니다
캐시 데이터는 언제든 사라질 수 있습니다. 항상 원본 데이터(RDB/NoSQL)를 함께 사용하고, 캐시 미스(miss) 시 원본에서 다시 읽는 로직을 구현하세요.