C.W.K.
Stream
Lesson 03 of 05 · published

CDN 층 — 브라우저, edge, origin (그리고 네 header 어디 가나)

~10 min · caching-perf, cdn, edge, origin

Level 0HTTP Newbie
0 XP0/46 lessons0/12 achievements
0/120 XP to next level120 XP to go0% complete
"모든 cached response 가 layered cake 에 살아 — 브라우저, CDN edge, 가능하면 shield, 그 다음 origin. Cache-Control header 가 다 운전하는데, 각 층을 다르게 운전. Header 가 어느 층 target 인지 아는 게 '어디서나 빠른 캐시' 와 '잘못된 곳 캐시' 차이."

위에서 아래로 cake

전형적 2026년 web request 가 거쳐:

  1. 브라우저 cache — user 당, 로컬 디스크 + 메모리. Hit 비율: 가장 높음 (같은 user 가 같은 페이지 돌아옴). Bandwidth 절약: 완전 회피.
  2. CDN edge node — Cloudflare PoP, AWS CloudFront edge, Fastly POP. Region 당; 그 region user 간 공유. Hit 비율: 인기 content 에 매우 높음. Bandwidth 절약: 절대 origin 도달 안 함.
  3. CDN shield / midtier (optional) — origin 치기 전 cross-region miss 흡수하는 더 작은 중앙 cache. Cloudflare 의 Tiered Cache, Fastly 의 Origin Shielding. Hit 비율: 꼬리 잡음.
  4. Origin / 앱 server — 실제 FastAPI/Node/Rails process. 항상 진실 원천, 가끔 microcache (Nginx, Varnish 앞에) 도.

각 층이 아래 층에 HTTP 말하는 cache. Response header 가 아래 층 도달; 그 층 header 가 다음 위 도달; 사이클 계속.

어느 header 가 어느 층 target

  • Cache-Control: max-age=N — 모든 cache (브라우저 + CDN + 사이 모든 거) 에 적용.
  • Cache-Control: s-maxage=N — SHARED cache (CDN + proxy) 만. 브라우저 무시; 자기 위해 max-age 씀.
  • private — 브라우저만 캐시 가능. CDN 저장 안 함. User 당 데이터에.
  • public — 어느 cache 든 저장 가능. 인증 안 된 response 기본.
  • no-store — 어디서도 절대 캐시 안 함. 브라우저 도 CDN 도. Token, payment form 에.
  • CDN-specific headerCDN-Cache-Control, Cloudflare-CDN-Cache-Control, Surrogate-Control. CDN 만 위해 Cache-Control override, 브라우저 vs CDN 다른 정책 유지 가능.

강력 패턴: 짧은 브라우저, 긴 CDN

모든 user 한테 같은 자주 변하는 content (뉴스 피드, 제품 카탈로그):

Cache-Control: public, max-age=10, s-maxage=600

브라우저 10초 캐시 — user 가 빨리 update 보게 충분히 신선. CDN 10분 캐시 — origin 이 그 edge 칠 user 수와 무관 10분 마다 CDN edge 당 request 하나 봄. 수학: 100,000 페이지 뷰 → 50 origin request (10분 윈도우 마다 edge 당 하나). Origin 이 어느 트래픽 spike 든 살아남음.

Cache-Control 이 cache chain 에 broadcast 하는 정책. 각 cache 가 해석; 한 cache 한테 말 아니라 모두한테 말. Header 변경이 모든 층 — 브라우저, edge, shield, origin proxy — 에 효과. 그게 힘이자 책임.

Cache key — 뭐가 두 request 를 '같음' 만드나

Cache 가 URL + Vary 에 나열된 request header 로 response key. 같은 URL 인데 다른 Authorization header 가진 두 request 가 Vary: Authorization 보냈으면 다른 cache 항목. Vary 없으면 cache 가 둘을 같이 다룸, 그게 의미:

  • User A 의 response 가 user B 한테 서빙 (cross-user 누설).
  • Gzip-only client 가 decode 못 하는 brotli-encoded body 받음 (Vary: Accept-Encoding 누락).
  • JSON-요청자가 HTML response 받음 (Vary: Accept 누락).

Cache key 가 조용 — cache 가 잘못된 항목 서빙했다고 안 알려줌; 그냥 해. Vary 가 유일 fix.

Purging — Cache 가 잘못된 거 가졌을 때

Content 조각 update; CDN 이 여전히 TTL 동안 옛 버전 서빙. 신선도 강제 두 방식:

  • URL 로 purge — specific URL 의 cached 항목 evict 하라고 CDN 한테 명시 말. Cloudflare API, Fastly API. 정확히 뭐 변했는지 알 때 써.
  • Cache tagging — response 에 tag 첨부 (Surrogate-Key: article-42 author-pippa); tag 로 purge. 모든 URL 나열 없이 "author Pippa 관련 모든 거" 무효화 가능. Fastly, Cloudflare Enterprise.

Purging 이 비싸고 느림; purge 가 드물도록 짧은 TTL + stale-while-revalidate 설계.

cwkPippa 의 CDN 현실

cwkPippa 가 CDN 없음 — WebUI 가 localhost 나 Tailscale 에서 돌아. cwk-site (공개 sibling repo) 가 Vercel 의 edge 네트워크에: Next.js static 페이지가 stale-while-revalidate 가진 적극 edge 캐시 받고, API route 가 대부분 동적, auth-민감 endpoint 에 no-store. Vary header 가 거기 핵심 — 같은 URL 이 Accept-Language 기반으로 한국어와 영어 content 서빙; Vary 없으면 한 언어가 다른 거 서빙. 초기 한 번 봤음; Vary: Accept-Language 추가가 영구 fix.

Code

짧은 브라우저 + 긴 CDN TTL 패턴·http
# 짧은 브라우저 TTL + 긴 CDN TTL — canonical 인기-content 패턴
GET /api/news HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=10, s-maxage=600
Vary: Accept-Encoding
ETag: "v17-abc"

# 번역:
# - 브라우저: 10s 후 refetch (혹은 304)
# - CDN edge: 600s 후 refetch (혹은 304)
# - 10분 100k 페이지 뷰면, origin 이 ~50 request 봄 (윈도우 당 edge 당 1)
CDN-Cache-Control + Surrogate-Key — 세밀 CDN 정책·http
# CDN-specific override — CDN vs 브라우저 다른 정책
GET /api/article/42 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=60
CDN-Cache-Control: public, max-age=86400, stale-while-revalidate=604800
Surrogate-Key: article-42 author-pippa
Vary: Accept-Encoding, Accept-Language
ETag: "v17-abc"

# 브라우저가 Cache-Control: 60s 신선도.
# CDN 이 CDN-Cache-Control: 1일 신선도 + 1주 stale-while-revalidate.
# Surrogate-Key 가 tag 로 purge 가능: 'author-pippa tag 된 모든 거 evict'.
Purging — URL 기반과 tag 기반·bash
# CDN cache purge (Cloudflare 예)
curl -X POST 'https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache' \
  -H 'Authorization: Bearer CF_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"files":["https://example.com/api/article/42"]}'

# Tag 기반 purge (CDN 이 지원하면; Fastly 가 함)
curl -X POST 'https://api.fastly.com/service/SERVICE_ID/purge' \
  -H 'Fastly-Key: TOKEN' \
  -H 'Surrogate-Key: author-pippa'
# 전체 CDN footprint 에서 author-pippa tag 된 모든 cached 항목 evict.

External links

Exercise

CDN-fronted endpoint (Vercel, Cloudflare, 어느 거든) 있으면 curl -i 로 실제 response 검사하고 세 가지 식별: (1) CDN 이 존중하는 Cache-Control 지시, (2) CDN-specific cache header (cf-cache-status, x-vercel-cache, age), (3) Vary header. 그 다음 origin 의 Cache-Control header 변경, 재배포, CDN 이 새 정책 서빙하는 데 얼마 걸리는지 봐. 보너스: Accept-Language 의존하는 response 에 일부러 Vary 빼고 다른 Accept-Language 가진 후속 request 한테 CDN 이 잘못된 언어 서빙 검증.
Hint
Cloudflare 가 cf-cache-status: HIT / MISS / EXPIRED 추가. Vercel 이 x-vercel-cache: HIT / MISS / STALE / REVALIDATED 추가. age header 가 cached 항목이 edge 에 얼마나 있었는지 알려줘. Vary 보너스가 canonical 'production CDN cross-user 누설' 데모 — Vary: Accept-Language 없으면 cache 가 두 언어를 같은 항목으로 다루고, 첫 저장된 거가 둘 다에 이김.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.