캐싱은 비싼 작업(DB 쿼리, 연산, 외부 API 호출)의 결과를 저장하여 반복 요청이 작업을 다시 하지 않고 빠르게 처리되게 합니다. API에서 가장 효과가 큰 성능 최적화 중 하나입니다.
인메모리 캐싱(가장 빠르고, 단일 인스턴스)
cache = ();
() {
(cache.(id)) cache.(id);
user = db.(id);
cache.(id, user);
user;
}
캐싱은 비싼 작업(DB 쿼리, 연산, 외부 API 호출)의 결과를 저장하여 반복 요청이 작업을 다시 하지 않고 빠르게 처리되게 합니다. API에서 가장 효과가 큰 성능 최적화 중 하나입니다.
cache = ();
() {
(cache.(id)) cache.(id);
user = db.(id);
cache.(id, user);
user;
}
간단하고 극도로 빠르지만, 캐시가 프로세스별(인스턴스 간 공유되지 않음)이고 재시작 시 사라집니다. 작고 자주 쓰이는 데이터에 좋지만 메모리를 한정하려면 축출(eviction)이 필요합니다(lru-cache 같은 LRU 캐시 사용).
import { createClient } from "redis";
const redis = createClient();
async function getUser(id) {
const cached = await redis.get(`user:${id}`);
if (cached) return JSON.parse(cached); // hit
const user = await db.findUser(id);
await redis.setEx(`user:${id}`, 3600, JSON.stringify(user)); // cache for 1h (TTL)
return user;
}
Redis는 여러 서버 인스턴스 간 캐싱의 표준입니다. 공유되고 빠른 저장소로, 재시작 후에도 유지되며 앱과 함께 확장됩니다. TTL(time-to-live)은 항목을 자동 만료시켜 데이터가 영원히 오래된 채로 남지 않게 합니다.
res.set("Cache-Control", "public, max-age=3600"); // browsers/CDN cache for 1h
res.set("ETag", hash); // conditional requests (304 Not Modified)
HTTP 캐시 헤더는 캐싱을 브라우저와 CDN으로 완전히 위임합니다. 가장 빠른 캐시는 서버에 도달하지 않는 요청입니다.
// when data changes, the cache must be updated or cleared, or users see stale data
async function updateUser(id, data) {
await db.updateUser(id, data);
await redis.del(`user:${id}`); // INVALIDATE — next read repopulates with fresh data
}
가장 큰 캐싱 과제는 무효화입니다. 업데이트가 영향받는 캐시 항목을 비우거나 갱신하여 사용자가 오래된 데이터를 보지 않게 보장하는 것입니다. 전략: TTL(잠깐의 오래됨 허용), write-through(쓰기 시 캐시 업데이트), 또는 변경 시 명시적 삭제.
✓ Read-heavy, infrequently-changing data (config, product catalogs, user profiles)
✓ Expensive computations, external API responses
✗ Highly dynamic/personalized or rapidly-changing data (or use very short TTLs)
✗ Sensitive data without care for who can read the cache
캐싱은 지연 시간과 데이터베이스/외부 부하를 극적으로 줄이며, 종종 느린 API와 빠르고 확장 가능한 API의 차이를 만듭니다.
계층을 아는 것 — 인메모리(가장 빠르고, 인스턴스별, LRU로 한정), Redis(인스턴스 간 공유), HTTP/CDN 캐싱(완전히 위임) — 은 올바른 전략을 고르게 합니다.
그리고 캐싱의 핵심 난제인 무효화(TTL이나 쓰기 시 명시적 비움을 통한)를 이해하는 것이 사용자에게 오래된 데이터를 제공하는 전형적인 트레이드오프 실패를 막습니다.
효과적인 캐싱은 API 성능과 확장성을 위한 가장 영향력 있는 도구 중 하나입니다.