-
Notifications
You must be signed in to change notification settings - Fork 0
AWS S3 이미지 파일 Deflater 활용하여 압축을 통해서 JPG 기준 이미지 16.01% 크기 감소
김무건 edited this page Sep 11, 2023
·
8 revisions
sequenceDiagram
participant 사용자 as 사용자
participant Client as 클라이언트
participant Server as 서버
participant S3 as AWS S3
사용자->>Client: 회원 이미지 업로드 클릭
Client->>Server: 이미지 업로드 요청
Server->>Server: 이미지 압축
Server->>S3: 압축된 이미지 업로드
S3-->>Server: 업로드 성공 메시지
Server->>S3: 압축된 이미지 다운로드 요청
S3-->>Server: 압축된 이미지 다운로드
Server->>Server: 이미지 디코딩
Server-->>Client: 이미지 전달
Client-->>사용자: 이미지 성공 처리
public static byte[] compressImage(byte[] data) {
Deflater deflater = new Deflater();
deflater.setLevel(Deflater.BEST_COMPRESSION);
deflater.setInput(data);
deflater.finish();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] tmp = new byte[4 * 1024];
while (!deflater.finished()) {
int size = deflater.deflate(tmp);
outputStream.write(tmp, 0, size);
}
try {
outputStream.close();
} catch (Exception ignored) {
}
return outputStream.toByteArray();
}
public static byte[] decompressImage(byte[] data) {
Inflater inflater = new Inflater();
inflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] tmp = new byte[4 * 1024];
try {
while (!inflater.finished()) {
int count = inflater.inflate(tmp);
outputStream.write(tmp, 0, count);
}
outputStream.close();
} catch (Exception ignored) {
}
return outputStream.toByteArray();
}
public String uploadCompressedImage(MultipartFile file) {
if (file == null || file.isEmpty())
return "";
byte[] originalImageBytes;
try {
originalImageBytes = file.getBytes();
} catch (IOException e) {
log.error("Error reading multipartFile", e);
return "";
}
byte[] compressedImageBytes = ImageUtils.compressImage(originalImageBytes);
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID() + ".compressed";
log.info("uploadCompressedImage fileName: {}", fileName);
s3Client.putObject(new PutObjectRequest(bucketName, fileName, new ByteArrayInputStream(compressedImageBytes), null));
return fileName;
}
[문제점 및 이슈]
- 개발을 하면서 다른 서비스를 살펴보면 (ex. 이커머스, 쇼핑몰) 많은 사진을 처리를 한다. 이때 현업에서는 어떻게 이미지 및 파일을 처리하는지 궁금증을 가지게 되었음
- AWS S3는 높은 확장성을 가지고 있으나 파일의 크기와 이용에 따라 비용을 발생을 함.
- 최근 AWS 학습 및 서비스를 배포하면서 서버 비용이 발생하여 AWS 비용을 낮추기 위해 다양한 방식을 생각
[원인 분석]
- 기존의 파일 업로드는 Local의 파일의 속성 및 사이즈가 동일하게 업로드
- 압축, 압축을 푸는 과정에서 오버헤드가 발생할 수 있다고 생각함
- 이미지 확장자 JPG, GIF, GIF에 따라서 압축 효율이 차이가 발생
[해결 방안]
- 자바의 Deflater를 이용하여 이미지를 Compress를 하여 사이즈를 줄여 업로드
- 압축을 하여 파일의 무결성을 보장하기 위해 무손실 압출을 통해 데이터의 무결성 보장
- 압축 오버헤드를 고려하여 회원의 @OneToOne 부분에만 처리함.