문제 상황
현재 앱을 개발하는 과정에 있으며, 어느 정도 개발이 완료된 상황에서 테스트를 진행할 수 있게 됐다.
테스트를 진행하면서 가장 먼저 직면한 문제는 이미지 로딩 속도가 너무 오래 걸린다는 문제였다.
우리 앱에서 이미지를 로딩하는 부분은 크게 두 가지가 있었다.
1. 챌린지 설명을 위한 이미지 로딩
2. 사용자가 인증한 챌린지 인증 이미지 로딩
특히 위 이미지들은 사용자가 가장 많이 보는 화면에 위치하고 있기 때문에, 이미지 로딩 속도는 사용자가 느끼는 앱 사용성에 직결되는 문제였다.
즉, 이미지 로딩 속도를 개선하는 것은 현재 우리에게 있어 필수적인 사항이다.
해결 방법
이미지 로딩 속도 개선을 위한 방법에는 어떤 것들이 있을까?
다음은 이미지 로딩 속도 개선 방법에 대한 ChatCPT의 답변이다.
- 이미지 최적화: 이미지의 해상도나 크기를 줄여서 이미지 파일의 크기를 최소화합니다. 여러 온라인 도구나 라이브러리 (예: TinyPNG, ImageOptim)를 사용하여 이미지를 압축할 수 있습니다.
- 적절한 이미지 형식 선택: PNG, JPEG, GIF, WebP 등 다양한 이미지 형식 중 가장 효율적인 형식을 선택하세요. 예를 들면, 사진에는 JPEG가, 단순한 아이콘에는 SVG가 적합할 수 있습니다.
- Lazy Loading: 페이지에 많은 이미지가 있을 경우, 사용자가 스크롤하여 해당 이미지 영역에 도달할 때까지 이미지 로딩을 지연시킬 수 있습니다.
- CDN (Content Delivery Network) 사용: 사용자에게 이미지를 더 빨리 제공하기 위해 CDN을 사용하세요. CDN은 전 세계의 여러 위치에 데이터를 복제하여 사용자에게 가장 가까운 서버에서 콘텐츠를 제공합니다.
- 브라우저 캐싱 활용: 이미지에 캐시 헤더를 설정하여 브라우저에서 이미지를 캐싱하도록 할 수 있습니다. 이렇게 하면 사용자가 사이트를 다시 방문할 때 이미 로컬에 저장된 이미지를 재사용할 수 있습니다.
- 이미지 스프라이트 사용: 여러 개의 작은 이미지를 하나의 큰 이미지로 결합하고 CSS를 사용하여 필요한 부분만 보여줄 수 있습니다. 이렇게 하면 이미지를 여러 번 요청하는 대신 한 번의 요청만으로 여러 이미지를 로드할 수 있습니다.
- 적응형 이미지 (Responsive Images) 사용: 화면 크기나 해상도에 따라 다른 이미지를 제공합니다. 이를 통해 작은 화면의 디바이스에 큰 이미지를 보내는 것을 피할 수 있습니다.
- 프로그레시브 JPEG 사용: 일반적인 JPEG와 달리 프로그레시브 JPEG는 이미지의 전체 레이아웃을 먼저 표시한 다음 점점 선명하게 표시됩니다. 이로 인해 사용자는 이미지가 완전히 로드되기 전에도 이미지의 전체 형태를 볼 수 있습니다.
위와 같이 이미지 로딩 속도 개선을 위한 방법에는 FE, BE에서 처리할 수 있는 다양한 방식이 존재한다.
나는 다양한 개선 방법들 중에서도 현재 사용자가 핸드폰으로 촬영해 업로드한 사진의 용량이 매우 크다는 점을 문제로 삼아 이미지 최적화를 진행하기로 했다.
우리 앱에서는 이미지 해상도가 낮아진다고 해서 추가로 발생되는 문제가 크게 없다고 생각해서 이미지의 해상도가 낮아져도 괜찮을 것이라 판단했다. 실제 해상도를 낮춘 이미지를 테스트 서버에 적용해 비교했을 때도, 해상도 차이에 따른 불편함을 느끼진 못했다.
해결 과정
현재 Spring Boot를 통해 서버 개발을 하고 있어.
Java에서 주로 사용하는 이미지 최적화를 위한 라이브러리인 thumbnailator를 이용했다.
implementation 'net.coobird:thumbnailator:0.4.14'
이후 thumbnailator 라이브러리의 이미지 리사이징 함수를 이용하여 MultipartFile로 받아온 사용자의 이미지의 해상도를 낮춰주었다.
public InputStream resize(MultipartFile multipartFile, int width, int height) throws IOException {
try (InputStream originalInputStream = multipartFile.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
Thumbnails.of(originalInputStream)
.size(width, height)
.outputFormat("jpg")
.toOutputStream(outputStream);
byte[] resizedImageBytes = outputStream.toByteArray();
return new ByteArrayInputStream(resizedImageBytes);
}
}
결과
이미지 최적화의 효율을 비교하기 위하 동일한 이미지를 리사이징 전/후로 업로드 했다.
그 결과 이미지 리사이징 전에 S3에 업로드한 사진은 3.5MB, 이미지 리사이징 후의 사진은 67.1KB이다.
결과적으로 약 98% 이미지 용량이 감소 된 것을 확인할 수 있었다.
실제 성능 테스트를 통해서 클라이언트 상에서 로딩 속도에 대한 테스트를 하지는 못했지만, 여러 번 실행하고 눈으로 비교해본 결과 기존보다 1초 정도 개선된 것으로 확인했다.
아직 앱에서 로딩 속도가 얼마나 개선 됐는지, API 성능이 얼마나 개선 됐는지 등은 확인하지 못해 추후 확인해볼 예정이다.
'Java' 카테고리의 다른 글
[JAVA] 자바에서 SWAP 구현하기! (1) | 2024.07.03 |
---|---|
[JAVA] 자바 컴파일과 실행 과정에 대해 알아보자 (0) | 2024.07.02 |
[JAVA] compareTo()에 대해 알아보자(문자열, 숫자 비교) (1) | 2024.04.18 |
[JAVA] Hello World!! (0) | 2023.03.21 |
[JAVA] 클래스명과 파일명은 왜 같아야 하는가? (0) | 2023.03.21 |