서비스

서비스

원본 서버가 죽어도 사이트는 살아있다 — stale-while-revalidate·stale-if-error로 만드는 CDN 가용성

원본 서버가 죽어도 사이트는 살아있다 — stale-while-revalidate·stale-if-error로 만드는 CDN 가용성

🤖 AI Summary

CDN을 깔아도 캐시가 만료되는 순간, 사이트는 다시 원본 서버에 의존합니다. 이때 원본이 느리거나 죽어 있으면 사용자는 그대로 대기 화면이나 에러를 보게 되죠. stale-while-revalidate는 응답이 만료된 뒤에도 일단 옛 응답을 즉시 내보내면서 뒤에서 조용히 갱신해 지연을 숨기고, stale-if-error는 원본이 500·502·503·504 오류를 낼 때 캐시된 옛 응답으로 버팁니다. 둘 다 RFC 5861에 정의된 Cache-Control 확장이고, Fastly를 비롯한 CDN이 이를 구현합니다. 이 글에서는 두 디렉티브의 동작과 설정 예시, 그리고 어떤 콘텐츠에 어디까지 적용해야 하는지를 1차 표준 기준으로 정리합니다.

블로그 목차

캐시가 만료되는 순간, 가용성 구멍이 열린다

CDN을 도입하면 트래픽 대부분을 엣지 캐시가 받아내니, 원본 서버는 한결 여유로워집니다. 그런데 한 가지 사각지대가 있습니다. 바로 캐시가 만료(stale)되는 순간입니다.

일반적인 캐시 동작에서는 응답이 만료되면, 다음 요청은 원본 서버에 다시 물어본 뒤에야 사용자에게 전달됩니다. 평소에는 몇십 밀리초면 끝나죠. 문제는 하필 그 순간 원본이 느려지거나, 배포 중이거나, 아예 죽어 있을 때입니다. 그러면 사용자는 갱신을 기다리느라 멈춘 화면을, 최악의 경우 502·503 에러 페이지를 보게 됩니다. 캐시가 있어도 "만료 직후 + 원본 장애"라는 조합에서는 가용성이 그대로 뚫리는 셈입니다.

이 구멍을 메우는 표준이 RFC 5861의 두 가지 Cache-Control 확장, stale-while-revalidate와 stale-if-error입니다. 참고로 RFC 5861은 표준화 트랙 문서는 아니고 2010년 Mark Nottingham이 정보 제공(Informational) 목적으로 발행한 문서지만, 오늘날 Fastly 같은 CDN이 이 동작을 구현하고 있습니다.




stale-while-revalidate — 만료돼도 일단 보여주고, 뒤에서 갱신

stale-while-revalidate는 이름 그대로 "재검증하는 동안 stale을 제공"하는 동작입니다. RFC 5861의 정의를 그대로 옮기면 이렇습니다.

응답에 stale-while-revalidate 확장이 있으면, 캐시는 그 응답이 stale 상태가 된 후에도 지정된 초만큼 응답을 제공할 수 있다(MAY).

핵심은 블로킹 없이 동작한다는 점입니다. RFC는 "stale 응답을 계속 제공하면서(즉, 블로킹 없이) 재검증을 시도해야 한다(SHOULD)"고 명시합니다. 즉 사용자는 만료된 캐시라도 즉시 응답을 받고, 갱신은 그 뒤에서 조용히 일어납니다. 사용자 입장에서는 "원본이 느린 순간"이 보이지 않게 됩니다.




stale-if-error — 원본이 5xx여도 옛 응답으로 버틴다

stale-while-revalidate가 지연을 숨기는 장치라면, stale-if-error는 장애를 버티는 장치입니다. RFC 5861의 정의는 이렇습니다.

오류가 발생하면, 다른 신선도 정보와 무관하게 캐시된 stale 응답을 요청 처리에 사용할 수 있다(MAY).

여기서 말하는 "오류"의 범위도 문서에 분명히 적혀 있습니다. 500, 502, 503, 504 상태 코드가 반환되는 상황을 의미합니다. 다시 말해 원본이 죽어서 5xx를 뱉는 동안에도, 캐시는 마지막으로 받아둔 정상 응답을 사용자에게 계속 보여줄 수 있습니다. 원본 복구까지의 시간을 사용자에게 들키지 않고 버는 것이죠.




실제 설정 — Cache-Control 한 줄로 시작한다

적용은 의외로 단순합니다. 응답의 Cache-Control 헤더에 디렉티브를 더하면 됩니다. MDN의 예시를 그대로 보면 이렇습니다.

Cache-Control: max-age=604800, stale-while-revalidate=86400
Cache-Control: max-age=604800, stale-if-error=86400
Cache-Control: max-age=604800, stale-while-revalidate=86400
Cache-Control: max-age=604800, stale-if-error=86400
Cache-Control: max-age=604800, stale-while-revalidate=86400
Cache-Control: max-age=604800, stale-if-error=86400

위 설정은 응답을 7일(604800초) 동안 fresh로 두고, 만료된 뒤 하루(86400초) 동안은 각각 "백그라운드 재검증을 전제로 재사용" 또는 "오류 시 재사용"을 허용한다는 뜻입니다. 두 디렉티브를 함께 쓰면 지연도 숨기고 장애도 버틸 수 있습니다.

CDN 단에서는 어떻게 적용할까요. Fastly 문서 기준으로, Fastly는 RFC 5861의 동작을 기반으로 하며 Cache-Control 또는 Surrogate-Control 헤더에 디렉티브를 넣어 stale 제공을 활성화합니다. 컨트롤 패널로 오류 시 stale 제공을 켜면 기본 TTL 기간은 43200초(12시간)이고, 더 세밀한 제어가 필요하면 커스텀 VCL로 동작 시간을 직접 조정합니다.

캐시 만료 직후, 같은 요청의 두 가지 결말




어디까지 stale을 허용할까 — 콘텐츠별로 다르게

강력한 만큼, 아무 데나 쓰면 안 되는 기능이기도 합니다. stale 제공은 말 그대로 "옛 응답을 잠깐 더 보여주는" 것이라, 항상 최신이어야 하는 데이터에는 맞지 않습니다. Fastly 문서도 stale 객체는 캐시 가능한 콘텐츠에 대해서만 사용할 수 있다고 못 박습니다.

콘텐츠 유형

stale 적용

이유

정적 자산·이미지·공개 페이지

적합

잠깐 옛 버전이어도 영향 적음, 가용성 이득 큼

자주 안 바뀌는 목록·콘텐츠

짧게 허용

신선도와 가용성의 균형 지점

결제·로그인 상태·실시간 잔액

부적합

옛 값이 곧 사고, 항상 원본 확인 필요

그래서 실제 설계는 "전부 켜기"가 아니라, 콘텐츠 종류별로 max-age와 stale 기간을 다르게 잡는 작업이 됩니다. 캐시를 언제 비울지(CDN 캐시 퍼지)와 함께, 만료된 뒤 어떻게 버틸지까지 정해두면 캐시 정책이 비로소 완성됩니다.




이것만 기억하세요

CDN을 깔아도 캐시가 만료되는 순간 + 원본 장애가 겹치면 가용성이 뚫립니다. stale-while-revalidate는 만료된 응답을 즉시 내보내면서 블로킹 없이 백그라운드로 갱신해 지연을 숨기고, stale-if-error는 원본이 500·502·503·504를 낼 때 캐시된 옛 응답으로 버팁니다. 둘 다 RFC 5861의 Cache-Control 확장이고, Cache-Control: max-age=604800, stale-while-revalidate=86400처럼 헤더 한 줄로 시작합니다. 단 stale은 캐시 가능한 콘텐츠에만 쓰고, 결제·실시간 데이터에는 적용하지 않습니다. 콘텐츠별로 max-age와 stale 기간을 다르게 설계하는 것이 핵심입니다.




자주 묻는 질문 (FAQ)

Q. stale-while-revalidate와 stale-if-error는 무엇이 다른가요?

stale-while-revalidate는 응답이 만료된 뒤 지정한 초 동안 stale 응답을 즉시 내보내면서 블로킹 없이 백그라운드로 재검증합니다. stale-if-error는 원본이 500·502·503·504 오류를 낼 때 신선도와 무관하게 캐시된 stale 응답을 사용해 버팁니다. 전자는 지연을 숨기고, 후자는 장애를 버티는 용도예요.

Q. 어떻게 설정하나요?

Cache-Control 헤더에 디렉티브를 더하면 됩니다. 예: Cache-Control: max-age=604800, stale-while-revalidate=86400. Fastly 같은 CDN에서는 Cache-Control 또는 Surrogate-Control 헤더로 적용하고, 커스텀 VCL로 동작을 세밀하게 제어할 수 있어요.

Q. 모든 콘텐츠에 적용해도 되나요?

아닙니다. Fastly 문서 기준 stale 객체는 캐시 가능한 콘텐츠에만 쓸 수 있어요. 결제·로그인 상태·실시간 잔액처럼 항상 최신이어야 하는 응답에는 적합하지 않습니다. 잠깐 옛 버전이어도 문제가 적은 정적 자산·공개 페이지부터 적용하는 게 안전해요.

Q. RFC 5861은 공식 표준인가요?

표준화 트랙 사양이 아니라 정보 제공(Informational) 목적으로 2010년 5월 발행된 문서입니다. 저자는 Mark Nottingham이고, Fastly 같은 CDN이 이 동작을 구현하고 있어요.

Q. stale을 얼마나 길게 허용해야 하나요?

가용성과 신선도의 균형으로 정합니다. 참고로 Fastly 컨트롤 패널로 오류 시 stale 제공을 켜면 기본 TTL 기간이 43200초(12시간)예요. 다만 환경에 따라 조정하는 값이라, 자주 바뀌는 콘텐츠는 짧게, 정적 자산은 길게 잡는 식으로 콘텐츠별로 다르게 설계하는 게 좋습니다.

비용 절감부터 차별화된 속도와 안정적 운영까지
기업에 최적화된 IT 환경을 지원합니다

비용 절감부터 차별화된 속도와
안정적 운영까지 기업에 최적화된 IT 환경을 지원합니다

비용 절감부터
차별화된 속도와 안정적 운영까지
기업에 최적화된 IT 환경을 지원합니다

(주)스피디

경기도 성남시 수정구 위례서일로 18, 1101호 (위례 더존메디컬타워)

TEL 031-697-8413

FAX 02-6455-4743

E.mail sales@speedykorea.com

© SPEEDY. All rights reserved

(주)스피디

경기도 성남시 수정구 위례서일로 18, 1101호
(위례 더존메디컬타워)


TEL 031-697-8413

FAX 02-6455-4743

E.mail sales@speedykorea.com

© SPEEDY. All rights reserved

(주)스피디

경기도 성남시 수정구 위례서일로 18, 1101호
(위례 더존메디컬타워)


TEL 031-697-8413

FAX 02-6455-4743

E.mail sales@speedykorea.com

© SPEEDY. All rights reserved