새 버전을 배포했는데 사용자 화면은 옛날 그대로일 때, 십중팔구 CDN 캐시가 옛 파일을 붙잡고 있는 것입니다. CDN(Content Delivery Network)은 전 세계 엣지 서버에 콘텐츠 사본을 두어 사용자와 가까운 곳에서 응답하게 합니다. 빠른 대신, "언제까지 옛것을 쥐고 있을지"를 제대로 설정하지 않으면 갱신이 안 보이는 문제가 생깁니다.
캐시는 어디서, 얼마나
요청은 보통 이 흐름을 탑니다.
TEXT
브라우저 캐시 → CDN 엣지 캐시 → 오리진(원본 서버)
각 단계가 콘텐츠를 얼마나 보관할지는 응답 헤더가 정합니다.
| 헤더 / 값 | 의미 |
|---|---|
Cache-Control: max-age=3600 | 브라우저가 3600초간 캐시 |
Cache-Control: s-maxage=86400 | CDN(공유 캐시)이 86400초간 캐시 |
Cache-Control: no-store | 어디에도 캐시하지 않음 |
Cache-Control: no-cache | 캐시하되 매번 오리진에 재검증 |
max-age가 클수록 빠르지만 갱신은 늦게 보입니다. s-maxage로 CDN의 보관 시간을 브라우저와 따로 길게 잡는 패턴이 흔합니다.
콘텐츠별 캐시 전략
- 해시 파일명 정적 자산은 길게 —
app.a1b2c3.js처럼 내용이 바뀌면 파일명이 바뀌는 자산은max-age=31536000(1년)으로 길게 잡아도 안전합니다. 새 배포는 새 파일명이라 캐시 충돌이 없습니다. - HTML은 짧게 또는 재검증 — 진입점 HTML은 항상 최신이어야 하므로
no-cache로 매번 재검증하거나 짧은 TTL을 줍니다. - API 응답은 신중하게 — 사용자별로 다른 응답은
private또는no-store로 공유 캐시를 막습니다. 공통 데이터만 짧게 캐시합니다.
무효화(invalidation)는 최후의 수단
급하게 옛 캐시를 지워야 하면 CDN 무효화를 겁니다.
로컬 터미널
aws cloudfront create-invalidation \
--distribution-id E123ABC \
--paths "/index.html" "/css/*"
다만 무효화는 느리고(전 엣지 전파에 시간 소요), 양이 많으면 비용도 듭니다. 그래서 무효화에 의존하기보다 파일명 버저닝으로 애초에 무효화가 필요 없게 만드는 것이 정석입니다. HTML만 짧은 TTL로 두고 정적 자산은 해시 파일명을 쓰면, 배포 때 무효화할 대상이 거의 사라집니다.
요점 정리
- 캐시는 브라우저 → CDN 엣지 → 오리진 순으로 일어나고
Cache-Control로 제어한다. s-maxage로 CDN 보관 시간을 브라우저와 분리해 잡을 수 있다.- 해시 파일명 자산은 길게, HTML은 짧게/재검증, 개인화 응답은 캐시 금지.
- 무효화는 최후 수단 — 파일명 버저닝으로 무효화 자체를 줄이는 것이 정석.
CDN을 직접 붙여 캐시 헤더와 무효화 동작을 확인하는 실습은 클라우드 트랙에서 회원가입 없이 무료로 할 수 있습니다.