대충 넘어가지 않는 습관을 위한 기록

S3 최적화 - 이미지 리사이징

uhyvn 2025. 1. 22. 18:08

이전 포스팅

https://hyunco.tistory.com/78

 

S3 최적화 - WebP 변환 및 이미지 압축 적용기

이번에 새로운 서비스에 합류하게 됐는데,(문제 발생 당시) DAU 50명일 때 갑자기 월 S3 요금만 50만원이 발생했다는 소식을 들었다.-> 현재는 라즈베리파이로 이동해 있음. 명확한 해결은 없는 상

hyunco.tistory.com

 

 

이미 클라우드 프론트는 버킷에 연동한 후라서, 캐싱으로 인한 성능 개선은 따로 포스팅을 할 예정이다.

이번 글에서는 이미지를 Webp로 변환하는 과정에서 발생한 문제와 해결 방법에 대해 다루려고 한다.

 

 


 

 

 

  • 문제 원인

이전 트러블 슈팅의 이미지 Webp 변환 작업을 처리하면서 API 응답 시간이 지연되는 문제가 발생했다.

이는 서버가 변환 작업을 수행하는 동안 사용자의 요청을 기다리게 함으로써, 굉장히 부정적인 결과를 만들었다.

당연하겠지만 변환 과정에서 발생하는 높은 CPU 사용률과 메모리 소비가 서버 리소스를 소모하여 다른 요청 처리에도 영향을 미쳤을 것이다.

 

 

  • 개선 방법

Lambda@Edge와 CloudFront를 통한 이미지 변환을 계획했으나, 비용적인 측면에서 다른 서비스를 의존하는 것은 불가능했기 때문에, 서버 리소스를 절약할 수 있는 리사이징 방식을 적용하기로 했다.

 

  • 테스트 결과 (원본 이미지 사이즈 : 6000 * 4000, 용량 5.4MB)

  • 리사이징 없는 원본 파일
    • 변환 소요 시간: 4653ms
    • 원본 파일 크기: 5395.27 KB
    • 변환 후 파일 크기: 245.67 KB
    • 압축률: 95.45%
  • Thumbnails 메소드 리사이징
    • 변환 소요 시간: 1093ms
    • 원본 파일 크기: 5395.27 KB
    • 변환 후 파일 크기: 22.58 KB
    • 압축률: 99.58%
    • 응답 시간 단축률: 76.47%
  • ScaleToWidth 메소드 리사이징
    • 변환 소요 시간: 1143ms
    • 원본 파일 크기: 5395.27 KB
    • 변환 후 파일 크기: 21.86 KB
    • 압축률: 99.59%
    • 응답 시간 단축률: 75.48%
  • Max 메소드 리사이징
    • 변환 소요 시간: 1013ms
    • 원본 파일 크기: 5395.27 KB
    • 변환 후 파일 크기: 21.86 KB
    • 압축률: 99.59%
    • 응답 시간 단축률: 78.27%

 

 

 

  • 최종 결정

max 메소드, scaleToWidth, thumbnails 메소드는 모두 최대 크기 제한을 설정할 수 있어 이미지 품질을 유지하면서도 크기를 효율적으로 조정할 수 있는 방식이다.

때문에 각각 변환 작업을 진행한 후, 성능과 압축률을 비교했다.

 

테스트 결과 ImmutableImage.max()가 가장 빠르고 효율적인 변환을 제공했으며, 변환 시간과 파일 크기에서 우수한 성능을 보여주었다.

 

 

 

 

 


 

 

 

 

이미지 리사이징 적용 코드

    // WebP로 변환 + 리사이징 및 압축
    public File convertToWebpWithResize(MultipartFile file, String fileName) {
        try {
            File originalFile = convertMultipartToFile(file);
            File webpFile = new File(createDatePath() + "/" + fileName + ".webp");
            Files.createDirectories(webpFile.getParentFile().toPath());

            ImmutableImage.loader()
                .fromFile(originalFile)
                .max(1280, 1280) // 리사이징 추가
                .output(WebpWriter.DEFAULT, webpFile);

            return webpFile;

        } catch (Exception e) {
            throw new BaseException(ErrorCode.S3_UPLOADER_ERROR);
        }
    }

 

 

 

 

사실 성능이 더 좋은 cover 메소드도 있었지만, 그건 고정 크기로 제한하는 방법밖에 없어서, 만약 고정 크기와 비율이 다른 파일을 업로드 할 때 이미지 일부가 날라가는 문제가 생겼었다.

그건 사용자가 원하지 않는 방식일 것 같아, 테스트 대상에서 제외했다.

 

 


 

 

 

결과는 라이브러리 코드 한 줄의 차이로 리사이징이 추가되어 성능이 개선되긴 했지만,

아직 Lambda@Edge와 CloudFront를 통한 이미지 변환 작업 처리는 미련이 남는다..

이후에 조금 더 알아보고, 비용 최적화를 할 수 있다면 적용해보고 싶다.