Lambda@Edge를 활용한 CloudFront 이미지 리사이징 도입 후기

조규진
DOMOVERSE 도모버스 블로그
8 min readMay 14, 2021

이번 글에서는 도모버스의 이미지 CDN 구조와 이미지 리사이징 도입 과정에서의 삽질 흔적을 톺아보려 합니다.

도모버스 이미지 CDN 소개

도모버스 앱 내에서 CDN을 통해서 제공되는 이미지는 크게 네 가지 분류로 나눌 수 있습니다.

도모버스에서 제공하는 교재의 표지 이미지입니다. 당사와 저작권 합의가 이루어진 교재의 표지는 CDN에서 직접, 그렇지 않은 경우는 재배포 관련 문제로 인해 저작권자의 이미지 링크를 통해 제공하고 있습니다.

도모버스의 톺아보기 컨텐츠 이미지들입니다. 작게는 4인치부터 크게는 12인치까지의 여러 화면 크기 및 해상도를 대응하기 위해 300px대의 세로 값을 사용하는 타 이미지들과 달리 주로 1000px의 이미지를 사용합니다.

커뮤니티 게시글 및 댓글 작성자의 프로필 이미지입니다. 역시나 정방형 이미지로 업로드되며, 이미지 컨테이너의 사이즈가 매우 작은 관계로 제공할 이미지의 사이즈도 작은 편입니다.

커뮤니티의 게시글에 사용자들이 게시하는 이미지입니다. 형태는… 예측할 수 없습니다.

도모버스는 이미지 제공을 위해 AWS의 CloudFront와 S3 조합을 활용하고 있습니다. 회사 인프라 중 AWS 비중이 절대적이기에 (도모버스의 서버 스택 톺아보기) 자연스레 이미지 제공도 AWS에 의존하게 되었습니다.

서비스 초기에는 자체적으로 제공하는 이미지의 경우 사이즈가 리사이징 효과를 볼 정도로 크지 않고, 사용자들의 일반적인 네트워크 및 단말 성능 수준이 어느 정도의 이미지를 다량으로 로드하는 것을 충분히 견딜 것이라고 판단되어 리사이징 없이 이미지를 제공하기로 결정했습니다.

이러한 방식은 개발 초기에는 별 문제 없이 작동하였습니다. 하지만 개발이 막바지에 다다르고, 실 서비스용 톺아보기들이 계속 추가되면서 문제가 생깁니다.

“예측하지 못한 결과에 대비하라”

최종 검증 과정 중에 피드백이 들어왔습니다.

톺아보기 목록 로딩이 너무 느려요!

도모버스의 톺아보기 목록은 3 by n의 그리드에 각각 톺아보기의 첫 장을 프리뷰로 제공하는 방식으로 표시됩니다. 개발 초기에는 한 화면에 띄워야 할 이미지의 갯수가 많지 않아 괜찮았지만, 개당 1MB 이상의 덩치를 자랑하는 리사이징을 거치지 않은 이미지들이 점점 늘어나면서 일부 연산 성능이나 RAM 사이즈가 좋지 못한 기기에서 이미지 로딩이 지연되는 현상이 발생한 것이죠.

이런 문제를 마주한 개발팀은 고심 끝에 Lambda@Edge를 통한 동적 리사이징 처리를 도입하기로 결론을 냈습니다.

Lambda@Edge란 무엇인가요?

Lambda@Edge는 CDN 요청/응답을 동적으로 처리 가능하게 해주는 AWS CloudFront의 기능 중 하나입니다. 처리를 위해 서버리스 컴퓨팅 기능인 AWS Lambda를 활용합니다.

Lambda@Edge의 네 가지 작동 방식

Lambda@Edge는 원본 서버와 CDN, 그리고 요청 사용자 사이에 전달되는 각 값들을 가로채서 수정하는 형태로 작동합니다. 이런 점을 활용해, Lambda@Edge를 통해 처리된 Origin 요청 / 응답의 경우 그렇지 않은 리소스와 동일하게 CloudFront의 CDN에 캐시됩니다.

도모버스 팀이 Lambda@Edge를 선택한 이유가 바로 여기에 있습니다.

일반적인 동적 리사이즈 서버의 경우 요청할 때마다 리사이징 프로시져가 기동 되어야 하기 때문에 요청이 많아질 수록 어마어마한 연산 자원을 소모하며, 원본 이미지 업로드 시 마다 리사이즈된 이미지를 별도의 저장소에 저장하는 것은 향후 이미지 사이즈 정책 변경 시 유연하게 대처가 힘들고 업로드와 리사이즈 이미지 생성 시간 사이의 텀 동안 이미지를 사용할 수 없다는 치명적인 단점이 있습니다.

하지만 Lambda@Edge를 도입하면 두 가지 방식의 단점을 모두 커버할 수 있습니다. 모든 이미지는 첫 리사이징 과정을 거치기만 하면 CDN에 캐시가 되기 때문에 더 이상 리사이징 작업을 수행할 필요가 없고, 혹여나 나중에 이미지 사이즈가 변경되어도 그냥 캐시를 날려버리기만 하면 되니까요.

다만, Lambda@Edge를 사용하기 위해서는 몇 가지 제약 사항이 존재합니다.

  • Lambda@Edge의 Lambda 함수는 AWS의 us-east-1 (North Virginia) 지역에서만 생성이 가능합니다. 다만, 실제 Lambda 함수를 Lambda@Edge로 배포 시에는 Lambda 함수가 CloudFront가 존재하는 모든 AWS 리전으로 Replica Function의 형태로 전파되며, 이후 사용자가 CDN에 요청을 보내면 각 CDN 리전에 존재하는 Lambda 함수가 가동이 됩니다.
N. Virginia에 배포된 Lambda@Edge는 각 CF Region에 Replication됩니다.
  • 위에서 설명한 특성 때문에, Lambda 함수의 CloudWatch 값들은 함수를 생성한 us-east-1 리전이 아닌 각 CDN 호출이 이루어진 리전에서 확인이 가능합니다.
  • 바닐라 Lambda 대비 일부 기능이 제한됩니다.
  • 환경 변수를 설정할 수 없습니다.
  • 최대 실행 가능 시간이 30초로 제한됩니다.
  • 응답 시에 추가할 수 없거나, 원본 응답에서 수정할 수 없는 일부 Response Header들이 존재합니다.
  • Lambda@Edge로 수정된 HTTP Body를 보낼 경우, Body의 사이즈는 1MB 이하여야 합니다.

도모버스의 Lambda@Edge 활용법

도모버스 팀은 리사이징 Lambda를 설계할 때 다양한 이미지 포맷을 지원하는 것을 최우선으로 고려했습니다. 도모버스 팀이 개발 중 고려해야 하는 기기는 사용자 특성 상 저사양이거나 낮은 운영체제 버전을 가지고 있는 경우가 많았습니다. 디바이스 통계를 살펴보면 iOS와 Android 구성비 또한 고르게 분포되어 있는 상황입니다. 이런 상황이다 보니 차세대 이미지 압축 코덱 중 Android 10 이상에서만 지원하는 HEIF, iOS 14 이상에서만 지원하는 WebP 둘 중 하나만 지원하기가 불가능한 상황입니다.

이러한 점을 감안하여 현재 도모버스의 이미지 리사이징 Lambda@Edge는 WebP를 기본으로, WebP를 지원하지 않는 단말에서는 PNG를 불러올 수 있도록 설계되어 있습니다. 추후 이미지 압축 라이브러리로 사용하는 Sharp에서 HEIF를 지원할 경우 HEIF 지원 또한 추가할 예정입니다.

리사이징 람다로 실제 사용중인 코드의 일부를 첨부합니다. Node.js 14, TypeScript 기반으로 구성되어 있습니다.

Troubleshooting

  • Lambda@Edge의 Lambda 함수 실행 로그가 CloudWatch에 나타나지 않을 경우
  • 출시 직전까지 싸웠던 문제입니다. Lambda@Edge로 호출한 Lambda 함수의 실행 관련 메트릭을 CloudWatch 어느곳에서도 찾아볼 수 없는 문제인데요.
    원인은 Lambda에서 기본 제공하는 Role 이었습니다. Role에 할당된 AWSLambdaBasicExecutionRole-<UUID> 정책은 기본적으로 us-east-1의 CloudWatch에만 로그를 보낼 수 있도록 설정되어 있습니다. Resource ARN에 있는 us-east-1 구문을 * 로 수정하면 로그가 모든 리전에서 출력됩니다.

성능

일반 이미지 로딩 시. 약 442KiB의 사이즈 그대로 보내줍니다.

리사이즈된 이미지 최초 로딩 시. 779ms의 전송 속도로 약 52KiB 사이즈의 이미지를 전달합니다.

캐싱된 리사이즈 이미지 로딩 시. 25.7ms의 전송 속도를 보여줍니다.

성능 확실하구만!

그래서, 무엇이 좋아졌나요?

이미지의 사이즈를 매우 작게 줄여 저성능 및 네트워크 상태가 좋지 않은 환경에서도 안정적인 속도의 톺아보기 목록의 로딩이 가능해진 것 뿐만 아니라, Resource Origin, Edge Network와 사용자의 단말 간의 각 RTT (Round-Trip Time) 또한 매우 크게 줄어 인터넷 상에서의 성능 향상도 꾀할 수 있게 되었습니다.

비용 절감 또한 무시할 수 없는 요소입니다. 이미지 사이즈가 14%로 작아지니 CDN의 트래픽 비용도 85% 절감할 수 있게 됨은 물론, 사용자의 데이터 소모량도 큰 폭으로 절감할 수 있게 된 것이죠.

결론적으로, 성능 향상과 비용 절감, 두 마리 토끼를 모두 잡을 수 있게 된 것입니다.

--

--