Amazon S3 경고 로그 "No content length", "JAXB is unavailable"

Alex·2024년 8월 30일

GenAI해커톤

목록 보기
5/9

Amazon S3를 써보면서 처음 보는 로그들이다.
내용을 보니 메모리 누수가 생길 수 있고, 성능에 악영향을 줄 수 있는 요인들이 있는 듯하다.

배포서버는 메모리 용량이 작으므로 배포하기 전에 해결해야 할 문제로 보인다.

No content length specified for stream data.

이 로그가 나오더라도 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();
           }
       }
   }
}

콘텐츠 길이를 위 처럼 설정해주어야 한다.

JAXB is unavailable. Will fallback to SDK implementation which may be less performant.If you are using Java 9+, you will need to include javax.xml.bind:jaxb-api as a dependency.

어떤 경고인지 확인하기 위해서 이 로그가 찍히는 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' 라이브러리를 추가해주면 된다.

profile
답을 찾기 위해서 노력하는 사람

0개의 댓글