S3에서 이미지를 제공하는 것이 충분하지 않을 때

발행: (2026년 1월 8일 오전 12:12 GMT+9)
14 min read
원문: Dev.to

I’m happy to translate the article for you, but I need the actual text you’d like translated. Could you please paste the content (or the portions you want translated) here? I’ll keep the source link at the top and preserve all formatting, markdown, and technical terms as requested.

Background

나는 7 년 전에 첫 블로그 글을 공개했습니다. Medium에서 약 1년 정도 글을 쓰다 Ready, Set, Cloud를 만들었습니다. 사이트가 대부분의 기간 동안 큰 외관 변화나 성능 업데이트 없이, 주로 내 글, 뉴스레터, 팟캐스트를 위한 공간으로 활용되었습니다.

나는 이 사이트를 6 년 동안 운영해 왔습니다. 보통은 오래 두고 못 보는 편이지만, 이 사이트는 수년간 거의 변함이 없었습니다. 잘 작동했지만… 어느 순간 작동을 멈췄습니다.

성능 문제

제가 마침내 사이트 성능을 살펴보았을 때, 눈에 띄게 명백한 것이 있었습니다: 이미지.

  • PageSpeed Insights는 크고 최적화되지 않은 이미지가 로드 시간을 지배하고 있음을 보여주었습니다.
  • 이미지는 S3에서 직접 단일 파일 형태로 제공되었으며, 포맷 협상 없음캐싱 없음 상태였습니다.

그 설정이 제가 만들었을 때 잘못된 것은 아니었습니다. 당시에는 간단하고 유지 보수가 적으며, 수십 명의 독자에게는 “충분히 좋음”이라는 합리적인 트레이드‑오프였습니다. 하지만 사이트가 콘텐츠와 독자 모두에서 성장하면서 성능에 대한 기대치가 바뀌었습니다. S3에서 그대로 원시 이미지를 제공하는 방식은 더 이상 통하지 않았습니다.

간단한 해결책만으로는 부족한 이유

즉각적인 반응은 S3에 들어가 여러 이미지를 수동으로 최적화하는 것이 될 것입니다. 이는 증상을 해결하지만 근본적인 문제는 해결하지 못합니다.

  • 이미지를 수동으로 리사이즈하고, 웹 친화적인 포맷으로 변환하며, 포스트당 어떤 크기를 업로드할지 결정하는 것은 확장성이 없습니다.
  • 나는 워크플로우를 바꾸고 싶지 않았습니다. 글을 쓰고, 게시하고, 다음 단계로 넘어가는 동안 성능 검증 단계를 추가하지 않고 진행하고 싶었습니다.

좋은 시스템은 다음을 해야 합니다:

  1. 백그라운드에서 이미지를 자동으로 최적화한다.
  2. 브라우저가 지원할 경우 WebP와 같은 최신 포맷을 제공한다.
  3. 모바일 기기가 데스크톱용 큰 자산을 다운로드하지 않도록 다양한 이미지 크기를 제공한다.
  4. 강력히 캐시 가능하도록 설계한다 — CDN은 이미 이미지 전달을 매우 효율적으로 해결하고 있다.

이미지 처리 재고하기

새로운 이미지 최적화 도구를 만들고자 했던 것이 아니라(과거에 그랬던 것처럼), 업계 표준 방식으로 최적화 결정을 중앙 집중화하는 것이 필요했습니다.

업로드 스크립트

저는 레포에 있는 작은 JavaScript 스크립트를 사용해 Ready, Set, Cloud에 이미지를 업로드합니다. 이 스크립트는:

  • 파일 접두사를 받습니다.
  • 로컬 폴더에서 일치하는 파일을 스캔합니다.
  • S3에 직접 업로드합니다.

웹 UI가 없으며 콘텐츠를 해석하려는 자동화도 없습니다—설계상 간단하게 유지하고 싶었기 때문입니다.

자동 처리

이미지가 이미 S3를 통해 흐르기 때문에, 워크플로를 전혀 바꾸지 않고도 업로드에 반응할 수 있습니다.

  • 이미지 업로드가 자동으로 Rust Lambda 함수EventBridge를 통해 트리거합니다.
  • Lambda가 원본 이미지를 WebP로 변환하고 표준 크기 몇 가지를 생성합니다.
  • 최적화된 버전은 원본과 같은 위치의 S3에 다시 기록됩니다.

장점

  1. 결정론적 최적화 – 모든 이미지가 매번 동일한 프로세스를 거칩니다.
  2. 핵심 경로에서 벗어나 작업 – 이 모든 작업이 비동기적으로 이루어지므로, 퍼블리싱이 지연되지 않습니다.

Source:

CDN 전달

처리 작업이 완료되면 다음 과제는 전달이었습니다. 모든 최적화된 자산은 이미 S3에 있었지만, 기존 콘텐츠에 포함된 2,000개 이상의 이미지 링크를 일일이 바꾸고 싶지는 않았습니다.

엣지에서의 콘텐츠 협상

해결책은 동작을 CDN으로 옮기는 것이었습니다.

  • CloudFront 배포가 S3 버킷 앞에 위치합니다.
  • Accept 헤더에서 WebP 지원 여부를 확인합니다.
  • 브라우저가 WebP를 지원한다고 선언하면, CloudFront Function이 요청 경로를 WebP 버전으로 재작성합니다.

이 함수는 viewer‑request 이벤트에서 실행되며, WebP 파일이 존재하는지 여부는 확인하지 않고 경로만 재작성합니다—파일 존재 여부 검사는 CloudFront가 원본에서 가져올 때 나중에 수행됩니다. 재작성은 엣지에서 일관되게 이루어지며, 결과 응답이 캐시되므로 이후 요청은 동일한 경로를 따르게 됩니다.

srcset으로 적절한 크기 제공

모든 이미지에 대해 여러 크기를 준비하면 다음과 같은 질문이 자동으로 떠오릅니다: 어떤 이미지를 제공해야 할까?

  • 모바일 화면은 데스크톱 크기의 이미지가 필요하지 않습니다.
  • 고해상도 디스플레이는 더 큰 이미지를 활용할 수 있습니다.
  • 홈 페이지의 썸네일은 가능한 한 작아야 합니다.

srcset 실제 사용 예

srcset을 사용하면 브라우저가 뷰포트와 디바이스 픽셀 비율에 따라 적절한 이미지를 선택합니다. 마크업은 그대로 유지되고, 런타임 로직이 없으며, 각 클라이언트는 실제로 필요한 것만 다운로드합니다.

![...](/images/diagram.png)

Ready, Set, Cloud는 Hugo로 생성된 정적 사이트입니다. srcset 지원을 추가하려면 render-image 훅을 오버라이드하고, 추가 속성을 만들기 위한 약간의 로직을 추가해야 했습니다.

결과

저의 주요 목표는 로드 시간을 단축하여 사이트가 빠르게 느껴지도록 기존 워크플로우에 아무것도 추가하지 않고 하는 것이었습니다.

  • 이미지 최적화 (Rust Lambda)는 업로드 시 자동으로 실행됩니다.
  • CDN 전송 (CloudFront + 엣지 함수)은 올바른 포맷과 크기로 제공되며 전 세계에 캐시됩니다.
  • **srcset**은 브라우저가 최적의 자산을 선택하도록 하여 수동 링크 업데이트의 필요성을 없앱니다.

그 결과, 기존에 사용해 온 동일한 간단한 퍼블리싱 프로세스를 유지하면서도 더 빠르고 확장 가능한 사이트가 됩니다.

성능 향상

IDE srcset을 추가했으며, 페이지 페이로드가 크게 감소한 것을 기쁘게 보고합니다. 페이지 렌더링 속도가 빨라지고, Largest Contentful Paint (LCP)가 개선되었으며, 전반적인 성능이 보다 예측 가능해졌습니다.

  • 홈페이지에서 **First Contentful Paint (FCP)**가 4.5 초에서 1초 미만으로 단축되었습니다.
  • 데스크톱과 모바일 모두에서 로드 시간이 훨씬 일관되게 유지되어, 지속적인 과제였던 문제를 해결했습니다.

SEO 보너스

예상치 못한 보너스는 이 동일한 변화들이 검색 엔진 순위에도 도움이 되었다는 점이다. 더 빠른 페이지, 더 작은 다운로드, 그리고 적극적으로 캐시된 자산은 모두 Core Web Vitals에 기여한다. 따라서 SEO를 명시적으로 목표로 하지 않았음에도 불구하고, 사이트는 크롤링이 더 쉬워지고, 인덱싱이 더 빨라지며, 사용자 경험을 우선시함으로써 검색 결과에서 더 높은 순위를 차지하게 되었다.

Common Bottlenecks

자신만의 블로그를 구축해 보았다면, 저처럼 이러한 성능 병목 현상을 겪어봤을 가능성이 높습니다. 그리고 괜찮습니다. S3에서 자산을 제공하는 것은 유효한 해결책이며, 사이트가 성장하면서 6년 동안 저에게 잘 작동했습니다.

시스템 확장

제 제약이 바뀌었을 때, 배포 워크플로우를 변경하지 않고 시스템을 확장하고 싶었습니다.

  • 여기서 설명한 동일한 개선 사항에 관심이 있다면, 이 설정은 기존 시스템에 바로 추가할 수 있는 형태로 Serverless Application Repository에서 제공됩니다.
  • 전체 소스는 자세히 살펴보거나 추가로 맞춤화하고 싶을 경우 GitHub에서도 확인할 수 있습니다.

일상 업무 흐름에서 의사결정 배제하기

무엇보다도, 이는 이미지 포맷, 크기 및 캐싱과 관련된 전체 결정들을 일상 업무 흐름에서 제외하는 것이었습니다. 모든 것이 갖춰지면 성능은 기본적으로 자동으로 향상됩니다.

마무리 생각

이것은 Ready, Set, Cloud에 대해 재미있으면서도 중요했습니다. 나는 도입하기 쉽고, 제거하기 쉬우며, 다른 모든 것이 그 주위에서 움직일 때 조용히 올바른 일을 해주는 무언가를 원했습니다.

행복한 코딩!

Back to Blog

관련 글

더 보기 »