현재 진행 중인 프로젝트에서는 이미지를 S3에 업로드하고, Endpoint URL로 이미지를 불러온다.
하지만 이렇게 S3만으로 이미지를 관리하면서 서비스를 운영하기에는 본인의 S3가 사용자에게 그대로 노출되어진다.
사용자로부터 직접적인 접근을 제한하고, Edge Location에 캐싱 및 지리적인 이점을 통한 성능 이점(전송 속도, 비용 절감, 서버 부하)을 제공하는 CloudFront를 본 프로젝트에 적용한 과정을 소개하고자 한다.
CloudFront
CloudFront는 AWS에서 제공하는 CDN 서비스이다.
전 세계 이곳저곳에 Edge Server(Location)을 두고 Client에 가장 가까운 Edge Server를 찾아 Latency를 최소화시켜 빠른 데이터를 제공하고, 캐싱을 통해 사용자에게 빠른 전송 속도를 제공한다.
CDN이란?
CDN(Content Delivery Network or Content Distribution Network, 콘텐츠 전송 네트워크) 은 콘텐츠를 효율적으로 전달하기 위해 여러 노드를 가진 네트워크에 데이터를 저장하여 제공하는 시스템이다.
즉, CloudFront를 통해 S3에 접근할 경우 얻는 이점은 다음과 같다.
- 콘텐츠 캐싱을 통한 S3 부하 감소
- Edge Location을 통한 응답속도 향상
- 콘텐츠 보안 유지
CloudFront 배포
Origin Domain Name(원본 도메인)
- CloudFront와 연결하고자 하는 S3를 찾아 넣어준다.
Origin Path(원본 경로)
- default 경로 값을 설정할 수 있다.
/profile
을 작성하면,{Origin-Domain-Name}/apple.png
요청 시,{Origin-Domain-Name}/profile/apple.png
를 호출한다.
Origin Access ID(원본 엑세스 제어 설정, OAI)
- 제어 설정 생성을 통해 원본 엑세스 제어를 생성 혹은 기존 원본 엑세스 제어를 연결한다.
- Legacy access identities로 원본 엑세스 ID(OAI)를 생성하여 설정할 수 있지만 본 프로젝트에서는 Legacy가 아닌 권장 설정으로 진행했다. (이전에는 OAI 사용 안함, OAI 사용-access identities 두 가지만 있었음)
S3 정책 수정
배포 후 CloudFront → 배포 → 원본 → 편집에서 S3 버킷 정책에 적용할 CloudFront 엑세스 정책을 복사한다.
S3 → 버킷 → 권한에서 버킷 정책에 CloudFront 정책을 입력한다.
퍼블릭 엑세스 또한 모두 차단한다.
SpringBoot로 S3에 파일을 업로드하고 있어 새 ACL(엑세스 제어 목록)을 통해 부여된 버킷 및 객체에 대한 퍼블릭 엑세스 차단은 비활성화한다.
이제 S3의 엔드포인트로 직접 요청을 하게 되면 Access Denied된다.
파일에 접근하려면 {CloudFront-도메인}/버킷경로/파일명
으로 요청해야한다.
코드 수정
MemberService.java
@Value("${cloud.aws.cloud-front.domain}")
private String cloudFrontDomain;
...
AwsS3 awsS3 = new AwsS3();
try {
awsS3 = awsS3Service.upload(profileImage, "profileImage");
}catch (IOException e){
System.out.println(e);
}
profileImageUrl = cloudFrontDomain + "/" + awsS3.getKey();
awsS3.getKey()
로 버킷 디렉토리/파일명 경로를 가져와 CloudFront 도메인 뒤에 합하여 CloudFront로 url을 저장한다.
파일 업로드/삭제는 그대로 진행하고, 조회 및 저장할 때 url만 수정해주면 된다.
DB에 CloudFront 도메인을 제외한 path만 저장하여 CloudFront가 바뀔 때 기존 DB의 값들이 모두 수정되어야 하는 상황을 방지하고자 했음.
하지만 이미지URL을 DB에서 직접 조회하여 사용하는 로직이 많아 일일이 DB에서 조회한 뒤 CloudFront 도메인 값을 붙여주는 것이 더욱 번거롭고 비즈니스 코드가 지저분해지게 된다.
DB에 CloudFront 도메인과 파일 Path 전체 url을 저장하고, 추후에 CloudFront 변경 사항이 있을 경우 CloudFront 도메인 부분을 전체 업데이트 하는 방식으로 구성하기로 결정함.
성능
aws 블로그에서 진행한 CloudFront 성능 테스트이다.
각 위치마다 4번씩 테스트를 진행. 일반적으로 CloudFront가 있을 때는 첫 번째 GET 요청이 CloudFront가 없을 때 동일한 요청에 비해 약간 빠르다. 하지만 이후부터는 각 GET 요청의 속도가 현저히 빨라진다. 이렇게 차이가 나는 이유는 캐싱에서 찾을 수 있다. 본인의 S3 버킷에서 전송되는 파일이 첫 번째 GET 요청 이후 캐싱되어 이미 테스트를 실시하는 곳과 가장 가까운 엣지 로케이션에 저장되었기 때문이다. 경우에 따라 파일 반환 속도가 100배까지 빨라진다.
S3와 함께 CloudFront를 설정하는 것 만으로 다음과 같은 이점을 얻을 수 있다.
- 콘텐츠를 더욱 빠르게 사용자에게 전송하여 애플리케이션 성능을 높일 수 있다.
- CloudFront의 보안 기능으로 애플리케이션의 보안을 강화할 수 있다.
- CloudFront에서 인터넷으로 데이터를 전송하는 요금이 간혹 S3에서 인터넷으로 전송하는 요금보다 저렴하여 AWS 청구 비용을 아낄 수 있다.