서울 사용자는 빠른데 미국·유럽 사용자는 페이지가 3초씩 걸린다고 합니다. 이미지가 전부 서울 원본 서버에서 지구를 돌아가는 탓입니다. 게다가 어느 날 새벽, HTTPS 인증서가 만료돼 전 사용자가 '안전하지 않음' 경고를 봤습니다. 빠르게, 그리고 안전하게 전 세계로 보내는 일은 DNS·CDN·인증서가 함께 풉니다.
- 1관리형 DNS가 단순 주소 변환을 넘어 트래픽을 제어하는 방법을 안다
- 2CDN이 엣지 캐싱으로 지연·부하를 줄이는 원리를 설명할 수 있다
- 3캐시 TTL·캐시 키·무효화가 왜 중요한지 이해한다
- 4TLS 인증서를 관리형으로 자동 갱신하는 이점을 안다
- 5DNS→CDN→LB→원본으로 이어지는 요청 경로를 그릴 수 있다
이름으로 안내하고, 가까운 곳에서 답한다
관리형 DNS — 주소록을 넘어선 트래픽 제어
DNS는 기본적으로 example.com → IP를 알려줍니다. 관리형 DNS(Route 53 등)는 여기에 트래픽 제어를 더합니다.
- failover: 헬스체크로 주(primary)가 죽으면 예비(secondary)로 자동 전환
- 지연/지리 기반: 사용자와 가까운 리전·엣지로 보냄
- 가중치: 10%만 새 버전으로 보내는 점진 배포(릴리스 전략)
같은 도메인이라도 누가·어디서 묻느냐에 따라 다른 답을 줄 수 있습니다.
CDN — 콘텐츠를 사용자 옆으로 옮긴다
CDN은 이미지·JS·CSS·동영상 같은 정적 콘텐츠를 전 세계 엣지 로케이션에 캐싱합니다. 사용자는 먼 원본(origin) 대신 가까운 엣지에서 받아 지연이 줄고, 원본 서버는 같은 파일을 매번 안 보내도 되니 부하·전송비가 줍니다.
핵심 개념 두 가지: TTL(엣지가 콘텐츠를 보관하는 시간)과 캐시 키(무엇을 기준으로 같은 콘텐츠로 볼지). 이 둘을 모르면 캐시가 너무 오래 남거나(옛 버전 노출) 너무 안 먹습니다(원본 부하 그대로).
확대
확대
위 그림처럼 레코드 타입마다 역할이 다릅니다. CNAME은 루트 도메인에 불가하므로 LB 연결 시 ALIAS를 사용해야 합니다.
확대
위 그림처럼 캐시 Hit이면 엣지에서 즉시 응답하고, Miss면 원본까지 거쳐 가져옵니다. 콘텐츠 변경 시 무효화(Invalidation)를 배포에 포함시키는 것이 실무 패턴입니다.
요청이 엣지에서 끝나는 다섯 단계
사용자가 가까운 서버에서 콘텐츠를 받는 법 — CDN 엣지 요청 흐름
"CDN을 붙였더니 빨라졌다"는 결과만 알고 그 사이 무슨 일이 도는지 모르면, 원본 부하가 안 줄거나 옛 파일이 계속 나갈 때 어디를 봐야 할지 막막합니다. CDN에서 요청 하나는 DNS로 엣지 찾기 → 가까운 PoP 배정 → 엣지 캐시 조회(HIT/MISS) → MISS면 오리진 페치 → 응답을 TTL 따라 저장의 다섯 단계로 흐르고, 이후 같은 지역 요청은 첫 단계 캐시 조회에서 끝납니다. 이 흐름을 알면 지연이 왜 줄고, 언제 안 주는지가 단계로 보입니다.
[브라우저] app.example.com/img/logo.png 요청
│
① 도메인 DNS 조회 → CDN 엣지 주소 응답 (Route 53 등 관리형 DNS)
│
② Anycast가 지리적으로 가까운 엣지 PoP로 안내
│ → 같은 엣지 주소라도 라우팅이 사용자와 가장 가까운 PoP로 보냄
│
③ 엣지에서 캐시 키로 조회 (호스트+경로+지정한 쿼리·헤더)
│ ├─ HIT → 즉시 반환, 원본 안 감 x-cache: Hit
│ └─ MISS → ④로
│
④ MISS면 오리진(또는 오리진 실드)으로 요청 (LB → 원본 서버)
│
⑤ 오리진 응답을 Cache-Control/TTL 따라 엣지에 저장
│ → max-age 동안 이 PoP는 같은 요청을 캐시에서 처리
▼
[이후] 같은 지역의 다음 요청은 ③에서 HIT로 끝남 (원본 부하·지연↓)
각 단계가 하는 일과, 어긋나면 나타나는 증상:
| 단계 | 하는 일 | 여기서 어긋나면 |
|---|---|---|
| ① DNS 조회 | 도메인을 CDN 엣지 주소로 해석 | DNS 전파 지연(TTL)으로 옛 엣지·옛 오리진으로 감 — 변경이 즉시 반영 안 됨 |
| ② 엣지 선택 | Anycast로 사용자와 가까운 PoP 배정 | 사용자가 먼 PoP에 붙으면(라우팅 이상) 지연이 기대만큼 안 줆 |
| ③ 캐시 조회 | 캐시 키로 HIT/MISS 판정 | 캐시 키에 쿼리스트링·쿠키가 과하게 들어가면 키가 잘게 쪼개져 HIT율↓·MISS 폭증 |
| ④ 오리진 페치 | MISS를 LB·원본에서 가져옴 | 오리진 실드 없이 전 엣지 MISS가 몰리면 원본 과부하(cache stampede) |
| ⑤ 저장 | Cache-Control·TTL 따라 엣지에 보관 | TTL이 너무 짧으면 곧 다시 MISS(오프로드↓), 너무 길면 옛 버전이 오래 노출 |
지연 감소는 거리(②)와 캐시(③) 두 축이 함께 작동한 결과이고, HIT/MISS 비율이 곧 오프로드율(원본을 얼마나 지켰나)입니다. 진단은 응답 헤더로 좁힙니다 — x-cache(HIT/MISS)로 엣지가 처리했는지, age로 캐시에 얼마나 오래 있었는지, 어느 엣지(PoP)에서 왔는지를 보고, 무효화(purge)와 stale 정책으로 갱신·완충을 조절합니다. x-cache가 MISS만 반복되면 캐시 키·TTL을, HIT인데 옛 버전이 나가면 무효화·파일명 버전을 봅니다.
TLS 인증서 — 관리형으로 자동 갱신
HTTPS를 위한 TLS 인증서를 수동 관리하면 '갱신을 잊어 만료→전체 다운' 사고가 납니다. 관리형 인증서 서비스(예: ACM)는 검증 방식과 연결된 서비스가 자동 갱신 조건을 충족할 때 무료 발급·자동 갱신되며, 로드밸런서나 CDN에 붙여 HTTPS를 종단합니다. DNS/이메일 검증 상태와 갱신 이벤트를 모니터링해야 하며, 운영에서 인증서는 "붙이고 검증·알림까지 자동화"하는 것이 정답입니다.
어떤 레코드가 어디를 가리키는지, 라우팅 정책이 걸렸는지 확인합니다.
aws route53 list-resource-record-sets --hosted-zone-id "$ZONE_ID" \
--query "ResourceRecordSets[?Type=='A'].{Name:Name,Alias:AliasTarget.DNSName,Policy:Failover}" --output table
+------------------+-----------------------------+----------+
| app.example.com | d111.cloudfront.net | - |
| api.example.com | alb-123.elb.amazonaws.com | PRIMARY |
+------------------+-----------------------------+----------+
aws route53 list-resource-record-sets응답 헤더로 CDN 캐시 적중 여부를 봅니다(X-Cache: Hit from cloudfront 등). HTTPS·캐시 동작을 한 번에 점검합니다.
curl -sI https://app.example.com/static/main.abc123.js | grep -iE "x-cache|cache-control|server"
server: CloudFront
x-cache: Hit from cloudfront
cache-control: public, max-age=31536000, immutable
curl -I- x-cache가 'Miss'만 반복되면 — 캐시 키 설정 과다(쿼리·쿠키별 분리)나 짧은 TTL로 캐시가 안 먹는 것. 원본 부하·비용 그대로
- Cache-Control max-age 값 — 정적 자산인데 너무 짧으면 효과↓, 자주 바뀌는데 너무 길면 옛 버전 노출
- 파일명에 해시가 없는 정적 자산 + 긴 TTL — 배포해도 사용자에게 안 바뀜. 해시 파일명 또는 무효화 필요
- 인증서 만료일(NotAfter) — 자동 갱신 대상인지, 임박했는지. 수동 인증서면 만료 모니터링 필수
상황: 새 버전을 배포해도 CDN/브라우저가 옛 정적 파일을 계속 제공.
원인: 정적 파일 이름이 그대로(main.js)인데 긴 TTL로 엣지·브라우저에 캐시돼 있음. TTL이 끝나기 전엔 새 파일을 안 받아옴.
진단: curl -I로 x-cache와 cache-control max-age 확인 → 파일명이 빌드마다 바뀌는지 확인.
해결: 정적 자산은 내용 기반 해시 파일명(main.abc123.js)을 쓰면, 내용이 바뀔 때 파일명이 바뀌어 캐시가 자연히 갱신됩니다(HTML은 짧은 TTL). 급하면 CDN 무효화(invalidation) 를 호출. 무효화 남발은 비용·지연이 있으니 해시 파일명이 근본 해법입니다.
심화 — 캐시가 비는 순간, DNS가 늦는 순간
심화: 캐시가 한꺼번에 비는 순간 — 원본을 지키는 완충 장치
캐시 히트율이 높은 시스템일수록 역설적으로 위험한 순간이 있습니다. 캐시가 한꺼번에 비는 순간입니다. 전체 무효화 직후, 인기 객체의 TTL 동시 만료, 새 지역 오픈 직후처럼 미스가 몰리면, 평소 캐시가 흡수하던 트래픽이 원본으로 그대로 쏟아집니다(cache stampede). 평소 원본이 전체 트래픽의 5%만 받도록 용량을 잡아뒀다면 이 순간 20배 부하를 맞는 셈입니다.
완충 장치는 세 겹입니다:
- 오리진 실드(Origin Shield): 엣지와 원본 사이에 중간 캐시 계층을 하나 더 둬, 전 세계 엣지의 미스가 원본에 도달하기 전에 한 번 더 합쳐지고 흡수됩니다.
- 요청 병합(request collapsing): 같은 객체에 대한 동시 미스를 하나로 묶어 원본에는 한 번만 갑니다 — 인기 객체가 만료되는 순간의 폭주를 막습니다.
- stale-while-revalidate: TTL이 지나도 일단 옛 사본으로 응답하고 뒤에서 갱신합니다 — 미스 스파이크가 평탄해집니다.
그리고 무효화는 /* 전체가 아니라 배포 단위 경로로 좁힙니다. 해시 파일명 체계를 갖췄다면 무효화가 필요한 것은 사실상 HTML 몇 개뿐입니다.
상황: 인프라 이전으로 A 레코드를 새 대상으로 변경했습니다. 대부분은 새 쪽으로 왔지만 옛 서버 액세스 로그에 전체의 십수 %가 이틀째 남아 있었고, 옛 서버를 종료하자 그 사용자들에게 장애가 났습니다.
원인: 바꾸기 전 레코드의 TTL이 86400초(24시간)였습니다. TTL은 '전 세계 리졸버가 옛 답을 캐시해도 되는 시간'이므로, 변경 직전에 캐시한 리졸버는 하루 동안 옛 IP를 계속 답합니다. 일부 ISP 리졸버는 TTL을 임의로 늘려 잡아 그보다 더 오래 갑니다. DNS 변경은 '즉시 반영'이 아니라 TTL만큼 천천히 번지는 것입니다.
진단: dig app.example.com @8.8.8.8, @1.1.1.1처럼 여러 퍼블릭 리졸버에 조회해 응답 IP와 남은 TTL을 비교하고, 옛 서버 액세스 로그로 잔존 트래픽 비율이 줄어드는 추이를 봅니다.
해결: 옛 서버를 바로 내리지 말고 잔존 트래픽이 잦아들 때까지 병행 운영하거나, 옛 IP에서 새 쪽으로 프록시를 걸어 전환기를 버팁니다. 다음부터는 전환 며칠 전 TTL을 300초 이하로 미리 낮추고 → 변경 → 안정 확인 후 TTL 복원 순서를 지킵니다. 함정 하나 — TTL 낮추기 자체도 기존 TTL이 다 소진돼야 효력이 나므로, 최소한 기존 TTL 이상의 여유를 두고 시작해야 합니다.
"전 세계 사용자인데 특정 지역만 느려요"의 단골 해법이 CDN 도입과 지연 기반 라우팅입니다. 반대로 "CDN을 붙였는데 원본 부하가 안 줄어요"는 거의 항상 캐시 키·TTL 설정 문제 — 캐시 히트율(x-cache Hit 비율)을 지표로 보고 튜닝합니다.
인증서 만료로 인한 전사 장애는 의외로 흔합니다. 관리형 인증서 자동 갱신 + 만료 임박 알림(관측과 거버넌스)을 기본으로 둡니다. DNS는 변경이 전 세계에 퍼지는 데 시간(TTL)이 걸리므로, 마이그레이션 전 TTL을 미리 줄여두는 것도 실무 팁입니다.
관련 모듈로 더 깊이:
- VPC와 서브넷 — DNS·CDN이 앞에서 안내하는 VPC 네트워크 구조
- 오토스케일링 + 로드밸런서 — CDN 뒤에서 트래픽을 여러 인스턴스로 나누는 로드밸런싱
- 오브젝트·블록·파일 스토리지 — CDN이 캐싱해 전달하는 정적 콘텐츠가 사는 오브젝트 스토리지
다음 모듈에서는 컴퓨트·네트워크를 떠나 데이터가 사는 곳 — 오브젝트·블록·파일 스토리지의 종류와 선택 기준으로 들어갑니다.