
Amazon S3를 써보면서 처음 보는 로그들이다.
내용을 보니 메모리 누수가 생길 수 있고, 성능에 악영향을 줄 수 있는 요인들이 있는 듯하다.
배포서버는 메모리 용량이 작으므로 배포하기 전에 해결해야 할 문제로 보인다.
이 로그가 나오더라도 S3에 파일은 잘 올라간다.
업로드 할 때 메타데이터의 컨텐츠 길이 설정이 빠졌기 때문에 나오는 로그라고 한다.

콘텐츠 길이를 저장하지 않으면 전체 인풋 스트림을 버퍼에 넣어야 한다고 한다. 때문에 메모리 사용량이 증가한다. 파일이 메모리에 완전히 버퍼링된 후 업로드가 시작되므로 업로드 지연이 생길 수도 있다.
public String uploadReportsToS3(String name, String fileUrl, String date) throws IOException, InterruptedException {
try (InputStream inputStream = new URL(fileUrl).openStream()) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("application/pdf");
amazonS3Client.putObject(new PutObjectRequest(
bucketName,
key,
inputStream,
metadata
).withCannedAcl(CannedAccessControlList.Private));
return amazonS3Client.getUrl(bucketName, key).toString();
} catch (IOException e) {
log.info(fileUrl + "에러");
}
throw new RuntimeException();
}
현재 코드에선 콘텐츠 길이를 설정하는 부분이 빠져 있다.
@Retryable(retryFor = IOException.class, backoff = @Backoff(delay = 1000))
public String uploadReportsToS3(String name, String fileUrl, String date) throws IOException, InterruptedException {
String key = date + "/" + name + ".pdf";
if (amazonS3Client.doesObjectExist(bucketName, key)) {
return amazonS3Client.getUrl(bucketName, key).toString();
}
HttpURLConnection connection = null;
try {
URL url = new URL(fileUrl);
connection = (HttpURLConnection) url.openConnection();
int contentLength = connection.getContentLength();
try (InputStream inputStream = connection.getInputStream()) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("application/pdf");
metadata.setContentLength(contentLength); // 파일 크기 설정
amazonS3Client.putObject(new PutObjectRequest(
bucketName,
key,
inputStream,
metadata
).withCannedAcl(CannedAccessControlList.Private));
return amazonS3Client.getUrl(bucketName, key).toString();
}
} catch (IOException e) {
log.info(fileUrl + " 에러");
throw new RuntimeException(e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}
콘텐츠 길이를 위 처럼 설정해주어야 한다.

어떤 경고인지 확인하기 위해서 이 로그가 찍히는 Base64를 뜯어봤다.
static 블록에 있는 boolean available가 false라면 로그가 찍히는 것이다.
available이 false가 되는 경우는 리플랙션을 통해서 javax.xml.bind.DatatypeConverter 정상적으로 불러올 수 없을 때 인 것으로 보인다.
available이 true이면 마지막에 isJaxbAvailable = available에서처럼 isJaxbAvailable가 true가 된다.

Base64 클래스 내부에 있는 encodeAsString이다. isJaxbAvailable가 true이면 DatatypeConverter.printBase64Binary(bytes);가 실행된다. 그렇지 않으면 CodecUtils를 사용한다.
로그에 따르면,DataTypeConverter는 성능이 상대적으로 좋고 CodecUtils는 상대적으로 좋지 않다.
참고 : Java AWS SDK 성능 하락이 될 수 있는 문제
Jaxb 란 Java 에서 XML 을 Java Object 로 맵핑할 수 있게 도와주는 도구(tools)다.

AWS-SDK 내부에서 S3 Client 에서 Image 를 S3 로 올리는 과정에서 Base64 Class 의 함수를 이용할때 Jaxb 를 이용함을 알 수 있다.
JaxB를 사용하려면 implementation 'javax.xml.bind:jaxb-api:2.3.0' 라이브러리를 추가해주면 된다.