AWS S3 + CloudFront 캐싱, TTL 설정 과정

희선·2025년 6월 20일
3

Portfolio

목록 보기
2/2
post-thumbnail

AWS S3 + CloudFront 배포 환경에서 캐싱을 적용하려 한다.
S3 버킷에 업로드된 mp4 파일의 메타데이터를 수정하려 했지만 CloudFront가 이미 해당 파일을 참조하고 있기 때문에 편집하려는 대상을 복제 해야한다

우선 처음에 정리가 잘 안되던 부분이 있었다
S3에도 Cache-Control을 명시하고 왜 또 CloudFront에도 Cache-Control을 명시하는걸까?
결론은 S3에 업로드 된 파일에도 cache-control을 적용할 수 있고 CloudFront에도 Cache-control을 적용 할 수 있다



S3 파일 Cache-Contrl 헤더

S3 파일의 Cache-Control 헤더 유무캐싱
Cache-Control 헤더 ❌CloudFront 캐싱 정책의 기본 TTL 값에 따라 캐싱
Cache-Control 헤더 ⭕️해당 헤더 값에 따라 캐싱 기간이 결정




S3 버킷의 캐싱 대상 복제

복제 할 대상의 복제 경로를 지정해주고, 추가 복사 설정 부분에서 설정을 직접 지정하도록 선택하여 메타데이터 cache-control을 세팅하면 된다

기존에 소스 설정 복사를 선택하니 같은 파일명 + 같은 소스설정으로 인해
복사된 파일이 기존 파일에 그냥 덮어씌워지는 이슈가 있었다
그래서 캐싱 대상을 복사하고 설정을 따로 지정해야한다


설정 지정을 통해 아래 Cache-Control 메타데이터를 추가한다

Cache-Control: public, max-age=31536000, immutable

public 접근을 허용하고 1년 캐시 코드를 넣어주었다
앞으로 변경될 가능성이 상당히 적은 파일이라 1년으로 적용했다


적용한 파일의 메타데이터를 확인하니 잘 적용된것을 볼 수 있었다.

기존 파일의 메타 데이터에는 content-Type이 지정되어 있었기 때문에
Cache-Control 설정에 추가로 Content-Type도 설정해 주었다!
캐싱 적용할 파일의 대상이 mp4 파일이기 때문에 Content-Typevideo/mp4로 설정
이렇게 되면 파일명은 동일하지만 메타데이터는 다르기 때문에 덮어씌워진다!


S3 정적 리소스의 Content-Type

S3에서 모든 정적 리소스의 Content-Type은 브라우저와 CloudFront, 캐싱에 모두 영향을 주므로 반드시 올바르게 지정해야한다!


왜 Content-Type을 지정해야 할까?

Content-Type을 통해 브라우저가 파일을 어떻게 처리할지 결정하기 때문이다

Content-Type처리방식
image/png이미지를 화면에 바로 렌더링
video/mp4<video> 태그 등으로 플레이어 호출
application/jsonJSON으로 파싱
text/css, application/javascript브라우저가 실행

만약, Content-Type이 없거나 잘못 지정된다면

다운로드되어버리거나 콘솔 경고 (MIME type mismatch)가 뜰 수 있다!
혹은 캐시/압축 최적화가 제대로 동작이 되지 않을 수도 있고 CORS 오류가 날 수 있다

CloudFront와 S3의 Content-Type의 연관성

CloudFrontS3Content-Type을 그대로 전달한다. 따라서 S3에서 지정하지 않으면 CloudFront도 잘못된 MIME을 그대로 전달하게 되는데
이로 인해 앞서 말한 문제점이 발생하게 되는것!
따라서 Content-Type은 올바르게 지정해야한다

CloudFront 캐시 정책 설정

그럼이제 CloudFront 캐시 정책 설정이 필요한데
CloudFront 탭에서 정책 페이지로 이동한다. 하단으로 쭉 내리면
사용자 정의 정책 란이 보이는데 여기서 캐시 정책 생성을 선택!


생성을 누르면 세부정보의 캐시 정책 이름을 작성해야하는 부분과 TTL 설정란이 보인다.
캐시 정책 이름은 아무래도 고유한 이름을 사용하는것이 좋기 때문에 정적 비디오 캐싱을 명시하고 캐싱 기간과 프로젝트 명을 명시해서 지어줬다

TTL은 총 3가지로 최소 TTL, 최대 TTL, 기본 TTL로 나누어져 있는데
각각의 역할이 다르다



✅ 최소 TTL (Minimum TTL)

최소한 이 시간만큼은 캐시된 데이터를 사용하겠다는 말!
그 시간 안에는 원본(S3 등)에 변경이 있어도 절대 다시 요청하지 않는다
ex) 60초 → 1분 동안은 무조건 캐시된 버전 사용

✅ 기본 TTL (Default TTL)

CloudFront가 원본 응답에 Cache-Control 헤더가 없을 때 사용할 기본 값
Cache-Control이 없다면 이 값만큼 캐싱
ex) 86400초 (1일)


✅ 최대 TTL (Maximum TTL)

최대 이 시간 이상은 절대 캐싱하지 않는다는 뜻으로
원본이 Cache-Control: max-age=31536000 (1년)으로 설정돼도 이 값을 초과할 수 없다
ex) 31536000초 → 1년 이상은 안 됨


S3의 Cache-Control 설정이 없으면 → 기본 TTL 사용
S3가 max-age=31536000이라도 → CloudFront의 최대 TTL 이하까지만 유효



CloudFront 캐시 정책 적용

정책의 응답 헤더를 추가해야하는데 정책의 응답 헤더 탭에서 정책 생성을 한다.
동일하게 고유의 이름을 생성하고


Cache-Control 추가! 추가하면서 ETag, last-modified까지 적용했다

모든 정책을 다 생성 했으면 CloudFront의 Edit behavior 탭으로 이동해서 캐시 정책과 응답 헤더 정책을 방금 생성한 정책을 적용시켜야 한다!


🧐 캐싱 결과 확인

이제 배포 개발자 도구에서 네트워크 탭의 response header를 확인해보자!


headerCache-Control이 잘 출력되고 있고, 함께 추가한 Etag, Last-Modified도 출력되는 중! 근데 여기서 드는 의문! 이제 정말 잘 캐싱되는것인가? 캐싱 되는지 여부를 내가 어떻게 파악 할 수 있는것인가?



확인하고 싶을때는 GeneralStatus Code를 확인하면 된다
캐싱 후 첫 호출때는 200ok 가 출력되었는데 다시 접근을 하면 304 Not Modified 로 출력된다.
이는 리소스 변경 없음, 캐시가 유효하다는 상태로 기존 캐시된 리소스 사용한다는것!

그리고 Response HeadersAge, X-Cache를 확인하면 되는데

Age는 캐시된 응답이 얼마나 오래되었는지 초단위로 보여주는데 이 숫자가 0 이상이면 캐시된 데이터라는것을 의미한다

X-Cache는 응답 을 보면된다
Hit from cloudfront → 캐시 적중 (캐시에서 응답함)
Miss from cloudfront → 캐시 미스 (오리진에서 응답함)
RefreshHit from cloudfront → 만료된 캐시가 새로 갱신됨

현재 내 페이지에서는 Hit from cloudfront로 응답이 왔기 때문에 잘 캐싱되고 있는것! ㅎㅎ 원본 S3가 아닌 Edge server에서 응답함으로써 S3 요청 비용과 네트워크 비용 절감!! 성공!



😉 CloudFront 캐싱 효과

  • 첫 요청 시에는 S3에서 파일을 가져와 엣지에 캐싱 → 이 때 S3 데이터 전송 및 CloudFront 비용 발생
  • 이후 동일 파일 요청은 CloudFront 엣지에서 처리 → S3 호출 비용과 일부 네트워크 비용 감소

하지만 CloudFront에서 캐싱이 만료되면(캐시 만료시간, 무효화 등), 다시 S3에서 콘텐츠를 가져오기 때문에 비용 발생! 캐싱이 지속되는 동안은 비용이 절감되지만 캐싱 자체가 완전 지속되는것은 아니기 때문에 캐싱 전략(캐시 만료 시간, 무효화 등)을 잘 설계해야 비용 최적화가 가능하다!

profile
FE 개발자가 되기 위한 땅굴 파기! 🌱

0개의 댓글