How to Design and Implement Caching Strategies: Claude Code 활용 가이드
design and implement caching strategies: Claude Code 활용. 실용적인 코드 예시와 단계별 가이드를 포함합니다.
캐시戦略の설계にClaude Code를 사용하는メリット
캐시は적절하게설계しないと、古い데이터の표시や메모리の浪費につながります。Claude Code는 애플리케이션の데이터アクセスパターンを分析し、最適な캐시戦略を提案・구현할 수 있습니다。
Redis캐시の구현
> Redis를 사용한캐시レイヤー를 구현해줘。
> 캐시무효化、TTL관리、캐시アサイドパターンで。
// src/lib/cache.ts
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL!);
interface CacheOptions {
ttl?: number; // 秒単位
prefix?: string;
}
export class CacheService {
private defaultTTL = 300; // 5分
async get<T>(key: string, options?: CacheOptions): Promise<T | null> {
const fullKey = this.buildKey(key, options?.prefix);
const data = await redis.get(fullKey);
if (!data) return null;
try {
return JSON.parse(data) as T;
} catch {
return null;
}
}
async set<T>(key: string, value: T, options?: CacheOptions): Promise<void> {
const fullKey = this.buildKey(key, options?.prefix);
const ttl = options?.ttl ?? this.defaultTTL;
await redis.setex(fullKey, ttl, JSON.stringify(value));
}
async getOrSet<T>(
key: string,
fetcher: () => Promise<T>,
options?: CacheOptions
): Promise<T> {
const cached = await this.get<T>(key, options);
if (cached !== null) return cached;
const data = await fetcher();
await this.set(key, data, options);
return data;
}
async invalidate(key: string, prefix?: string): Promise<void> {
const fullKey = this.buildKey(key, prefix);
await redis.del(fullKey);
}
async invalidatePattern(pattern: string): Promise<void> {
const keys = await redis.keys(pattern);
if (keys.length > 0) {
await redis.del(...keys);
}
}
private buildKey(key: string, prefix?: string): string {
return prefix ? `${prefix}:${key}` : key;
}
}
export const cache = new CacheService();
캐시アサイドパターンの구현
// src/services/product-service.ts
import { cache } from '@/lib/cache';
import { prisma } from '@/lib/db';
export class ProductService {
async getProduct(id: string) {
return cache.getOrSet(
`product:${id}`,
() => prisma.product.findUnique({
where: { id },
include: { category: true, reviews: { take: 10 } },
}),
{ ttl: 600, prefix: 'products' }
);
}
async getPopularProducts(limit = 20) {
return cache.getOrSet(
`popular:${limit}`,
() => prisma.product.findMany({
orderBy: { salesCount: 'desc' },
take: limit,
include: { category: true },
}),
{ ttl: 300, prefix: 'products' }
);
}
async updateProduct(id: string, data: UpdateProductInput) {
const product = await prisma.product.update({
where: { id },
data,
});
// 関連캐시を무효化
await cache.invalidate(`product:${id}`, 'products');
await cache.invalidatePattern('products:popular:*');
return product;
}
}
HTTP 캐시헤더の설정
// src/middleware.ts
import { NextResponse, NextRequest } from 'next/server';
export function middleware(req: NextRequest) {
const res = NextResponse.next();
const path = req.nextUrl.pathname;
// 静的アセット:長期캐시
if (path.match(/\.(js|css|png|jpg|svg|woff2)$/)) {
res.headers.set('Cache-Control', 'public, max-age=31536000, immutable');
}
// API:캐시なし
if (path.startsWith('/api/')) {
res.headers.set('Cache-Control', 'no-store');
}
// 페이지:短期캐시 + ISR
if (!path.startsWith('/api/') && !path.match(/\.[a-z]+$/)) {
res.headers.set('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=300');
}
return res;
}
메모리캐시(애플리케이션内)
小規模な데이터にはイン메모리캐시が유효です。
// src/lib/memory-cache.ts
interface CacheEntry<T> {
value: T;
expiresAt: number;
}
export class MemoryCache {
private store = new Map<string, CacheEntry<unknown>>();
private maxSize: number;
constructor(maxSize = 1000) {
this.maxSize = maxSize;
}
get<T>(key: string): T | null {
const entry = this.store.get(key);
if (!entry) return null;
if (Date.now() > entry.expiresAt) {
this.store.delete(key);
return null;
}
return entry.value as T;
}
set<T>(key: string, value: T, ttlMs: number): void {
// サイズ制限チェック
if (this.store.size >= this.maxSize) {
const firstKey = this.store.keys().next().value;
if (firstKey) this.store.delete(firstKey);
}
this.store.set(key, {
value,
expiresAt: Date.now() + ttlMs,
});
}
clear(): void {
this.store.clear();
}
}
// 설정値などの頻繁にアクセスされる데이터に使用
export const configCache = new MemoryCache(100);
캐시戦略の選定가이드
| 데이터の種類 | 推奨캐시 | TTL目安 |
|---|---|---|
| 설정マスタ | 메모리 + Redis | 1시간 |
| 사용자プロフィール | Redis | 10分 |
| 상품목록 | Redis + CDN | 5分 |
| 세션情報 | Redis | 24시간 |
| 静的アセット | CDN | 1年 |
| API응답 | HTTP Cache | 1分 |
캐시の모니터링
// 캐시ヒット率の計測
export class CacheMetrics {
private hits = 0;
private misses = 0;
recordHit() { this.hits++; }
recordMiss() { this.misses++; }
getHitRate(): number {
const total = this.hits + this.misses;
return total === 0 ? 0 : this.hits / total;
}
getStats() {
return {
hits: this.hits,
misses: this.misses,
hitRate: `${(this.getHitRate() * 100).toFixed(1)}%`,
};
}
}
정리
Claude Code를 활용하면 Redis캐시、HTTP캐시、메모리캐시など多層的な캐시戦略を효율적으로설계・구현할 수 있습니다。캐시の설계方針をCLAUDE.mdに記述しておくと、프로젝트全体で一貫した구현が得られます。성능改善の全体像は生産性を3倍にするTips도 참고하세요.
Claude Code의 상세 정보는Anthropic공식 문서를 확인하세요.Redis의 상세 정보는Redis공식 문서를 참고하세요.
Claude Code 워크플로우를 한 단계 업그레이드하세요
지금 바로 Claude Code에 복사해 쓸 수 있는 검증된 프롬프트 템플릿 50선.
이 글을 작성한 사람
Masa
Claude Code를 적극 활용하는 엔지니어. 10개 언어, 2,000페이지 이상의 테크 미디어 claudecode-lab.com을 운영 중.
관련 글
Claude Code Agent SDK 입문 ― 자율 에이전트를 빠르게 구축하는 방법
Claude Code Agent SDK로 자율형 AI 에이전트를 구축하는 방법을 해설합니다. 설정부터 도구 정의, 멀티스텝 실행까지 실전 코드와 함께 소개합니다.
Claude Code 컨텍스트 관리 테크닉 완전 가이드
Claude Code의 컨텍스트 윈도우를 최대한 활용하는 실전 테크닉을 해설합니다. 토큰 절약, 대화 분할, CLAUDE.md 활용법까지 소개합니다.
Claude Code MCP Server 설정 및 실전 활용 가이드
Claude Code의 MCP Server 기능을 종합적으로 소개합니다. 외부 도구 연결, 서버 설정, 실전 통합 사례까지 한 번에 알아보세요.