문제 해결 & 구현 기록

이미지 최적화 파이프라인 구축기 (1) - 문제 진단과 방법 선택

sangchu 2026. 3. 23. 23:48

들어가며

이전에 정적 이미지 최적화 방식을 다룬 글을 작성한 적 있다. 이번에는 사용자가 업로드한 이미지를 최적화한 경험을 정리해보려 한다.

 

이번 글에서는 LCP 7.6초라는 수치를 발견하고, 네 가지 최적화 방법을 비교해 S3 이벤트 기반 Lambda 방식을 선택하기까지의 과정을 다룬다. 이 작업을 통해 최종적으로 LCP를 7.6초에서 2.1초로 단축하고, Lighthouse Performance 점수를 70에서 90으로 개선했다.

 

문제 상황

모멘트는 사용자가 게시물에 텍스트와 이미지를 함께 업로드할 수 있는 SNS 커뮤니티 서비스다.

 

일부 사용자로부터 이미지 로드 속도가 느리다는 피드백을 받았고, 서비스 성능을 점검하기 위해 Lighthouse 측정을 진행했다.

수치로 확인해보니 문제는 생각보다 명확했다. Performance 점수는 70점이었고, 그 중 주요 콘텐츠가 화면에 보이는 시간(LCP)이 7.6초로 측정됐다.

Lighthouse 측정 결과

 

Google의 Core Web Vitals 기준에서 좋은 사용자 경험으로 분류되려면 LCP가 2.5초 이하여야 한다. 7.6초는 '나쁨' 구간으로, 사용자가 핵심 콘텐츠를 보기까지 상당한 시간을 기다려야 하는 상태였다.

출처: Google web.dev 문서

 

원인을 더 구체적으로 파악하기 위해 Network 탭을 확인했다. 이미지 리소스의 Content Download 시간이 약 633ms로, 다른 리소스(JS, 폰트)의 평균 약 50ms 대비 약 12배 길었다. 이미지 다운로드 구간이 LCP 지연의 주요 원인임을 파악했다.

 

 

모멘트는 이미지 중심의 SNS 서비스인 만큼, 이미지 로딩이 느리면 사용자는 핵심 콘텐츠를 확인하기 전까지 빈 화면을 봐야 하고 게시물 탐색 흐름이 끊긴다. 이는 서비스 품질에 직결되는 문제였다.

 

이에 따라 '사용자가 피드의 핵심 콘텐츠를 지연 없이 확인할 수 있도록 이미지 노출 성능을 개선한다'는 목표를 세웠고, 이미지 로딩 병목 진단 및 최적화 구조 설계·구현을 진행하였다.

 

문제 해결을 위한 조사

문제의 원인을 더 정확히 파악하고 해결 방향을 결정하기 위해 Lighthouse 분석 결과, AWS 공식 문서, 이미지 최적화 관련 기술 블로그를 참고했다.

 

원인 파악

Lighthouse는 이미지 다운로드 속도를 줄이기 위해 두 가지 개선 포인트를 제시하고 있었다.

 

(1)WebP와 같은 최신 이미지 포맷을 사용하면 다운로드 용량을 줄일 수 있다는 것, (2)화면에 필요한 크기보다 훨씬 큰 이미지가 그대로 전달되고 있다는 것이었다.

 

실제로 S3 버킷에 저장된 이미지를 확인해보니, 확장자는 jpg, png 등 제각각이었고 이미지 크기도 업로드된 원본 그대로 유지되고 있었다. 화면에 렌더링될 때 필요한 크기보다 훨씬 큰 데이터가 그대로 전송되고 있었던 것이다. 이것이 이미지 다운로드 구간이 길어지고, LCP가 7.6초까지 되는 직접적인 원인이었다.

 

S3 버킷에 저장된 이미지 목록

 

해결 방향 설정

사용자가 업로드한 이미지는 빌드 시점에 미리 최적화할 수 없다. 서비스가 운영되는 중에 동적으로 처리할 수 있는 계층에서 최적화를 진행해야 했다.

어느 계층에서 처리할지를 결정하기 위해 기존 업로드 구조를 유지할 수 있는지, 서버 부하 없이 처리할 수 있는지, 이미지 크기 제한 없이 안정적으로 처리할 수 있는지를 기준으로 네 가지 방법을 검토했다.

 

방법 A: 백엔드 서버에서 직접 처리

서버에서 이미지를 수신해 처리하는 방식으로, 이미지 처리 로직을 중앙에서 관리할 수 있다는 장점이 있다.

하지만 이 방식을 채택하면 이미지 데이터가 '클라이언트 → 서버 → S3' 경로로 두 번 전송되는 구조가 된다. 서버가 이미지 데이터를 직접 받아야 하기 때문에 네트워크 부담도 커진다. 우리 서비스는 서버 부하를 줄이기 위해 presigned URL 기반의 직접 업로드 구조를 사용하고 있었는데, 이 방식은 그 장점을 정면으로 훼손하게 된다.

 

방법 B: 클라이언트에서 S3 업로드 전 압축

browser-image-compression 같은 라이브러리를 활용하면 사용자가 이미지를 업로드하는 시점에 자동으로 압축을 수행할 수 있다. 서버를 거치기 전에 이미지 크기를 줄일 수 있어 전송 데이터 자체를 줄인다는 장점이 있다.

 

하지만 압축 작업이 사용자 기기에서 직접 수행되기 때문에, 저사양 기기에서는 압축 시간이 길어지면서 오히려 업로드 체감 속도가 느려질 수 있다. 또한 클라이언트 환경마다 결과가 달라질 수 있어 이미지 품질과 용량을 일관되게 관리하기 어렵다.

 

방법 C: CloudFront Lambda@Edge 기반 실시간 변환

CDN 레이어에서 요청 시점에 이미지를 변환하는 방식으로, 하나의 원본 이미지를 썸네일, 리스트, 상세 화면 등 다양한 크기로 유연하게 제공할 수 있다는 장점이 있다.

출처: AWS 공식 문서

 

하지만 Lambda@Edge는 응답 크기에 제한이 있다. 우리 서비스는 사용자가 업로드한 원본 이미지가 수 MB 이상이 될 수 있었기 때문에, 안정적인 처리를 보장하기 어려웠다. 또한 요청 흐름 내에서 처리되기 때문에 실패 시 사용자에게 직접 영향을 준다는 점도 부담이었다.

 

방법 D: S3 업로드 이벤트 트리거 → Lambda 비동기 처리 (채택)

앞선 세 방법은 각각 기존 업로드 구조를 훼손하거나, 결과의 일관성을 보장하기 어렵거나, 이미지 크기 제한이라는 구조적 한계가 있었다.

S3는 객체가 업로드되면 이벤트를 발생시킬 수 있고, 이를 트리거로 Lambda 함수를 실행할 수 있다. 이 방식은 기존 presigned URL 기반 업로드 흐름을 전혀 건드리지 않아도 되고, 이미지 처리가 사용자 요청 흐름과 완전히 분리되어 있어 실패해도 사용자 경험에 영향을 주지 않는다. 또한 이미지 처리 부하가 API 서버와 분리되어 있어 업로드량이 늘어도 서버 부담이 커지지 않는다.

 

세 가지 기준을 모두 충족하는 방식이었기 때문에 이 방법을 최종 선택했다.

S3 이벤트 기반 Lambda 설정 화면

 

정리 및 다음 단계

이번 글에서는 LCP 7.6초라는 수치로 문제를 진단하고, 네 가지 이미지 최적화 방법을 비교해 S3 이벤트 기반 Lambda 비동기 처리 방식을 선택하기까지의 과정을 다뤘다.

 

다음 글에서는 실제로 S3 이벤트와 Lambda를 연결해 이미지 최적화 파이프라인을 구현한 과정을 다룬다. Sharp 설정값을 어떻게 결정했는지, 재귀 트리거 방지와 fallback 구조를 어떻게 설계했는지도 함께 정리할 예정이다.

 

 

이미지 최적화 파이프라인 구축기 (2) - S3 이벤트 트리거 기반 Lambda 구현

들어가며지난 글에서는 LCP 7.6초라는 문제를 진단하고, 네 가지 방법을 비교해 S3 이벤트 기반 Lambda 비동기 처리 방식을 선택하기까지의 과정을 다뤘다. 이미지 최적화 파이프라인 구축기 (1) - 문

sanghee01.tistory.com

728x90