개발하고 있는 서비스에서 특정 html 파일이나 이미지를 AWS CloudFront를 사용하여 CDN으로 제공하고 있다.
화면상에서 고정으로 사용되는 아이콘들처럼 자주 수정되지 않을거라 예상하는 이미지나 파일을 CDN으로 제공하고 있는데, 최근에 html 파일을 변경해서 업로드했는데도 변경된 내용으로 화면에 보이지 않는다는 프론트팀의 말에 그저 "CDN으로 제공되고 있어서 캐시 때문에 그래요..!" 라고 할 수는 없기에 어떻게 해야하나 찾아보며 해결해본 내용에 대해 적어보려고 한다.
CDN은 Content Delivery/Distribution Network의 약자다.
지리적, 물리적으로 멀리 떨어져있는 사용자에게 거리와 상관없이 빠른 속도로 컨텐츠를 전송할 수 있는 기술로, 콘텐츠를 효율적으로 전달하기 위해 여러 노드를 가진 네트워크에 데이터를 저장하여 제공하는 시스템을 말한다.
CDN의 동작을 설명해보자면,
최초 요청 시 origin 서버에서 (운영중인 서버) 컨텐츠를 가져온 후 지리적으로 분산된 서버에 캐싱해둔 다음에
그 지역에서 똑같은 컨텐츠에 대해 요청이 들어왔을 땐 지리적으로 가까운 서버에 캐싱된 데이터를 가져오게 된다.
캐싱된 데이터는 설정된 주기에 따라 삭제되었다가 다시 요청이 들어오면 캐싱된다.
따라서 지리적으로 거리가 먼 사용자에게도 빠른 속도로 컨텐츠를 제공할 수 있다는 장점 뿐만 아니라
캐싱된 데이터가 있다면 origin 서버에 요청을 보내지 않기 때문에 서버의 부하를 줄일 수도 있다.
AWS CloudFront는 CDN 서비스를 제공한다.
CloudFront는 엣지 로케이션(Edge Location)이라고 하는 데이터 센터의 전 세계 네트워크를 통해 콘텐츠를 제공한다. CloudFront를 통해 서비스하는 컨텐츠를 사용자가 요청하면 지연 시간이 가장 낮은 엣지 로케이션으로 요청이 라우팅되어 가능한 최고의 성능으로 컨텐츠가 제공된다.
엣지 로케이션 뿐만 아니라 리전 엣지 캐시 라는 것도 있는데 좀 더 자세한 내용은 공식 문서에 잘 나와있기 때문에 읽어보면 될 것 같다.
상품 설명을 html 파일로 작성하여 S3에 저장하고 읽어올 때는 CDN 주소로 읽어오도록 하고 있었다. html을 CDN으로 제공하는 이유는 자주 변경될 내용이 아니고 정적 컨텐츠이기 때문에 CDN으로 제공하는 것이 효율적이라 생각되었기 때문이다.
이런 상황에서 한가지 이슈가 생겼는데, 상품 설명을 수정한 후 다시 업로드를 했을 때 내용이 변경되지 않는다는 것이다. 파일 업로드 시 파일 이름을 변경하지 않고 정해진 이름으로 올리고 있는데 이것 때문에 cloudfront에서 업데이트가 이뤄지지 않고 캐시되어있는 데이터를 응답으로 받아 이런 문제가 생기게 되었다.
여러가지 방법으로 해결할 수 있고 찾아본 해결 방법을 정리해보면 다음과 같다.
1번은 파일 이름을 동일하게 관리하기로 정해져서 패스
2번은 html은 현재 기본 정책을 사용하고 있는데 (Managed-CachingOptimized) 이미지들과 동일하게 쿼리 문자열을 허용할까.. 싶었지만 설정 자체는 유지하는게 좋겠다고 생각해서
3번 해결책을 선택하기로 했다.
사실 3번도 알고 있던 방법이긴 한데 매번 새롭게 업데이트 될 때마다 AWS에 로그인해서 무효화시키는건 아무리 생각해도 말이 안되고 분명히 효율적인 방법이 있을거라 생각했다.. (개발자들이 이런걸 이렇게 할 리가 없지..!)
단순하게 한번 무효화를 진행할 경우에 알맞는 방법이다.
무효화 생성 버튼을 클릭하고 무효화시킬 객체의 경로를 적고 무효화 생성만 하면 끝이다.
하지만 이렇게 하기엔 위에서 말했듯이 새로 업데이트 할 때마다 로그인해서 경로 이름 적어주고 무효화 생성해주고.. 하는 과정을 반복해야하기 때문에 자동화할 수 있는 방법이 없나? 찾아보았고
무효화하는 함수도 SDK로 제공되고 있다는 것을 알았다.(역시!)
무효화를 적용한 글들을 보면 lambda 함수와 연결해서 적용한 경우가 많은 것 같았다.
근데 의문이 든건 SDK로 제공이 되고 있는데 lambda를 연결해야하는 이유가 있을까? 였는데..
업로드 되는 시점과 캐시 무효화가 되어야하는 시점을 알고 있는데 왜 lambda로 무효화시키는 기능만 따로 만들어야 하는건지 잘 모르겠어서 그냥 애플리케이션에서 SDK 호출해서 무효화시키기로 했다!
CloudFront SDK를 사용하기 위해서는 일단 @aws-sdk/client-cloudfront를 설치해야한다.
yarn add @aws-sdk/client-cloudfront
그리고 CloudFrontClient 설정을 해주면 된다.
const cloudfrontClient = new CloudFrontClient({
region: "객체 원본의 리전",
credentials: {
accessKeyId: "access key",
secretAccessKey: "secret key",
},
});
이 설정할 때 region을 어떤걸로 해야하는지 모르겠어서 잠깐 헤맸었는데 객체 원본의 region을 적어주면 된다.
안적어주면 실행이 안되니까 꼭 적어줘야 한다!
무효화하기 위해서는 CreateInvalidationCommand를 사용하면 된다.
사용 방법은 [SDK 문서]((https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/cloudfront/command/CreateInvalidationCommand/)에 나와있다.
const cacheInvalidationInfo = {
DistributionId: "CDN ID",
InvalidationBatch: {
Paths: {
Quantity: pathList.length,
Items: pathList,
},
CallerReference: String(new Date().getTime()),
},
};
const command = new CreateInvalidationCommand(cacheInvalidationInfo);
await this.cloudFrontClient.send(command);
cacheInvalidationInfo의 모든 필드가 필수 값이다.
InavalidatoinBatch.Paths.Items에 무효화시킬 객체의 경로가 들어가면 된다.
이렇게 해서 실행시켜주면 무효화 생성이 잘 된다.
근데 무효화하는 비용이 따로 있는데 월 1,000회는 무료로 제공된다고 한다. 비용을 내지 않으려면 캐시 무효화가 진짜로 바로 적용이 되어야하는 파일인지 잘 고려해서 꼭 필요한 경우에만 무효화하는 것이 중요할 것 같다.
구글링을 하다가 마침 딱 원했던 정보여서 ㅠㅠ 큰 도움이 되었습니다~ 감사합니다!