본문 바로가기
AWS

CloudFront 캐시 무효화 비용 — 파일 수가 아니라 경로 수로 센다

by 꼼냥냥 2026. 9. 18.
728x90

CloudFront 캐시 무효화 요금은 지운 파일 수가 아니라 요청한 경로 수로 매긴다. /* 하나로 수천 개를 지워도 1건이고, 파일 100개를 하나씩 적으면 100건이다. 매달 무료 1,000건이 있는데, 이건 배포(distribution)마다가 아니라 계정 전체 합산이다. 배포가 여럿이면 생각보다 빨리 넘는다. 그리고 경로 대신 태그로 무효화하는 기능이 생겼다. 태그 하나도 경로 1건으로 센다.

과금 단위는 "경로"다

AWS 문서가 과금 규칙을 이렇게 정리한다.

  • 한 달에 처음 1,000개 경로는 무료이고, 넘는 경로마다 요금이 붙는다
  • 경로는 파일 하나(/images/logo.jpg)일 수도, 여러 파일(/images/*)일 수도 있다
  • *가 들어간 경로는 수천 개를 지워도 1건이다
  • 요청 하나에 경로를 여러 개 묶어도 경로마다 따로 센다

즉 무효화 비용은 얼마나 많이 지웠느냐가 아니라 몇 줄로 적었느냐다. (문서)

S3에서는 파일 개수가 곧 요청 수였다. CloudFront 무효화는 반대다. 개수를 줄이려면 파일을 줄이는 게 아니라 적는 줄을 줄인다.

1,000건은 계정 전체 합산이다

이게 가장 흔한 착각이다. 무료 한도는 한 계정에서 만든 모든 배포의 합계다.

문서의 예로, 배포 3개에 각각 600건씩 보내면 합계 1,800건이다. 배포마다 1,000건 안이라 무료일 것 같지만, 800건이 과금된다.

환경별로 배포를 나눈 경우가 특히 그렇다. 개발·스테이징·운영에 각각 배포가 있고 CI가 배포할 때마다 무효화를 보내면, 세 환경의 호출이 전부 같은 1,000건을 나눠 쓴다.

배포 스크립트가 파일을 하나씩 적는 패턴

요금이 새는 전형은 이렇다. 바뀐 파일 목록을 뽑아 그대로 무효화에 넣는다.

# 바뀐 파일 수만큼 경로가 된다
aws cloudfront create-invalidation \
  --distribution-id "$DISTRIBUTION_ID" \
  --paths /js/app.1.js /js/app.2.js /css/main.css /index.html

경로 4건이다. 번들 파일이 수십 개면 배포 한 번에 수십 건이 나간다. 하루 몇 번 배포하면 한 달에 1,000건은 금방이다.

같은 효과를 와일드카드로 내면 이렇다.

# 디렉터리 단위로 묶으면 경로 수가 준다
aws cloudfront create-invalidation \
  --distribution-id "$DISTRIBUTION_ID" \
  --paths "/js/*" "/css/*" "/index.html"

경로 3건이다. /* 하나로 끝내면 1건이다.

대신 /*는 캐시를 통째로 비운다. 바뀌지 않은 이미지까지 다음 요청에서 원본을 다시 읽는다. 원본 트래픽이 한꺼번에 몰릴 수 있으니 요금만 보고 고르지 않는다.

태그로 무효화하기

URL 구조와 무관하게 의미 단위로 지우는 방법이다. 경로 무효화와 같은 1,000건 한도를 쓰고, 태그 하나가 경로 1건이다.

동작 순서

  1. 배포 설정에 CacheTagConfig를 넣고, 원본이 태그를 실어 보낼 응답 헤더 이름을 지정한다
  2. 원본이 그 헤더에 쉼표로 구분한 태그를 실어 응답한다
  3. 무효화할 때 경로 자리에 # 접두어를 붙인 태그를 넣는다

원본 응답은 이런 모양이다.

HTTP/1.1 200 OK
Content-Type: text/html
x-amz-meta-cache-tag: product:electronics, category:tv
Cache-Control: max-age=3600

원본이 S3면 객체 메타데이터로 태그를 붙인다. S3는 메타데이터를 x-amz-meta-<키> 헤더로 돌려주므로, 키를 cache-tag로 두면 x-amz-meta-cache-tag 헤더가 된다. 배포의 헤더 이름을 그걸로 맞추면 된다.

무효화는 이렇게 한다.

aws cloudfront create-invalidation \
  --distribution-id "$DISTRIBUTION_ID" \
  --paths "#product:electronics"

그 태그가 붙은 캐시 객체가 URL과 무관하게 전부 지워진다. 여러 태그를 나열하면 OR 조건이고, 경로와 태그를 한 요청에 섞을 수도 있다.

태그 규칙

항목 제한
문자 ASCII 보이는 문자(33~126). 공백·쉼표·제어문자 불가
대소문자 구분 안 함
길이 태그 하나당 최대 256자
개수 객체 하나당 최대 50개 — 넘는 태그는 조용히 버려진다

50개 제한은 에러가 안 난다. 51번째 태그로 무효화하면 아무 일도 안 일어난다.

헤더 이름을 바꾸면 기존 태그가 끊긴다

태그 무효화는 현재 CacheTagConfig의 헤더 이름으로만 찾는다. 헤더 이름을 바꾸면, 옛 이름으로 캐시된 객체에는 태그 무효화가 더 이상 먹지 않는다. 낡은 콘텐츠가 계속 나간다.

문서가 권하는 순서는 이렇다. 원본이 옛 헤더와 새 헤더를 둘 다 보내게 하고, 경로 무효화(/* 등)로 기존 캐시를 비운 다음 헤더 이름을 바꾼다. 그 뒤에 옛 헤더를 뗀다.

CacheTagConfig를 아예 지우면 태그 추출이 멈추고, 이미 캐시된 객체는 만료되거나 경로로 무효화될 때까지 그대로 나간다.

무효화 자체를 줄이는 쪽

요금을 줄이는 가장 확실한 방법은 무효화를 안 하는 것이다.

바뀌는 파일은 이름에 버전이나 해시를 넣는다. app.3f9a2c.js처럼 내용이 바뀌면 이름이 바뀌므로 새 URL이 되고, 무효화할 필요가 없다. 번들러 대부분이 기본으로 이렇게 한다.

그러면 무효화가 필요한 건 이름을 못 바꾸는 진입점(index.html 같은)뿐이다. 배포 한 번에 1~2건으로 끝난다.

FAQ

무효화 요청은 바로 반영되나요

요청 후 처리가 끝나야 반영된다. get-invalidation으로 상태를 확인할 수 있다. 태그 무효화도 같은 방법으로 확인한다.

태그 무효화를 쓰려면 배포를 새로 만들어야 하나요

아니다. 기존 배포에 CacheTagConfig를 추가하면 된다. 추가하기 전에 캐시된 객체에는 태그가 없으므로 태그 무효화가 먹지 않는다. 설정 직후 한 번은 경로로 비우는 게 안전하다.

와일드카드를 중간에 쓸 수 있나요

이 글에서 확인한 범위는 경로 끝의 *다. 경로 형식의 세부 규칙은 문서의 무효화 경로 절을 따로 확인하는 편이 정확하다.

확인한 것과 확인하지 못한 것

이 글의 규칙은 CloudFront 개발자 안내서에서 확인했다. 무료 1,000개 경로와 계정 합산, 와일드카드와 태그가 각각 1건인 것, 요청에 묶어도 경로별로 센다는 것, 태그 무효화의 설정 방법·형식 제한·헤더 이름 변경 시 주의점이 그렇다.

확인하지 못한 것은 1,000건을 넘었을 때의 경로당 단가다. 요금 페이지를 이 글에서 직접 읽지 못해 금액을 적지 않았다. 계산이 필요하면 CloudFront 요금 페이지에서 확인하는 게 정확하다.

단가를 몰라도 판단은 된다. 줄 수를 줄이면 요금이 줄고, 계정 전체 합산이라는 걸 알면 어디서 새는지 보인다.

댓글