Skip to content

[트러블 슈팅] 이미지 렌더링 속도 개선을 위한 리사이징

hyeji edited this page Apr 7, 2022 · 5 revisions

1️⃣ 이미지 리사이징이 필요했던 이유


주문제작 케이크에 관한 서비스인만큼 서비스 곳곳에서 이미지를 많이 띄우게 된다.
이 때 이미지 렌더링 바로 되는 경우도 있었지만 유난히 느리게 렌더링되는 경우도 종종 있었다.
사용자 입장에서는 당연히 부정적인 경험이어서 해결방법을 찾기로 했다.

개발자 도구를 열어 네트워크 탭을 살펴보니 Content Download 부분에서 많은 시간이 소요됐다.
그리고 시간이 오래 걸리는 이미지들을 보니 2MB가 넘는 파일들도 많았다.
사용자가 올린 리뷰 사진이나 팀원들이 모아온 케이크 매장에서 올린 케이크 사진들 모두 핸드폰으로 찍어서 올린 사진들이어서 이렇게 큰 용량을 가지고 있었다.

하지만 우리가 보여줄 사진은 이렇게 작은 사진이었기 때문에 원본 파일을 그대로 렌더링 하는 것은 너무 큰 낭비라는 생각이 들었다.
그래서 미리보기용 사진으로 쓰일 썸네일 이미지를 생성하기로 했다.


2️⃣ 해결 과정

상세페이지에서는 큰 사진이 떠야 하므로 원래의 사진 파일도 필요하다.
그래서 사진이 전달되면 전달받은 사진 파일을 그대로 저장하고, 추가적으로 썸네일도 생성해서 저장하기로 했다.
즉 하나의 파일을 전달받아 두 개의 사진을 저장하는 것이다.

썸네일 이미지를 생성할 때는 이미지 크롭과 리사이징을 편하게 할 수 있도록 도와주는 Thumbnailator 라이브러리를 이용해
먼저 1:1 정사각형 모양으로 크롭해준 뒤에 200*200 사이즈로 줄이기로 했다.


// 크롭 사이즈 정하기
BufferedImage originalImage = ImageIO.read(multipartFile.getInputStream());
int width = originalImage.getWidth();
int height = originalImage.getHeight();
int cropSize = min(width,height);

if (cropSize < size) {
    size = cropSize;
}

// 정사각형으로 크롭하고 사이즈 줄이기
BufferedImage resizedImage = Thumbnails.of(multipartFile.getInputStream())
        .sourceRegion(Positions.CENTER, cropSize, cropSize)
        .size(size,size)
        .asBufferedImage();

// 이미지 쓰기
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(resizedImage, ext, os);

사용자가 등록하는 리뷰사진이나 프로필 사진등은 이렇게 저장 로직에 썸네일 저장 메소드를 추가해서 해결했다.

하지만 이미 저장된 5000여개의 케이크들도 썸네일 이미지가 필요했다.
그래서 디비에 저장되어 있는 이미지 url로부터 이미지 stream 받아와 썸네일 이미지를 생성해 저장하는 메소드도 추가적으로 만들고 실행해줬다.
이렇게 해서 모든 사진이 썸네일 이미지를 갖게 되었다.


3️⃣ 적용 결과

이미지가 54개씩 렌더링되던 케이크 탭에서는 눈에 띄게 속도가 빨라졌다.
캐싱이 안된 이미지를 대상으로 테스트해봤을 때 한번 렌더링하는데 평균적으로 5초가 소요됐는데
썸네일 이미지로 바꾸고 나니 500ms 즉 0.5초로 확 줄었다.

(전)


(후)


홈탭에서도 원본 이미지를 내려주던 속도에 비해 80%나 단축시키는 결과를 얻어냈다.



4️⃣ 추가적인 해결 방안

이미지를 읽고 쓰는 작업은 일반적인 CRUD에 비해 시간이 좀 더 걸리는 작업이다.
실제로 postman으로 테스트를 했을 때 이미지를 업로드할 때 확실히 시간이 더 많이 걸렸다.
이런 이미지 저장 과정이 총 두 번 일어나게 돼서 전보다 저장 시간이 늘어난 것이 마음에 걸려 검색을 해보다가 aws 람다를 이용해 썸네일 이미지를 생성하는 방법이 있다는 것을 알게 됐다.

aws 람다는 서버를 관리하지 않고도 코드를 실행하게 해주는 컴퓨팅 서비스이다.
한마디로 서버리스 컴퓨팅 서비스이다.
람다에 썸네일 이미지 생성 코드를 올려놓고 s3에 putObject 이벤트가 발생할때마다 실행되도록 설정할 수 있었다.
이러면 서버는 전달받은 이미지를 저장하는 일만 하고 부가적이 썸네일 생성 업무는 람다가 하게 된다.

프로젝트 막바지에 알게 돼서 적용은 하지 못했지만 꼭 썸네일 생성이 아니더라도 람다를 유용하게 사용해보면서 서버리스 컴퓨팅의 이점과 필요한 시점등을 자세히 공부해나가고 싶다.


5️⃣ 참고자료

[JAVA] 이미지 리사이즈, 썸네일 만들기 - Thumbnails.of

Java로 썸네일(Thumbnail) 이미지 만들기