정의
stale-while-revalidate(SWR) 는 Service Worker(페이지와 네트워크 사이에서 fetch를 가로채는 브라우저 스크립트)가 Cache Storage에 있는 응답을 먼저 돌려주고, 동시에 백그라운드 네트워크 요청으로 캐시를 갱신하는 전략이다. 캐시 miss일 때만 네트워크 완료를 기다린다.
왜 필요한가
문서·이미지처럼 크고 반복 조회되는 리소스는 매번 네트워크를 기다리면 체감이 느리다. "캐시만" 쓰면 오래된 파일이 남고, "네트워크만" 쓰면 첫 표시가 늦다. SWR은 첫 페인트는 빠르게, 최신성은 뒤에서 맞춘다.
브라우저 Cache Storage API는 용량 상한·LRU 제거를 기본 제공하지 않는다. 바이트 예산·메타데이터는 애플리케이션이 직접 관리해야 한다.
동작 원리
핵심 규칙:
- GET 성공 응답만 저장.
Range·HEAD·PUT등은 캐시하지 않아 부분/손상 응답 혼입을 막는다. - 404·410은 원본 삭제 신호 — 기존 캐시 항목도 제거한다.
- 캐시 키는 presigned-url-cache-key-normalization처럼 인증 쿼리만 제거한다.
- 용량: 이미지 본문 +
{key, bytes, lastAccess}메타를 별도 저장, 총 바이트가 예산(예: 100MB)을 넘으면 LRU로 제거. - 적중 시
lastAccess갱신 — 개수가 아닌 바이트 합 기준이 크기 차이 큰 이미지에 공정하다.
실무 적용
- 외부 객체 스토리지 URL은 same-origin 프록시로 통일하면 SW scope·쿠키 제어가 쉽다.
- 민감 이미지(마스킹 전 원본)에는 SWR 즉시 반환을 쓰지 않는다 — cache-generation-stale-write-guard와 삭제 ACK 순서를 따른다.
트레이드오프
- SWR은 약간 오래된 콘텐츠를 잠깐 보여줄 수 있다 — 일반 문서 이미지에는 허용, PII 마스킹 직후에는 불가.
- SW 등록·업데이트·디버깅 비용이 있다. Workbox 같은 라이브러리는 보일러플레이트를 줄이지만 정책 이해는 여전히 필요하다.
- 백그라운드 revalidate는 삭제와 race — generation guard 없으면 삭제 후 원본이 되살아난다.
사용하면 안 되는 경우
- 항상 최신이어야 하는 인증 토큰·결제 결과 API 응답.
Range스트리밍·비디오 시크가 핵심인 미디어(부분 캐시 오염).- SW를 쓸 수 없는 환경만 타깃일 때 — 서버 CDN 캐시·HTTP
Cache-Control만으로 충분한지 먼저 본다.
흔한 실수
- presigned URL 쿼리 전체를 키에서 제거해 마스킹·원본이 같은 항목으로 충돌한다.
- 캐시 삭제만 하고 in-flight revalidate를 막지 않는다.
- 개수 제한만 두어 큰 이미지 하나가 예산을 다 쓰거나, 작은 썸네일만 LRU에서 살아남는다.
- 페이지가 SW 제어 전에 삭제 메시지만 보내고 무한 대기한다 — 타임아웃·직접
caches.delete병행.
관련 개념
- presigned-url-cache-key-normalization — 서명 쿼리 strip·의미 쿼리 보존
- cache-generation-stale-write-guard — 삭제 후 stale write 방지
- server-image-proxy-transcoding-cache — 서버 프록시 LRU와 역할 분담