포스트

프록시·리버스 프록시·CDN — 콘텐츠를 사용자 코앞으로 옮기는 기술

포워드 프록시와 리버스 프록시의 차이, HTTP 캐싱(Cache-Control·ETag), CDN 엣지 캐싱과 Anycast로 가장 가까운 PoP 라우팅, origin shielding과 캐시 무효화(CloudFront)를 설명합니다.

프록시·리버스 프록시·CDN — 콘텐츠를 사용자 코앞으로 옮기는 기술

“서버는 서울에 한 대인데, 사용자는 상파울루에 있다”

첫 글에서 봤듯 전파 지연은 거리에 비례합니다 — 서울↔상파울루는 광속 한계상 편도만 ~90 ms. 회선을 아무리 넓혀도 줄지 않습니다. 답은 하나뿐입니다. 콘텐츠를 사용자 가까이로 옮긴다. 그게 CDN이고, 그 앞에 깔리는 일반 기술이 프록시입니다.

프록시는 방향에 따라 완전히 다른 일을 합니다. 그리고 CDN은 “전 세계에 깔린 거대한 리버스 프록시 + 캐시”입니다. 이 글은 포워드 vs 리버스 프록시의 본질, 캐시가 신선도를 지키는 규칙, 그리고 Anycast로 가장 가까운 엣지를 찾는 마법까지 내려갑니다. AWS CloudFront가 정확히 이 위에 있습니다.

포워드 vs 리버스: 누구를 대리하나

flowchart LR
    subgraph fwd["포워드 프록시 — 클라이언트 측 대리"]
      C1[사내 PC들] --> FP[포워드 프록시] --> I1[인터넷]
    end
    subgraph rev["리버스 프록시 — 서버 측 대리"]
      I2[인터넷 사용자] --> RP[리버스 프록시] --> B[백엔드 서버들]
    end
 포워드 프록시리버스 프록시
대리 대상클라이언트서버
누가 존재를 아나클라가 의식하고 설정클라는 모름(서버인 줄)
용도사내 아웃바운드 통제·캐시·익명화TLS 종료·캐시·LB·WAF·압축
대표기업 프록시, VPN 게이트웨이Nginx, Envoy, CDN, ALB

아래는 리버스 프록시가 인터넷을 향한 단일 진입점이 되어, TLS를 종료하고 경로별로 여러 백엔드 앞에 서는 모습입니다. 백엔드는 바깥에 직접 노출되지 않습니다.

사용자 리버스 프록시 TLS 종료·라우팅 /api /app /static

캐시: 무엇을, 얼마나 오래, 어떻게 검증하나

CDN의 힘은 캐시에서 나옵니다. HTTP 캐시는 세 가지 질문에 답합니다.

헤더역할
Cache-Control: max-age=3600, public얼마나 신선한가(초). public이면 공유 캐시(CDN) 저장 가능
ETag: "v3-abc" / If-None-Match바뀌었나 — 같으면 304 Not Modified(본문 0바이트)
Last-Modified / If-Modified-Since시간 기반 검증(ETag 보조)
stale-while-revalidate=60만료돼도 일단 옛 것 주고 뒤에서 갱신(체감 0 지연)
s-maxage공유 캐시(CDN) 전용 수명(브라우저와 분리)

신선도와 정확성의 줄타기. max-age가 길면 빠르지만 갱신이 늦고, 짧으면 신선하지만 origin 부하가 큽니다. 정답은 콘텐츠별 분리입니다 — 해시가 박힌 정적 자원(app.3f9c.js)은 max-age=31536000, immutable(1년, 영구), HTML은 짧게+검증(no-cache = 매번 ETag 검증). 파일명에 해시를 박으면 “영구 캐시 + 배포 시 새 URL”로 무효화 문제 자체가 사라집니다.

Anycast: 같은 IP, 가장 가까운 곳으로

CDN의 진짜 마법은 Anycast입니다. 전 세계 수백 PoP(엣지)가 같은 IP를 BGP로 광고하면, 라우팅이 각 사용자를 네트워크상 가장 가까운 PoP로 자동으로 보냅니다. 사용자는 한 IP에 접속할 뿐인데, 도쿄 사용자는 도쿄 엣지에, 상파울루 사용자는 상파울루 엣지에 닿습니다.

아래는 사용자가 가까운 엣지에 닿아 캐시 히트면 즉시 응답, 미스면 origin까지 갔다 와 채우는 흐름입니다. 첫 사용자(미스)는 멀리 가지만, 이후 사용자(히트)는 코앞에서 받습니다.

사용자① 미스 사용자② 히트 가까운 엣지(PoP) Anycast로 도달 Origin 서울(멀다)

추가 최적화 — origin shielding: 모든 엣지가 미스 때 origin을 직접 때리면 origin이 폭격당합니다(특히 새 콘텐츠·캐시 만료 동시 발생 = cache stampede). 그래서 엣지들 사이에 상위 캐시 계층(shield PoP) 을 둬 origin으로 가는 요청을 한 곳으로 모읍니다.

디버깅: 캐시가 정말 맞았나

1
2
3
4
5
6
7
8
9
# 응답 헤더로 캐시 적중·수명 확인
curl -sI https://cdn.example.com/app.3f9c.js
#  HTTP/2 200
#  cache-control: public, max-age=31536000, immutable
#  x-cache: Hit from cloudfront        ← Hit / Miss / RefreshHit
#  age: 842                            ← 캐시에 머문 초

# 어느 엣지로 갔는지(Anycast 도달 지점) — DNS/지연으로 추정
dig +short example.com

프로덕션 함정 모음. ① 쿠키가 캐시를 무력화: 응답에 Set-Cookie가 붙거나 캐시 키에 쿠키가 포함되면 적중률이 0에 수렴 → 정적 경로는 쿠키 제거. ② 캐시 키 누락: Vary: Accept-Encoding을 안 주면 gzip/br이 섞여 깨진 응답이 캐시됨. ③ 무효화 지연: 퍼지(invalidation)는 전 세계 PoP 전파에 시간이 걸림 → 급한 갱신은 퍼지보다 버전 URL이 확실.

AWS로 매핑 / 시리즈 연결

  • CloudFront = 글로벌 엣지(PoP) + 캐시 + Anycast. origin은 S3·ALB·임의 HTTP.
  • 동작 단위 = behavior(경로 패턴별 캐시 정책·TTL·쿠키/헤더 전달 규칙).
  • 엣지에서 코드 실행 = CloudFront Functions / Lambda@Edge(요청 가까이서 변형).

가장 가까운 엣지를 IP로 안내하는 DNS, 같은 IP를 여러 곳이 광고하는 토대인 라우팅/BGP, 엣지가 종료하는 TLS, origin 앞단의 로드 밸런싱과 한 묶음입니다.

면접/리뷰 단골 질문

  • Q. 포워드와 리버스 프록시 차이? → 포워드는 클라이언트를 대리(사내 아웃바운드), 리버스는 서버를 대리(TLS 종료·캐시·LB). 클라는 리버스 프록시를 서버로 안다.
  • Q. CDN이 어떻게 사용자를 가장 가까운 엣지로 보내나? → Anycast — 여러 PoP가 같은 IP를 BGP로 광고하면 라우팅이 최단 경로 PoP로 보낸다(또는 DNS 기반 지리 라우팅 병행).
  • Q. 캐시 무효화를 안전하게? → 정적 자원은 파일명에 해시(영구 캐시 + 새 URL), 급할 땐 퍼지보다 버전 URL. HTML은 no-cache로 매번 ETag 검증.
  • Q. CDN 적중률이 낮다, 원인은? → 쿠키/Set-Cookie, 캐시 키 과다(쿼리스트링·헤더), Vary 오설정. 헤더로 x-cache·age 확인.

정리

  • 포워드(클라 대리) vs 리버스(서버 대리) — CDN은 전 세계에 펼친 거대 리버스 프록시 + 캐시.
  • 캐시는 Cache-Control(수명) + ETag(검증) + stale-while-revalidate로 신선도와 속도를 줄타기. 정적은 해시 파일명 + immutable.
  • Anycast가 같은 IP로 사용자를 가장 가까운 PoP에 자동 연결 — 거리=지연 문제의 정공법.
  • 함정은 대부분 캐시 키(쿠키·Vary)와 무효화 전파 지연. 헤더(x-cache·age)로 검증하라.

다음 글: 엣지·LB·서버를 드나드는 트래픽을 규칙으로 거르는 방화벽·보안그룹·네트워크 ACL로 이어집니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

시리즈 · 네트워크 A-Z (20편)

  1. 네트워크란 무엇인가 — 회선 교환 vs 패킷 교환, 왜 인터넷은 패킷을 선택했나
  2. OSI 7계층과 TCP/IP — 왜 네트워크를 굳이 층으로 쪼갰나
  3. 이더넷·MAC·스위치 — 스위치는 어떻게 "어느 포트로 보낼지" 스스로 배우나
  4. IP 주소와 서브넷팅 — /24를 /26으로 쪼갠다는 게 비트 단위로 무슨 뜻인가
  5. 라우팅은 어떻게 길을 찾나 — 라우팅 테이블, Longest Prefix Match, 그리고 BGP
  6. ARP와 L2/L3 경계 — IP는 아는데 왜 MAC을 또 묻나
  7. TCP는 어떻게 신뢰를 만드나 — 3-way handshake, 상태 머신, 그리고 TIME_WAIT
  8. TCP는 얼마나 빨리 보낼까 — 흐름 제어 vs 혼잡 제어, 그리고 톱니파의 비밀
  9. UDP와 QUIC — TCP를 버려야 더 빨라지는 순간
  10. DNS는 어떻게 이름을 주소로 바꾸나 — 루트부터 권한 서버까지, 그리고 캐시의 마법
  11. HTTP의 진화 — 1.1의 줄 서기에서 HTTP/2 멀티플렉싱, HTTP/3까지
  12. TLS/HTTPS는 어떻게 도청 불가능한 채널을 만드나 — 핸드셰이크부터 인증서 체인까지
  13. NAT와 사설망 — 주소 하나로 수백 대가 인터넷을 쓰는 법, 그리고 P2P가 막히는 이유
  14. 로드 밸런싱 — L4와 L7은 무엇이 다르며, 왜 헬스체크가 서비스를 살리고 죽이나
  15. 프록시·리버스 프록시·CDN — 콘텐츠를 사용자 코앞으로 옮기는 기술 지금 보는 글
  16. 방화벽·보안그룹·네트워크 ACL — stateful과 stateless가 가르는 모든 것
  17. VPC & 클라우드 네트워킹 — 라우팅 테이블 한 줄이 퍼블릭과 프라이빗을 가른다
  18. 소켓과 커널 네트워크 스택 — accept 한 줄 뒤에서 벌어지는 일
  19. 네트워크 성능 — 대역폭은 왜 빠름이 아닌가 (RTT·BDP·처리량의 진실)
  20. 현대 네트워킹 — 사이드카, eBPF, 그리고 경계가 사라진 신뢰