S3 Cache를 설정해보자 !

김동헌·2024년 4월 24일
2

SpringBoot

목록 보기
16/19
post-thumbnail

잉크링크 서비스 중 기존의 사용자에게 제공되는 PDF파일이 수정됐음에도 사용자에게 수정되지 않은 원본의 PDF파일이 제공되는 문제점을 발견했습니다.

해당 포스팅은 원인 분석과 문제 해결을 중심으로 포스팅을 진행했습니다.


어떤 문제가 발생했나 ?

  1. 관리자가 사용자만의 책(pdf)S3에 업로드
  2. 사용자가 객체 URL을 통해 pdf에 접근
  3. 관리자가 사용자의 책을 수정 후 S3에 재 업로드(파일명 동일)
  4. 사용자는 객체 URL을 통해 pdf에 접근 할 때 수정되지 않은 기존의 pdf를 제공받음

원인이 무엇일까 ?

S3의 저장된 객체에 대한 캐싱 정책을 적용하지 않았기 때문 !

사용자는 기존에 제공된 pdf 파일이 브라우저에 캐싱이 되어 있어서 아무리 pdf 파일을 수정하더라도 객체 URL이 동일했기 때문에 수정된 파일이 제공되지 않았습니다.


기본 개념

객체 메타데이터

  • 객체 메타데이터는 이름-값 페어의 집합으로 객체에 대한 추가 정보를 의미합니다.
    AWS 공식문서 - S3를 통해 메타데이터의 목록을 확인해보면 Cache-Control이 있는데 이를 통해 객체의 캐싱 정책을 추가할 수 있습니다.

Cache-Control 헤더

  • 적용 범위 : Cache-Control는 일반 헤더 필드로, 요청/응답 체인의 모든 캐싱 메커니즘에 반드시 따라야 할 지시문을 지정하는 데 사용됩니다. 이 헤더는 요청이나 응답이 캐싱 방해를 받지 않도록 설계되어있습니다.
  • 단방향성 : Cache-Control 헤더는 요청과 응답에 각각 독립적으로 적용됩니다. 요청에 포함된 특정 지시어가 응답에 동일하게 포함되지 않습니다.
  • 프록시 및 게이트웨이 적용 : Cache-Control는 요청/응답 체인의 모든 수신자에게 적용될 수 있으며, 프록시 서버나 게이트웨이를 통해서도 전달되어야 합니다. 특정 캐시 대상에 대한 지시어를 지정할 수는 없으며, 지시어는 전체 네트워크 경로에 걸쳐 적용됩니다.

W3 공식문서 - 14.9 Cache-Control

Cache-Control Directives
여기서 사용할 캐시 지시어는 no-cache, no-store, must-revalidate입니다.

  • no-cache
    • 캐시가 반드시 원 서버에서 콘텐츠의 유효성을 재확인해야합니다. 캐싱을 완전히 금지하는 것이 아니라, 캐시를 사용하기 전에 매번 검증을 요구합니다. (바뀐 내용이 있는지)
  • no-store
    • 캐시가 요청이나 응답에 포함된 어떠한 정보도 저장하지 못하도록합니다.
  • must-revalidate
    • 만료된 캐시는 서버의 재승인 없이 사용될 수 없습니다. 이 지시어는 캐시된 콘텐츠의 유효성이 만료된 후 사용자에게 제공되는 것을 방지합니다.

지시어들을 정리하면서 왜 3개를 같이 사용할까 ?라는 궁금증이 생겼고 정리해 보았습니다.

보안이 중요한 경우 no-store만 사용하여 데이터가 전혀 저장되지 않도록 할 수 있고
no-cache, must-revalidate를 함께 사용해 항상 최신 데이터만 사용되도록 할 수 있습니다.

3개를 같이 사용하는 이유
1. 복합적인 요구 사항 충족 : 서비스를 운영하면서 다양한 유형의 데이터와 상호작용을 처리하기 때문에 여러 지시어를 함께 사용하여 각기 다른 캐싱 이슈에 대응하기 위해서
2. 예측 불가능한 사용 환경 : 클라이언트의 환병(ex: 브라우저, 프록시 서버 등)에서 다르게 해석하거나 적용할 수 있기 때문에, 서버 측에서 보다 명확하게 캐싱 정책을 지시하기 위해 여러 지시어를 함께 사용합니다.

다양한 Cache-Control을 설정한다면
rfc7234 - 공식문서, W3 공식문서 - sec14.9.2를 참고하시면 좋을 것 같아요 !

캐시를 사용하지 않는다면?

캐시를 사용하지 않는 경우 증가된 대기 시간, 높은 네트워크 트래픽, 비용 증가, 서버 부하 증가, 스케일링 문제가 있습니다. 캐시 제어를 완전히 비활성화 하는 대신, 적절한 캐시 유효 시간(max-age)을 설정하거나, 콘텐츠의 변경을 감지할 수 있는 다른 메커니즘(ex:ETag, Last-Modified 헤더)을 활용할 수 있습니다.

저희 서비스에서는 관리자가 파일을 업로드할 때 no-cache, no-store, must-revalidate 지시어를 사용하여 객체의 메타데이터 캐시를 비활성화하였습니다.

캐시를 사용하지 않을 경우 단점이 존재하지만, 제공되는 파일은 주로 다운로드 목적으로 접근되기 때문에, 사용자의 접근 빈도가 높지 않을 것으로 예상되어 캐시 제어를 비활성화 하였습니다.

이를 통해 파일이 잘못 업로드되었을 경우 수정 후 즉시 사용자에게 최신 버전을 제공할 수 있습니다.


해결

특정 콘텐츠가 브라우저 캐시 사용 여부는 시스템 제어 또는 사용자 제어의 방법이 있고 두 방법 모두 포스팅해보겠습니다.

시스템 제어

시스템 제어는 S3 객체에 직접 메타데이터를 편집하는 방법입니다 !

객체 선택 -> 메타데이터 편집

메타데이터 추가

  • 시스템 정의
  • : Cache-Control
  • : max-age=0, no-cache, no-store, must-revalidate


사용자 제어

    private String ebookToS3(String key, MultipartFile file, String mimeType) throws IOException {
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(mimeType);
        metadata.setContentLength(file.getSize());
        metadata.setCacheControl("no-cache, no-store, must-revalidate, max-age=0");
        amazonS3Client.putObject("inklink-bucket", key, file.getInputStream(), metadata);
        return defaultUrl + key;
    }

위 코드에서
metadata.setCacheControl("no-cache, no-store, must-revalidate, max-age=0");를 통해 S3객체에 대한 캐시 제어 정책을 설정하였습니다.
해당 설정으로 클라이언트 측에서 해당 객체를 캐시하는 것을 완전히 비활성화하여, 매번 원 서버에서 최신 버전의 데이터를 확인하도록 설정하였습니다.


참고 자료

AWS 공식문서 - S3
AWS 공식문서 - CloudFront
rfc7234 - 공식문서
W3 공식문서 - sec14.9.2

profile
백엔드 기록 공간😁

0개의 댓글