이미지 렌더링 속도를 위한 선제적 대응: Pre-resizing 시스템 구축기

해상도별 이미지 사전 리사이징으로 사용자에게 더 빠른 페이지를 제공하기 위한 고민

March 16, 2025


이미지 리사이징 시스템 도입 배경

현재 운영 중인 민트스캔 서비스에서는 검증인(Validator) 이미지를 사용하고 있습니다. 아래 테이블의 형태로, 최대 200개의 이미지를 한번에 로드해야하는 상황이었습니다.

Example Image

검증인 이미지는 사내 GitHub 레포지토리를 통해 관리되고 있으며, 웹 브라우저는 물론 모바일 앱에서도 동일한 리소스를 공유합니다.

기존 이미지 관리 방식에는 여러 문제가 있었습니다. 우선 이미지 포맷이 제각각이고 크기도 통일되어 있지 않아, 플랫폼별로 일관된 UI를 제공하는 데 어려움이 있었습니다. 또, 실제 렌더링되는 이미지보다 훨씬 큰 해상도의 원본 이미지를 그대로 사용하다 보니, 페이지 로딩 시 불필요하게 많은 리소스를 로딩하게 되었고, 이로 인해 사용자는 더 많은 시간을 기다리게 되었습니다.

브라우저와 모바일이 요구하는 이미지 사이즈가 서로 다른 점도 문제였습니다. 같은 이미지를 다양한 크기로 사용하는 환경에서, 하나의 큰 이미지로 모두를 커버하는 방식은 최적화된 방법이 아니었습니다.

이러한 문제를 해결하고자, 클라이언트 환경에 맞게 이미지를 자동으로 리사이징해서 제공하는 시스템을 구축하기로 결정했습니다. 이 시스템은 단순히 리사이징된 이미지를 제공하는 것을 넘어, 사람이 직접 이미지의 크기나 포맷을 일일이 수정해야 하는 반복적인 작업을 제거하고, 전 과정을 자동화하는 것에 핵심 목적을 두고 있습니다.

이를 통해 다음과 같은 목표를 달성하고자 했습니다:

  • 플랫폼별 최적 해상도의 이미지를 제공하여 이미지 렌더링 속도를 향상하자!

  • 통일된 포맷 및 사이즈로 이미지를 관리하자!

  • 수동 리사이징 및 포맷 변경 업무를 자동화해보자!



🔄 리사이징 방식: 온디맨드 vs 사전 리사이징

이미지 리사이징 방식은 다음 두 가지를 비교하며 검토했습니다.

1. 온디맨드 리사이징 (On-Demand)

사용자 요청이 들어올 때마다 서버에서 이미지를 실시간으로 리사이징해 전달하는 방식입니다.

  • 장점

    • 다양한 요청 해상도에 유연하게 대응 가능
    • 불필요한 이미지 저장을 피할 수 있어 저장 공간 절약
  • ⚠️ 단점

    • 첫 요청 시 변환 작업이 발생해 응답 시간이 길어짐
    • 요청량이 많을 경우 서버 부하 증가
    • 동일 요청 중복 방지를 위한 캐시 로직 필요

2. 사전 리사이징 (Pre-Resize)

업로드 시점에 여러 해상도로 미리 리사이징하여 스토리지에 저장하는 방식입니다.

  • 장점

    • CDN 캐싱 및 빠른 응답 시간 확보 가능
    • 서버 부하 없음 (정적 이미지 제공)
  • ⚠️ 단점

    • 저장 공간 차지 증가
    • 고정된 해상도 외 요청에는 대응 불가

✅ 최종 선택: 사전 리사이징 방식

저희의 목표는 이미지의 빠른 로딩이었고, 필요한 해상도는 명확하게 정해져 있었습니다. 또한 스토리지 비용 부담이 크지 않다는 점에서 사전 리사이징 방식을 선택했습니다.



🧩 어떤 이미지 포맷을 써야할까?

리사이징한 이미지를 어떤 포맷으로 저장할지도 중요한 고민 포인트였습니다. 포맷별 특성을 정리해 보면 다음과 같습니다.

포맷장점단점
PNG

무손실 압축, 투명도 지원, 높은 호환성

파일 크기 큼
JPEG용량 작음, 빠른 로딩손실 압축, 투명도 미지원
WebP

고효율 압축, 투명도 지원, 빠른 로딩

일부 환경 미지원

WebP는 Google이 개발한 이미지 포맷으로, JPEG보다 최대 25~34% 더 작은 용량으로 비슷한 수준의 시각적 품질을 유지할 수 있습니다. PNG보다도 훨씬 작은 용량으로 투명한 배경(알파 채널)을 지원할 수 있기 때문에, PNG와 JPEG의 장점을 모두 아우를 수 있는 포맷입니다. 이러한 장점 덕분에 WebP는 성능 최적화 측면에서 매우 매력적인 포맷이지만, 해당 이미지는 모바일팀에서도 활용하고 있어 브라우저 호환성과 범용성을 고려해 PNG 포맷을 최종 선택했습니다.


🔧 Sharp를 활용한 리사이징 시스템 구현

Node.js 환경에서 이미지 변환을 위해 고성능 라이브러리인 **Sharp**를 선택했습니다. 다양한 포맷을 지원하며, 비동기 API와 빠른 처리 속도로 대량 이미지 처리에 적합했습니다.

주요 적용 코드

sharp(input)
	.resize(width, height, {
		fit: 'cover',
		withoutEnlargement: true, // 원본보다 확대 방지
	})
	.png({
		compressionLevel: 9, // 최대 압축
		quality: 80, // 품질 균형 설정
		adaptiveFiltering: true, // 압축 효율 향상
	});

이미지의 해상도와 용량은 반비례 관계입니다. 해상도를 높이면 선명도는 유지되지만 용량이 커지고, 용량을 줄이면 품질 저하가 발생합니다. 좋은 퀄리티를 유지하기 위해 해상도를 최대치로 한다면 용량이 함께 커지고, 이는 이미지 최적화 목적에 맞지 않습니다. 그렇다고 해상도를 크게 낮추어 용량을 챙기는 것도 무리입니다. 해상도와 용량간의 적합한 균형을 맞추는 것이 필요하다고 생각하였습니다.

  • compressionLevel: 9
    PNG의 압축 수준을 설정하는 옵션으로, 0은 압축하지 않음, 9는 최대 압축을 의미합니다.
    리사이징된 이미지는 대부분 정적이고 자주 변경되지 않기 때문에, CPU 사용량을 다소 감수하더라도 최대한 압축하여 저장 공간을 줄이는 방향으로 설정했습니다.

  • quality: 80
    PNG 포맷은 technically "lossless"이지만, 일부 필터 및 압축 처리 과정에서 내부적으로 품질 균형 조절이 가능하기 때문에 해당 옵션을 포함했습니다.
    80은 시각적으로 큰 손실 없이 용량을 줄일 수 있는 적정 수치입니다.

  • adaptiveFiltering: true
    PNG 포맷에서 사용되는 필터링 전략으로, 이미지 데이터에 따라 최적의 필터 방식을 자동 선택합니다.
    이미지마다 최적의 압축 방식을 적용할 수 있어, 전체적으로 용량을 줄이고 처리 효율을 높일 수 있습니다.

위 설정을 통해 시각적으로 선명한 이미지를 유지하면서도 파일 크기를 최소화하는 데 중점을 두었습니다.



🧵 마무리하며

이미지 최적화는 단순히 "보기 좋은" 이미지를 만드는 것을 넘어, 렌더링 성능과 사용자 경험을 개선하는 중요한 작업입니다.

사전 이미지 리사이징 작업을 통해 사용자에게 더 빠른 웹 경험을 제공하고, 반복적인 작업을 자동화함으로써 관리 포인트도 크게 줄일 수 있었습니다. 사용자 경험과 개발자 경험을 고려하며 더 나은 서비스를 만들어가기 위해 고민하고 공부하는 개발자로 성장해야겠다는 생각을 다시금 할 수 있었던 프로젝트였습니다 :)