[ReactJS] Express + CKeditor5 이미지 업로드 구현해보기 (3) (AWS S3 - Severless 구성)

오진서·2022년 7월 15일
2
post-thumbnail

제 주관적인 생각이 담긴 글이라 틀린 부분이 있을 수 있습니다.


서버 대신 S3 (Simple Storage Service)를 쓰는 이유

이번 시간에는 이미지 파일 업로드 기능을 AWS S3 Serverless 구조에서 동작하는 과정에 대해 알아보는 시간을 가져보겠습니다.

들어가기 앞서, S3를 사용했을 때의 이점에 대해 간략히 알아보겠습니다.

저희가 서버에 이미지를 저장한다고 가정해보겠습니다.

서버는 결국엔 공간적 한계가 있기 마련입니다. 한계에 도달하면 서버 용량을 무진장 늘릴 수 없으니 또다른 서버를 추가할 것이고, 이는 서버간 의존성이 높아지거나 statefull한 상태를 초래할 수 있습니다.

클라우드 상에서 서버를 구동할 때도 마찬가지입니다.

예를 들어, EC2 인스턴스를 동적으로 확장해주는 Auto Scaling 기능을 사용한다 가정했을 때, Load Balancer는 성능을 위해 요청을 분산시킬 것입니다. 그럼 이미지 파일들은 여러 서버에 흩어지게 되며, 각 서버는 상태 값을 가지게 되어 의존성을 가지게 됩니다. 마찬가지로 나중 부하가 줄어들어 서버를 축소시킬 때도 문제가 발생합니다.

반면, S3는 무제한의 스토리지를 가지고 있어 앞에서 언급한 문제점들을 걱정할 필요가 없습니다.

S3에는 이외에도 많은 장점을 가지고 있습니다. 정적 웹 호스팅 기능, 높은 보안성과 편리성, 버전 관리 (Git과 비슷), 수명 주기 설정 등 다양합니다.

본격적으로 들어가기 앞서, S3 관련 용어부터 간략히 짚고 넘어가겠습니다.

  • 버킷 (bucket) : 한 프로젝트의 최상위 디렉토리로 생각하시면 됩니다.
  • 객체 (object) : S3에선 파일 하나를 객체로 부릅니다.


프로세스 이해하기

현재 프로젝트 상황을 보면, 임시 폴더와 영구 폴더 두 가지가 존재합니다. 즉, 현 상황에서 나올 수 있는 경우의 수는 두 가지입니다.

  1. 임시 폴더는 로컬 서버에 두고, 영구 폴더만 S3에서 관리
  2. 임시 폴더, 영구 폴더 둘 다 S3에서 관리

둘 중 어떤 방식을 사용할지 혼자 고민해보다가 성능 면을 고려해서 제 얕은 지식으로.. 나름대로 정리해보았습니다.

먼저 (1) 방식을 사용한다고 가정해보면 다음 그림과 같습니다.

위 방식은 결국엔 최초의 이미지 업로드가 서버에 저장되므로 S3의 존재 이유가 무색해질 것입니다. 만약 동시 사용자 수가 급증해서 트래픽이 몰리면? 앞에서 언급했던 부작용이 되풀이 되는 것입니다.

또한 서버를 반드시 거쳐야하는 구조이기 때문에 클라이언트에서 S3로 직접 업로드하는 presigned URL 기능 또한 사용할 수 없게 됩니다.

다음으로 (2) 방식을 살펴보겠습니다.

(2) 방식에서는 임시 폴더가 S3에 있으니 추후 Serverless 아키텍처를 통한 presigned URL 기능을 구현할 수 있게 됩니다. Serverless 방식에 대해서는 나중에 자세히 다룰 예정입니다.

단, 구현이 많이 복잡해진다는 단점이 존재합니다.

현재 저희 프로젝트에서는 사용자가 글 작성 도중 나가면(컴포넌트가 Unmount된다면) 임시 파일 삭제 API를 호출하도록 되어있습니다. 이를 간편화하기 위해 S3에서 제공하는 수명 주기 정책 (Life Cycle Rule)을 적용하여 일정 시간이 지난 임시 폴더(Object)를 삭제하도록 하겠습니다.

다음으로 Serverless 업로드 아키텍처에 대해 알아보겠습니다.


Serverless 업로드 아키텍처

일반적으로 S3 버킷에 이미지 파일을 업로드한다 가정해보면,

브라우저 -> 서버 -> S3 순으로 업로드가 진행됩니다.

이 과정은 중간에 서버가 필요도 없는 파일들을 쥐고 있기 때문에 리소스 낭비가 크며, 시간 소모 또한 발생하게 됩니다. 이를 해결하기위한 방법으로 서버를 거치지 않고 브라우저에서 S3로 직접 업로드하는 방법이 있습니다.

하지만 이미지를 가져오는 것은 public 할지라도 버킷에 업로드하는 행위는 인증된 사용자만 허용토록 해야되므로 AWS로부터 presigned URL을 발급받아 인증 과정을 거치도록 해야 합니다.

presigned URL이란 말 그대로 미리 서명된 URL입니다. 이 URL을 가지고 제한된 시간 안에 버킷에 접근할 수 있게하며 일정 기간 다른 사용자의 접근을 허용하거나 공유를 하기도 합니다.

전체 아키텍처를 살펴보겠습니다.

  1. 사용자가 파일 업로드 시 API Gateway를 호출하여, 트리거가 걸린 Lambda 함수를 통해 presigned URL을 S3에서 가져옵니다.
  • API Gateway : API들이 지나다니는 통로이며, 람다 함수를 라우팅 하기위한 API를 생성하는 용도입니다. (스프링에서 Dispatcher Servlet 개념과 비슷한 것 같습니다)

  • Lambda : 특정 이벤트의 응답을 위한 코드를 작성할 수 있으며, 여기서는 presigned URL을 발급 받기 위해 람다 함수를 사용합니다.

  • API GatewayLambda를 이용해서 서버 없이 HTTP or REST API를 구성한다 생각하시면 됩니다.
  1. 클라이언트에서 presigned URL로 직접 S3에 파일을 업로드 합니다.

이렇게 Serverless 방식을 도입해서 서버에 의존하지 않고도 이미지를 업로드 할 수 있는 구조가 완성되었습니다.

마지막으로 이미지 파일들을 빠르게 로드시킬 수 있도록 CloudFront (CDN) 기능을 적용해보겠습니다.


CloudFront (CDN)?

CloudFront 기능에 대해 간략히 설명하자면 AWS에서 제공하는 CDN (Content Delivery Network) 서비스 입니다.

만약 S3에서만 이미지를 제공한다 가정한다면? 물리적인 위치가 먼 이용자일 수록 이미지 로드 시간이 길어지게될 것이고, 한 곳 (Origin Server)에서 서비스하므로 트래픽 급증에 대한 부하 또한 걱정해야 됩니다.

CloudFront는 전 세계 곳곳에 Edge Server (Location)(중간 서버)을 두고, 컨텐츠를 미리 캐싱하여 사용자들이 가까운 Edge Server로부터 빠르게 이미지를 로드할 수 있도록 해줍니다.

최종적인 이미지 업로드 아키텍처 모습입니다.



이번 포스팅은 여기서 마치겠습니다.

다음 시간에는 지금까지 설명한 시나리오대로 구현을 해볼텐데,, 아직 구상만한 단계라 실제로 구현이 될지 모르겠습니다..

그리고 아직 보안에 대한 고려는 안해봐서 구현을 해보면서 고민해봐야될 것 같습니다. 감사합니다. ㅎㅎ

참조

https://aws.amazon.com/ko/blogs/storage/
AWS 스토리지 관련 문서들을 참고하였습니다.

https://serverlessfirst.com/serverless-photo-upload-api/
서버리스 아키텍처에 대해 참고하였습니다.

profile
안녕하세요

0개의 댓글