본문 바로가기
AWS

AWS Lambda를 이용한 이미지 리사이징

by yongjinDev 2023. 3. 30.

1편에 이어서 진행합니다.


기존 이미지 업로드 - 썸네일을 만드는 과정은 아래와 같았다.

  1. 클라이언트로부터 이미지 파일을 받아서
  2. API 서버에서 이미지 S3 업로드 및 DB 저장
  3. 비동기로 이미지 리사이징 작업 후 2번 작업
  4. 썸네일은 비동기로 처리되기 때문에 작업 완료되기 전까지는 사용자는 이미지 원본을 조회

여기서 클라이언트에서 S3로 직접 업로드함으로써 1,2번의 과정을 단축시켰다.

남은건 3,4번이다. 원본 이미지를 리사이징하고 S3와 DB에 저장하는 부분인데, 이 부분을 개선하기 위한 고려사항은 다음과 같았다.

  1. 시간 단축
  2. 비용
  3. 유지보수 / 개발 공수 고려

다양한 레퍼런스를 참고하면서 내린 결론은 서버리스(Serverless) 방식의 AWS Lambda를 이용한 리사이징 방식이였다.

이유는 다음과 같다.

  1. AWS Lambda에서 동작하므로 API 서버와 로직이 분리되어 서버에 부담을 주지 않는다.
  2. 지금 우리 서비스 규모에서는 비용이 들지 않는다. (이미지 리사이징 전용 서버를 비용 없이 얻는 효과)
  3. 서버리스 환경에 구축하여 서버 인프라 구축 및 유지 관리 공수가 비교적 적다.

 

처음에는 현재 당근마켓, 트레바리등 많은 기업에서 적용하고 있는 Lambda@Edge와 CDN 방식을 이용한 On-demand 방식(요청이 왔을 때 처리)으로 리사이징을 하는 것을 고려했다.

그러나 우리 서비스는 당근마켓이나 SNS처럼 사용자들이 같은 사진을 보는 서비스가 아니라, 본인의 게시글을 보는 클라우드 서비스이므로 CDN을 통한 캐싱방식이 맞지 않다고 생각했다. CDN 방식의 단점은 캐싱되기전에는 그냥 S3에서 가져오는 속도보다 느리다는 점이다.

속도 비교

같은 리전이더라도, 모두 다른 게시글을 조회하기 때문에 차라리 클라이언트측에서 캐싱을 하는 것이 더 효율적이라 판단했다. 그래서 On-demand 방식이 아닌, 이미지 업로드 시 썸네일을 AWS Lambda에서 생성해 S3 및 DB에 저장하는 방식을 선택했다. 

처음에는 S3 버킷에 원본 이미지가 업로드 되면, Lambda가 트리거를 받아 썸네일을 생성해주는 방식으로 작업했다.

그리고 람다가 썸네일을 생성해주는 시간은 ms 단위로 생각보다 빠르게 동작했다.

하지만 이 방식에는 문제가 있었다. 이번에 클라이언트에서 직접 이미지를 S3에 업로드 하는 방식으로 바뀌면서, S3에는 원본이미지가 업로드 됐는데 아직 DB에 저장 되지 않은 경우나, 반대로 S3에는 업로드가 안됐는데 DB에 저장 되어있다면 이미지 처리에 순서가 꼬여서 썸네일이 생성되지 않는 경우가 생길 수 있었다.

그래서 게시글이 DB에 저장 되고, S3에 이미지가 들어간 후에 썸네일을 생성하도록 순서를 핸들링해야했다.

최종적으로 API 서버에서 원하는 시점에 람다를 호출하는 방식으로 변경했다. (Lambda의 트리거가 API Gateway로 변경)

 

Lambda 프로젝트에는 Serverless 프레임워크를 사용했고, 이유는 yml 파일로 Lambda에서 사용할 핸들러들을 관리할 수 있고, 테스트와 배포에도 편리한 기능을 제공하기 때문이다. Lambda에는 굳이 NestJS를 설치하진 않았고, NodeJS 환경에서 TypeORM만 적용했다.

그리고 Lambda의 단점..보다는 서버리스 방식의 단점인 cold start문제를 해결하기 위해서 5분마다 주기적으로 람다를 실행시켜 warm start 상태를 유지할 수 있도록 하였다. (추후에 Lambda를 사용한 각 종 배치나 스케줄링 작업이 추가되면서 자연스럽게 warm start 상태를 유지할 수 있도록 되었다.)

 

람다의 콜드스타트란 마치 노트북을 재부팅 하는 것과 같다. 재부팅시에 약간의 대기시간이 필요하듯이, 람다도 일정시간(5분)동안 호출되지 않으면 꺼진다. 그래서 람다의 핵심은 시간이 오래걸리는 코드는 전역으로 뺀다는 점이다. (DB 커넥션 등)

콜드 스타트를 해결하기 위한 방법으로는 람다를 계속 호출해주는 방법과 프로비저닝된 동시성(Provisioned Concurrency) 활성화를 설정하는 방법이 있었다. AWS 공식 문서에서 권장하는 방법은 Provisioned Concurrency 였지만, 추가 비용이 발생해서 선택하지 않았다. 실제로 람다를 계속 호출하는 방식을 적용하고 비용을 확인했을 때, Lambda의 비용은 따로 발생하지 않았다.

 

 

 

Lambda에 대해 알아보자. 특징과 동작원리, 장/단점과 단점을 보완했던 방법을 정리했다.

AWS Lambda

  • 서버리스 컴퓨팅 서비스 특징
    • 서버리스, 이벤트 드리븐, 비동기
    • 항상 서버를 켜두는 것이 아닌, 필요할때만 함수가 호출 되어 코드가 동작하는 방식.
  • 실행 시마다 람다 서비스에 할당된 EC2에 컨테이너를 띄워서 실행하는 방식.

 

  • 람다의 동작 원리(Life-Cycle)
    • 람다 핸들러의 실행 순서

1. Download your code
- 람다 핸들러가 실행될 AWS의 내부 인스턴스(ECS)에서 개발자가 작성하고 업로드한 코드를 다운로드 합니다.


2. Start new execution environment
- 새로운 실행 환경을 생성하는 단계입니다.
- 메모리, 런타임 등을 말합니다.

 

3. Execute initialzation code
- 람다 핸들러의 전역 코드를 실행하는 단계입니다.

빨간 원의 코드가 람다 핸들러 범위 밖의 코드.

 

4. Execute handler code

- 람다 핸들러 내부의 코드를 실행하는 단계입니다.

 

 

장점

  • API 서버 작업 감소
  • 비용 절감 (함수가 호출되어 처리하는 시간만 밀리초 단위 및 실행횟수로 비용이 발생)
    • 월 백만건의 요청이 와도 월 13$ (현재 서버 한대 비용보다 저렴)
    • 당시 통계에 하루 평균 500개 정도의 이미지가 업로드 되었는데, 월 0.3$ 예상 비용
  • 서버 관리 부담 절감
    • 오토스케일링: 람다는 요청에 따라 내부적으로 스케일아웃한다.
    • 람다 메모리 = CPU사양 이라 할 수 있는데, 높은 메모리 일수록 처리속도가 빨라지므로 총 실행시간은 줄어든다.
      람다는 메모리를 늘린다고 무조건 비싼것이 아니다.
  •  AWS의 다른 인프라와 연동 가능 (S3, SQS, CloudWatch 등)

 

단점, 단점을 우리 서비스에서 보완한 방법

1. 여러 형식의 썸네일 이미지를 하나의 Lambda 함수에서 생성하도록 동작한다.
이때, 미처 썸네일이 생성 되기 전에 요청이 들어와 제대로 응답하지 못하는 경우가 있을수 있다.

  => 우리 서비스는 아직 하나의 썸네일만 저장하고 있고, 후에 다양한 사이즈의 썸네일을 생성하도록 변경되더라도, 썸네일이 생성되기 전에는 원본이미지를 조회하는 방식으로 보완하고 있다.

 

2. 모든 썸네일이 S3에 저장되어 저장소 사용량도 증가한다.

  => Lambda 도입 전과 동일한 부분. 하지만 S3 용량은 신경쓰지 말라는 팀장님의 든든한 지원..!

 

3. 서비스 UI 개편으로 썸네일 이미지 크기가 변경될 경우 모든 썸네일을 재생성 해야 하는 일이 발생한다.

  => 맞다. 실제로 나중에는 썸네일 크기를 S,M,L 이런식으로 사이즈별로 변경되어서 스크립트를 통해 썸네일을 재 생성했다.

하지만 필요한 사이즈크기를 지정해주는 작업만 추가로 필요하고, 로직은 동일하다.

 

4. 로그를 CloudWatch를 통해 봐야함.

  => 이미 우리는 서비스 로그도 CloudWatch를 통해서 보고 있었다.

 

5. 기타 (리소스 제한 및 cold start 문제 등)

  • 상태비저장(Stateless) - cold start
  • 러닝타임 최대 15분
  • 타 클라우드로 이전 어려움

  => 5분마다 람다를 호출하는 방법으로 항상 warm start 상태를 유지했으며, 15분 이상 걸리는 배치 작업은 아니였다. AWS에서 다른 클라우드로 옮길 확률도 없었다.

 

 

 

 

'AWS' 카테고리의 다른 글

Pre-Signed URL을 이용한 S3 이미지 업로드  (0) 2023.03.13
서버 부하 테스트 (feat. Jmeter)  (0) 2023.03.05