TIL2026. 8. 18.
캐시 개념 정리
#개념
캐시란
같은 데이터를 반복 요청하지 않도록 결과를 저장해두는 것. 어디에, 얼마나, 누구 기준으로 저장하느냐에 따라 종류가 나뉨.
1. 브라우저 캐시 (Client-side)
브라우저가 로컬 디스크에 저장. 개인 단위.
1-1. HTTP 캐시 (디스크/메모리 캐시)
서버 응답 헤더(Cache-Control, ETag, Last-Modified)에 따라 브라우저가 자동 저장.
Cache-Control: max-age=3600 → 1시간 동안 서버 요청 안 함
Cache-Control: no-cache → 매번 서버에 유효성 확인
Cache-Control: no-store → 아예 저장 안 함- 같은 이미지, JS, CSS 반복 다운로드 방지
ETag: 파일 해시. 서버에 "이거 바뀌었어?" 물어봄 → 안 바뀌었으면 304 응답 (본문 없음)- 강력 새로고침(Ctrl+Shift+R): 이 캐시 무시하고 서버에 새로 요청
1-2. Service Worker 캐시
개발자가 JS로 직접 제어하는 캐시. Cache API 사용.
// 설치 시 정적 자산 미리 캐시
self.addEventListener('install', (e) => {
e.waitUntil(
caches.open('v1').then((cache) =>
cache.addAll(['/index.html', '/style.css'])
)
);
});- 오프라인 지원 가능 (PWA)
- 네트워크 요청 가로채서 캐시 우선/네트워크 우선 전략 선택
- 브라우저 캐시와 달리 만료 정책을 코드로 완전 제어
1-3. 메모리 캐시 (JS 런타임)
변수, Map, 상태에 저장. 탭 닫으면 사라짐.
const cache = new Map();
function getData(key) {
if (cache.has(key)) return cache.get(key);
const data = fetchFromAPI(key);
cache.set(key, data);
return data;
}- React Query, SWR 등이 이 방식. API 응답을 메모리에 캐시하고 stale 시간 관리.
2. 서버/CDN 캐시 (Server-side)
서버 또는 CDN이 저장. 모든 유저 공유.
2-1. CDN 캐시 (Edge 캐시)
전 세계 엣지 서버에 응답 복사본 저장. Vercel, Cloudflare 등.
유저 (서울) → 도쿄 엣지 → 캐시 있음 → 즉시 응답 (오리진 서버 안 감)
유저 (LA) → SF 엣지 → 캐시 있음 → 즉시 응답- 모든 유저가 같은 캐시 공유
- 지리적으로 가까운 엣지에서 서빙 → 빠름
- 오리진 서버 부하 0
2-2. ISR 캐시 (Incremental Static Regeneration)
Next.js 전용 개념. CDN 캐시 + 백그라운드 재생성 결합.
export const revalidate = 43200; // 12시간동작 흐름:
[0초] 첫 요청 → 서버 렌더링 → HTML 생성 → CDN 저장 → 유저에게 응답
[1~12h] 모든 요청 → CDN 캐시 서빙 (서버 실행 0)
[12h] 캐시 만료 → 요청 오면:
1. stale 캐시 먼저 서빙 (유저는 빠르게 받음)
2. 백그라운드에서 서버 재렌더링
3. 새 HTML로 CDN 캐시 교체
[12h+] 다음 요청부터 새 캐시 서빙핵심 특징:
- 유저가 느린 응답 받는 순간 = 배포 직후 첫 요청 딱 1번
- 만료 후에도 stale 캐시 먼저 보여줌 (느린 응답 없음)
revalidatePath()/revalidateTag()로 수동 갱신 가능
2-3. SSR 캐시 없음 (force-dynamic)
export const dynamic = "force-dynamic";매 요청마다 서버 함수 실행. 캐시 안 함.
유저A 요청 → 서버 실행 → DB 조회 → 렌더링 → 응답
유저B 요청 → 서버 실행 → DB 조회 → 렌더링 → 응답 (똑같은 작업 반복)- 항상 최신 데이터
- 서버 부하 비례 증가
2-4. SSG (Static Site Generation)
빌드 시점에 HTML 생성. 배포 후 변하지 않음.
빌드 시 → HTML 생성 → CDN에 배포 → 재배포 전까지 동일- 가장 빠름 (완전 정적)
- 데이터 변경 반영 = 재빌드 필요
2-5. 서버 메모리/Redis 캐시
서버 애플리케이션 레벨에서 DB 쿼리 결과 등을 메모리나 Redis에 저장.
요청 → Redis에 캐시 있음? → 있으면 반환 / 없으면 DB 조회 후 저장- DB 부하 감소
- TTL(Time To Live) 설정으로 자동 만료
- Vercel Serverless에서는 함수 인스턴스 간 메모리 공유 안 되므로 Redis(Upstash 등) 필요
3. DNS 캐시
도메인 → IP 변환 결과를 OS/브라우저/라우터가 저장.
dolchimdae.vercel.app → 76.76.21.21 (캐시됨, DNS 서버 안 감)- TTL 보통 수 분~수 시간
ipconfig /flushdns(Windows)로 초기화
4. DB 캐시 (Query Cache)
데이터베이스 자체가 쿼리 결과 캐시. PostgreSQL의 shared_buffers, MySQL의 Query Cache 등.
같은 SELECT → 디스크 안 읽고 메모리에서 반환- 개발자가 직접 제어할 일 적음
- Supabase(PostgreSQL) 자체적으로 동작
비교 요약
| 캐시 종류 | 저장 위치 | 공유 범위 | 제어 방법 | 무효화 |
|---|---|---|---|---|
| 브라우저 HTTP | 유저 디스크 | 개인 | Cache-Control 헤더 | 강력새로고침, 시간만료 |
| Service Worker | 유저 디스크 | 개인 | JS 코드 | 코드로 삭제 |
| 메모리 (SWR 등) | 유저 RAM | 개인 (탭) | 라이브러리 설정 | 탭 닫기, refetch |
| CDN/Edge | 엣지 서버 | 전체 유저 | 서버 헤더 | 퍼지, 재배포 |
| ISR | Vercel CDN | 전체 유저 | revalidate 값 | 시간만료, revalidatePath |
| SSG | CDN | 전체 유저 | 빌드 시 생성 | 재빌드 |
| Redis | 서버 메모리 | 전체 요청 | TTL, 코드 | TTL 만료, DEL 명령 |
| DNS | OS/라우터 | 개인/네트워크 | TTL | flushdns |
| DB Query | DB 메모리 | 전체 쿼리 | DB 설정 | 데이터 변경 시 자동 |
현재 프로젝트 적용 상태
/job-radar → ISR 12시간 (CDN 캐시, 전체 유저 공유)
/job-radar/saved → ISR 12시간
/job-radar/gap → ISR 12시간
/job-radar/[id] → 동적 (매 요청 서버 실행)
/blog, /projects → ISR (빌드 시 설정값 따름)캐시 레이어 순서 (요청 흐름):
브라우저 캐시 → CDN/ISR 캐시 → Serverless Function → Supabase (DB 캐시)
개인용 전체 공유 서버 실행 DB 레벨각 레이어에서 캐시 히트하면 그 아래로 안 감. ISR에서 히트하면 서버 함수 실행 자체가 없음.