CloudFront Cache

Amazon CloudFront를 사용하면 사용자의 요청을 Edge Location에서 캐시 값을 검사하여 24시간 동안에는 사용자에게 다시 파일을 제공하지 않고 캐시 된 값을 빠르게 제공한다. 서비스의 종류에 따라 다르겠지만 만약 이미지를 제공하는 사이트라면 한번 올라간 이미지는 바뀔 일이 없어서 전송 비용을 아낄 수 있는 엄청난 기술이다. 물론 이미지 리사이징 후 다시 저장해야 하는 경우도 있지만 하지만 자주 바뀌어야 하는 오브젝트라면 S3에 원본 오브젝트가 바뀌어도 이미 캐시 된 이전 오브젝트가 클라이언트에게 제공되는 현상이 생길 수 있다. 오히려 자주 바뀌는 오브젝트는 CloudFront의 Cache가 오히려 독이 되는 셈이다. 그렇다고 오브젝트의 Cache가 즉시 Expire 하게 설정하자니 Cache의 효과를 포기하기에는 비용 손실 때문에 그럴 수는 없는 셈이다.
AWS 공식문서에서도 이러한 문제점의 해결책으로 2가지를 제시하고 있다.

⭐AWS가 제시하는 해결책⭐
1. S3 객체를 무효화합니다.
2. 객체 버전 관리를 사용합니다.
본 포스트는 1번을 설명할 예정이니 2번에 관한 내용은 링크를 통해 확인바란다.

S3 Object Invalidation (S3 객체 무효화)

Amazon CloudFront를 통해 배포된 콘텐츠를 변경한 후 캐시를 사용하지 않는 방법은 두 가지가 있다. 캐시가 만료될 때까지 기다리거나 변경사항을 즉시 반영하기 위해 Invalidation 한다. (물론 이미 사용자 브라우저의 캐시 된 콘텐츠에 대해서는 아무것도 할 수 없다.) Invalidation 이 완료되면 클라이언트는 캐시 된 콘텐츠가 아닌 새로 업데이트된 오브젝트를 제공받는다.

해결 방안

위와 같은 Invalidation을 이용해 해결을 하고자 한다. 하지만 매번 새로운 콘텐츠가 바뀔 때마다 AWS에 로그인하여 Invalidation을 실행하기에는 너무 레거시한 방법이라고 생각했다. 그리고 AWS Lambda에 S3 Bucket에 Object Created Trigger 이벤트를 등록하여 자동화를 만들 예정이다.

구현

Lambda 함수 생성

함수 이름은 CacheInvalidationOnObjectUpdate로 설정 후 런타임은 Python 3.6으로 설정한다.

Lambda 코드 작성

from __future__ import print_function

import boto3
import time

def lambda_handler(event, context):
    path = []
    for items in event["Records"]:
        path.append("/" + items["s3"]["object"]["key"])
    print(path)
    client = boto3.client('cloudfront')
    invalidation = client.create_invalidation(DistributionId='E1204AGXXXXXXX',
        InvalidationBatch={
            'Paths': {
                'Quantity': 1,
                'Items': path
        },
        'CallerReference': str(time.time())
    })

기본으로 만들어진 lambda_function.py 에 위 코드를 작성한다. 그리고 코드 중 DistributionId='E1204AGXXXXXXX' 이 부분을 본인이 연결하고자 하는 CloudFront의 DistributionId 값을 넣는다.

권한 설정

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
        "Effect": "Allow",
        "Action": [
            "cloudfront:CreateInvalidation"
        ],
        "Resource": [
            "*"
        ]
    }
  ]
}

구성 -> 권한 -> 실행 역할 -> 편집 에서 권한을 위 json으로 편집한다.

트리거 설정

트리거 추가를 눌러 트리거를 아래와 같이 추가한다.

테스트

모든 설정이 완료된 후 CloudFront와 연결된 S3 Bucket에서 오브젝트를 수정하면 자동으로 Lambda에서 트리거를 감지하여 코드가 실행된다.

위 사진은 이벤트 발생 시 CloudWatch 그래프로 함수의 실행 여부를 확인할 수 있다.

그리고 CloudFront에 Invalidations 탭에서 자동으로 실행된 무효화를 확인할 수 있다.

그리고 업데이트된 파일에 한해서만 무효화가 실행된다. 만약 파일을 하나만 업데이트 시 전체 무효화를 실행한다면 클라이언트에게 캐시 없이 모든 파일을 재전송해야 하는 손실이 생길 수 있기 때문이다.

요금
Lambda 128MB 기준 3,200,000번 무료로 호출할 수 있다.
그 후 비용은 매 100ms 실행 당 $0.000000208가 된다.
위 로그를 확인하면 함수 한번 실행당 254ms 가 소요되었으니
1회당 $0.00000052832 라고 볼 수 있다.
그리고 무효화 1회 당 비용이 청구되는데 월 1,000회는 무료로 제공된다.
그 후 비용은 링크에서 참고 바란다.

'AWS > CloudFront' 카테고리의 다른 글

AWS S3 + CloudFront 대용량 파일 전송  (0) 2021.06.01