OneWebDesk

SWR 캐시 설계기

max-age와 stale-while-revalidate 값을 설계해 헤더로 출력합니다.

stale-while-revalidate(SWR)는 캐시가 만료된 직후에도 사용자에게 묵은(stale) 응답을 즉시 돌려주고, 백그라운드에서 조용히 최신본을 다시 가져오는 캐시 전략입니다. 덕분에 만료 경계에서 발생하는 느린 요청(캐시 미스 폭주)을 없애고, 거의 항상 캐시 속도로 응답하면서도 콘텐츠를 적당히 신선하게 유지할 수 있습니다.

이 설계기는 max-age, stale-while-revalidate, 선택적 stale-if-error, 그리고 public/private 범위를 입력하면 바로 붙여 쓸 수 있는 Cache-Control 헤더를 조립해 줍니다. 동시에 각 구간을 초·분 단위로 환산하고, 요청이 들어온 시점에 따라 응답이 어떻게 동작하는지 타임라인으로 설명합니다.

Cache-Control 헤더
Cache-Control: public, max-age=60, stale-while-revalidate=600
구간 환산
신선 구간 (0 ~ max-age)60초 (1분)
백그라운드 갱신 구간 (swr)600초 (10분)
묵은 응답 총 허용 (max-age + swr)660초 (11분)
오류 시 제공 (stale-if-error)
동작 타임라인
  1. 0 ~ 60초: 신선. 캐시가 즉시 응답하며 원본 요청 없음.
  2. 60 ~ 660초: 묵은 응답을 즉시 반환 + 백그라운드에서 원본 재검증. 사용자 대기 없음.
  3. 660초 이후: SWR 창 종료. 다음 요청은 동기 재검증(원본 응답까지 대기).

각 지시어가 의미하는 것

Cache-Control 응답 헤더에서 세 지시어는 캐시(브라우저·CDN)가 응답을 다루는 방식을 정합니다.

  • max-age=N: 응답이 신선하다고 간주되는 시간(초). 이 구간에는 캐시가 원본에 묻지 않고 바로 응답합니다.
  • stale-while-revalidate=N: max-age가 지난 뒤에도 N초 동안은 묵은 응답을 즉시 돌려주고, 같은 순간 백그라운드에서 재검증(원본 재요청)을 수행합니다. 사용자는 기다리지 않습니다.
  • stale-if-error=N: 원본이 오류(5xx)나 응답 불가 상태일 때, 만료 후 N초까지는 묵은 응답을 대신 제공해 장애를 감춥니다. 가용성 보험에 해당합니다.
  • public / private: public은 CDN 등 공유 캐시도 저장 가능, private는 최종 사용자 브라우저 캐시에만 저장(사용자별 콘텐츠).

응답이 동작하는 타임라인

어떤 응답이 캐시에 저장된 시점을 0초라고 하면, 이후 요청 시점에 따라 캐시는 다음처럼 동작합니다.

  1. 0초 ~ max-age: 신선 구간. 캐시가 즉시 응답, 원본 요청 없음.
  2. max-age ~ (max-age + swr): 백그라운드 갱신 구간. 사용자에게는 묵은 응답을 바로 주고, 동시에 캐시는 원본에서 새 응답을 받아 갱신합니다. 체감 지연 0.
  3. (max-age + swr) 이후: SWR 창이 닫혀 더 이상 묵은 응답을 줄 수 없으므로, 다음 요청은 원본 재검증이 끝날 때까지 기다립니다(동기 재검증).

max-age를 짧게, stale-while-revalidate를 길게 두면 “거의 항상 빠른 응답 + 꾸준한 백그라운드 갱신”을 얻습니다. 자세한 캐시 헤더 조립은 Cache-Control 빌더와 함께 쓰면 좋고, 임시 접근용 서명 URL의 만료 시각은 서명 URL 만료 계산기로 설계하세요.

장점과 주의점

SWR의 핵심 이점:

  • 만료 경계의 “캐시 미스 천둥떼(thundering herd)”와 느린 첫 요청을 제거합니다.
  • 거의 모든 응답이 캐시 속도라 TTFB가 안정적입니다.
  • stale-if-error까지 더하면 원본 장애 시에도 마지막 정상본으로 버틸 수 있습니다.

주의할 점:

  • 사용자가 항상 최신본을 본다는 보장은 없습니다. SWR 구간 동안은 한 박자 묵은 데이터를 받을 수 있으니, 결제 금액·재고처럼 즉시 정확성이 필요한 응답에는 부적합합니다.
  • 모든 브라우저·CDN이 SWR을 동일하게 지원하지는 않습니다. 미지원 캐시는 보통 max-age까지만 신선으로 취급합니다.
  • 백그라운드 갱신도 결국 원본 요청을 발생시킵니다. swr 창이 매우 길면 트래픽이 적은 리소스는 갱신이 드물게 일어나 더 묵은 응답을 줄 수 있습니다.

자주 묻는 질문

max-age=0, stale-while-revalidate=60 으로 두면 어떻게 되나요?
응답은 저장 즉시 stale로 간주되지만, 60초 동안은 묵은 응답을 바로 주면서 매 요청마다 백그라운드 재검증을 트리거합니다. 사실상 '항상 캐시 속도로 응답하되 1분 이내로 갱신'하는 패턴으로, 자주 바뀌지만 1분 지연은 허용되는 콘텐츠에 흔히 씁니다.
stale-while-revalidate는 max-age에 더해지나요, 포함되나요?
더해집니다. 묵은 응답을 줄 수 있는 총 기간은 max-age + stale-while-revalidate 입니다. 즉 max-age=60, swr=600이면 만료 후에도 600초(총 660초까지) 동안 SWR 동작이 가능합니다.
stale-if-error는 꼭 필요한가요?
선택 사항입니다. 원본(오리진)이 5xx 등으로 응답하지 못할 때 마지막 정상 응답으로 버티고 싶다면 추가하세요. 가용성에 민감한 페이지에 유용하며, 평소 동작에는 영향을 주지 않습니다.
이 도구는 입력값을 서버로 보내나요?
아니요. 헤더 문자열 조립과 구간 환산은 모두 브라우저에서만 계산되며, 입력값이 외부로 전송되지 않습니다.
CDN과 브라우저 캐시가 다르게 동작할 수 있나요?
네. public이면 CDN(공유 캐시)과 브라우저 모두 저장하지만, SWR 지원 여부와 동작 시점은 구현마다 조금씩 다를 수 있습니다. 운영 전에 실제 응답 헤더와 동작을 검증하세요.

관련 도구