AWS S3 + CloudFront
배포 환경에서 캐싱을 적용하려 한다.
S3 버킷에 업로드된 mp4 파일의 메타데이터를 수정하려 했지만 CloudFront
가 이미 해당 파일을 참조하고 있기 때문에 편집하려는 대상을 복제 해야한다
우선 처음에 정리가 잘 안되던 부분이 있었다
S3
에도 Cache-Control
을 명시하고 왜 또 CloudFront
에도 Cache-Control
을 명시하는걸까?
결론은 S3
에 업로드 된 파일에도 cache-control
을 적용할 수 있고 CloudFront
에도 Cache-control
을 적용 할 수 있다
S3 파일의 Cache-Control 헤더 유무 | 캐싱 |
---|---|
Cache-Control 헤더 ❌ | CloudFront 캐싱 정책의 기본 TTL 값에 따라 캐싱 |
Cache-Control 헤더 ⭕️ | 해당 헤더 값에 따라 캐싱 기간이 결정 |
복제 할 대상의 복제 경로를 지정해주고, 추가 복사 설정 부분에서 설정을 직접 지정하도록 선택하여 메타데이터 cache-control
을 세팅하면 된다
기존에 소스 설정 복사를 선택하니 같은 파일명 + 같은 소스설정으로 인해
복사된 파일이 기존 파일에 그냥 덮어씌워지는 이슈가 있었다
그래서 캐싱 대상을 복사하고 설정을 따로 지정해야한다
설정 지정을 통해 아래 Cache-Control
메타데이터를 추가한다
Cache-Control: public, max-age=31536000, immutable
public
접근을 허용하고 1년 캐시 코드를 넣어주었다
앞으로 변경될 가능성이 상당히 적은 파일이라 1년으로 적용했다
적용한 파일의 메타데이터를 확인하니 잘 적용된것을 볼 수 있었다.
기존 파일의 메타 데이터에는 content-Type
이 지정되어 있었기 때문에
Cache-Control
설정에 추가로 Content-Type
도 설정해 주었다!
캐싱 적용할 파일의 대상이 mp4 파일이기 때문에 Content-Type
을 video/mp4
로 설정
이렇게 되면 파일명은 동일하지만 메타데이터는 다르기 때문에 덮어씌워진다!
S3에서 모든 정적 리소스의 Content-Type
은 브라우저와 CloudFront
, 캐싱에 모두 영향을 주므로 반드시 올바르게 지정해야한다!
Content-Type
을 통해 브라우저가 파일을 어떻게 처리할지 결정하기 때문이다
Content-Type | 처리방식 |
---|---|
image/png | 이미지를 화면에 바로 렌더링 |
video/mp4 | <video> 태그 등으로 플레이어 호출 |
application/json | JSON으로 파싱 |
text/css, application/javascript | 브라우저가 실행 |
만약, Content-Type
이 없거나 잘못 지정된다면
다운로드되어버리거나 콘솔 경고 (MIME type mismatch)가 뜰 수 있다!
혹은 캐시/압축 최적화가 제대로 동작이 되지 않을 수도 있고 CORS
오류가 날 수 있다
CloudFront
는 S3
의 Content-Type
을 그대로 전달한다. 따라서 S3
에서 지정하지 않으면 CloudFront
도 잘못된 MIME
을 그대로 전달하게 되는데
이로 인해 앞서 말한 문제점이 발생하게 되는것!
따라서 Content-Type
은 올바르게 지정해야한다
그럼이제 CloudFront
캐시 정책 설정이 필요한데
CloudFront
탭에서 정책 페이지로 이동한다. 하단으로 쭉 내리면
사용자 정의 정책 란이 보이는데 여기서 캐시 정책 생성을 선택!
생성을 누르면 세부정보의 캐시 정책 이름을 작성해야하는 부분과 TTL
설정란이 보인다.
캐시 정책 이름은 아무래도 고유한 이름을 사용하는것이 좋기 때문에 정적 비디오 캐싱을 명시하고 캐싱 기간과 프로젝트 명을 명시해서 지어줬다
TTL
은 총 3가지로 최소 TTL, 최대 TTL, 기본 TTL로 나누어져 있는데
각각의 역할이 다르다
최소한 이 시간만큼은 캐시된 데이터를 사용하겠다는 말!
그 시간 안에는 원본(S3
등)에 변경이 있어도 절대 다시 요청하지 않는다
ex) 60초 → 1분 동안은 무조건 캐시된 버전 사용
CloudFront
가 원본 응답에 Cache-Control
헤더가 없을 때 사용할 기본 값
Cache-Control
이 없다면 이 값만큼 캐싱
ex) 86400초 (1일)
최대 이 시간 이상은 절대 캐싱하지 않는다는 뜻으로
원본이 Cache-Control: max-age=31536000 (1년)
으로 설정돼도 이 값을 초과할 수 없다
ex) 31536000초 → 1년 이상은 안 됨
S3의 Cache-Control 설정이 없으면 → 기본 TTL 사용
S3가 max-age=31536000이라도 → CloudFront의 최대 TTL 이하까지만 유효
정책의 응답 헤더를 추가해야하는데 정책의 응답 헤더 탭에서 정책 생성을 한다.
동일하게 고유의 이름을 생성하고
Cache-Control 추가! 추가하면서 ETag, last-modified까지 적용했다
모든 정책을 다 생성 했으면 CloudFront
의 Edit behavior 탭으로 이동해서 캐시 정책과 응답 헤더 정책을 방금 생성한 정책을 적용시켜야 한다!
이제 배포 개발자 도구에서 네트워크 탭의 response header
를 확인해보자!
header
에 Cache-Contro
l이 잘 출력되고 있고, 함께 추가한 Etag
, Last-Modified
도 출력되는 중! 근데 여기서 드는 의문! 이제 정말 잘 캐싱되는것인가? 캐싱 되는지 여부를 내가 어떻게 파악 할 수 있는것인가?
확인하고 싶을때는 General
의 Status Code
를 확인하면 된다
캐싱 후 첫 호출때는 200ok
가 출력되었는데 다시 접근을 하면 304 Not Modified
로 출력된다.
이는 리소스 변경 없음, 캐시가 유효하다는 상태로 기존 캐시된 리소스 사용한다는것!
그리고 Response Headers의 Age
, X-Cache
를 확인하면 되는데
Age
는 캐시된 응답이 얼마나 오래되었는지 초단위로 보여주는데 이 숫자가 0 이상이면 캐시된 데이터라는것을 의미한다
X-Cache
는 응답 값을 보면된다
Hit from cloudfront
→ 캐시 적중 (캐시에서 응답함)
Miss from cloudfront
→ 캐시 미스 (오리진에서 응답함)
RefreshHit from cloudfront
→ 만료된 캐시가 새로 갱신됨
현재 내 페이지에서는 Hit from cloudfront
로 응답이 왔기 때문에 잘 캐싱되고 있는것! ㅎㅎ 원본 S3
가 아닌 Edge server
에서 응답함으로써 S3
요청 비용과 네트워크 비용 절감!! 성공!
S3
에서 파일을 가져와 엣지에 캐싱 → 이 때 S3
데이터 전송 및 CloudFront
비용 발생CloudFront
엣지에서 처리 → S3
호출 비용과 일부 네트워크 비용 감소하지만 CloudFront에서 캐싱이 만료되면(캐시 만료시간, 무효화 등), 다시 S3에서 콘텐츠를 가져오기 때문에 비용 발생! 캐싱이 지속되는 동안은 비용이 절감되지만 캐싱 자체가 완전 지속되는것은 아니기 때문에 캐싱 전략(캐시 만료 시간, 무효화 등)을 잘 설계해야 비용 최적화가 가능하다!