AWS

우당탕탕 AWS 학습기 - S3, CDN서버 사용기

curiousKidd 2023. 11. 1. 11:54
반응형

회사 업무에서 AWS S3를 활용한 CDN 서버를 사용할 기회가 생겼습니다.
AWS 공부에는 순서가 없지만 S3를 사용해볼 수 있는 기회를 놓칠 수 없기에 S3를 급하게 작성하게 되었습니다
공부 내용이라기보단 사용 방법과, 곤란했던 경험들을 작성하였습니다.

아쉽지만 CDN 서버를 직접 구성해보진 못하였고, 업체를 사용하여 AWS를 사용하게 되었습니다.
업무에서 사용한 경험은 단순 S3의 접근 및 Upload, Download가 되었습니다.

기본적으로 AWS CDN 서버는 S3 서비스와 CloudFront를 같이 사용하여 구성하는 것으로 알고 있지만
이부분은 추후 블로그에 글을 남겨 링크를 첨부하겠습니다.

AWS SDK Version

Java 1.X 버전을 사용하였습니다.
버전선택시 가장 중요했던건 정보였습니다. 아직 V2보다는 V1의 정보가 많이 퍼져있었기에 보다 빠르게 사용하기 위해서 V1을 사용하였습니다.

도움 자료

AWS S3를 사용하기 위해서 가장 많이 본 사이트는 AWS Doc 였습니다.

Amazon S3란 무엇인가요?
멀티파트 업로드를 사용한 객체 업로드
AWS SDK를 사용하여 Amazon S3 버킷에 객체 업로드

등등 AWS Doc안에 충분한 정보가 있었고 이는 큰 도움이 되었습니다.

 

테스트 코드

1. putObject

objectMetadata.setContentLength(file.getSize());
objectMetadata.setContentType(file.getContentType());

//putObject(PutObjectRequest(), uploadDirectoryText, File)
s3Client.putObject(new PutObjectRequest(bucket, uploadDirectoryEnum.getDescription() + today + fileName, file.getInputStream(), objectMetadata)
    .withCannedAcl(CannedAccessControlList.PublicRead)); // 외부에 공개할 이미지이므로, 해당 파일에 public read 권한을 추가

s3Client를 확인해보시면 아시겠지만, putObject를 활용하는 방법에는 File을 사용하는 방법, objectMetadata를 사용하지 않는 방법도 존재합니다.

이러한 방법은 PutObject를 사용해서 직접 upload를 진행하는 방식입니다.

 

2. TransferManager를 활용

AWS는 TransferManager라는 기능을 제공하여 업로드, 다운로드를 보다 쉽고 빠르게 사용할 수 있게 합니다.
파일을 조각내어서 업로드하여 putObject를 직접적으로 사용하는 것보다 빠르게 처리가 가능합니다.

// AmazonS3 Client는 상황따라 다르기 때문에 참고만 부탁드려요
private AmazonS3 getAmazonS3() {
    AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
    AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(endpoint, region);

    return AmazonS3ClientBuilder.standard()
            .withCredentials(new AWSStaticCredentialsProvider(credentials))
            .withEndpointConfiguration(endpointConfiguration)
            .build();
}

 

단일 업로드의 경우 putObject를 직접 사용하는것과 크게 다르지 않습니다.

@Test
void S3_파일_단일_업로드_TEST() {
    try {
        AmazonS3 s3Client = getAmazonS3();

        TransferManager tm = TransferManagerBuilder.standard()
          .withS3Client(s3Client)
          .build();

        File file1 = new File("File 경로");

        final ObjectMetadata objectMetadata = new ObjectMetadata();

        Upload upload = tm.upload(bucket, UploadDirectoryEnum.STORE_ENTRY.getValue() + "test.jpg", file1);

        long start = System.currentTimeMillis();
        System.out.println("Object upload started = " + start);

        upload.waitForCompletion();
        long end = System.currentTimeMillis();
        System.out.println("Object upload complete = " + end);
        System.out.println("Object upload Time = " + (end - start));
        System.out.println("test = " + upload.getDescription());
    } catch (Exception e) {
          e.printStackTrace();
    }
}

 

TransferManager는 List, Directory의 Upload를 지원합니다.
이 기능을 사용할 때 putObject보다 빠른 응답시간을 확인 할 수 있습니다.

    @Test
void S3_파일_리스트_업로드_TEST() throws IOException {
    try {
        AmazonS3 s3Client = getAmazonS3();

        TransferManager tm = TransferManagerBuilder.standard()
                .withS3Client(s3Client)
                .build();

        File file1 = new File("File 경로");
        File file2 = new File("File 경로");
        File file3 = new File("File 경로");

        List<File> files = new ArrayList<>();
        files.add(file1);
        files.add(file2);
        files.add(file3);

        // uploadFileList(bucket, "AWS Directory Text", new File(AWS Directory 내부에서 저장될 DirectoryPath), files);
        // 이부분에서 큰 골치를 겪었습니다. 
        // new File() 이부분을 어떻게 써야하는지도 모르겠고 예시글은 다들 new File(".")만 되어있어서 어려웠습니다.
        // 밑에 자세히 적어놓을게요
        MultipleFileUpload upload = tm.uploadFileList(bucket, "AWS Directory", new File("."), files);
        long start = System.currentTimeMillis();
        System.out.println("Object upload started = " + start);

        upload.waitForCompletion();
        long end = System.currentTimeMillis();
        System.out.println("Object upload complete = " + end);
        System.out.println("Object upload Time = " + (end - start));
        System.out.println("test = " + upload.getDescription());
    } catch (Exception e) {
        // Amazon S3 couldn't be contacted for a response, or the client
        // couldn't parse the response from Amazon S3.
        e.printStackTrace();
    }
}

 

테스트 시간

// 해당 테스트는 200M 파일 3개 업로드 테스트 입니다.
// stream을 활용한 병렬기능을 사용한다면 시간적으로는 비슷해지지만 그래도 다중 업로드의 경우는 TransferManager 추천합니다.
## default
Object upload started = 1698736347577
Object upload complete = 1698736513047
Object upload Time = 165470

## parallel
Object upload started = 1698736596076
Object upload complete = 1698736653667
Object upload Time = 57591

## TransferManager
Object upload started = 1698736788717
Object upload complete = 1698736843335
Object upload Time = 54618

 

TransferManager의 장점

TransferManager의 가장 큰 장점은, 큰 파일을 분할해서 병렬로 업로드 처리를 한다는 것입니다.
사용자가 따로 무언가를 하지 않아도 자체적으로 해당 기능을 제공합니다.

putObjec의 경우 작은 용량의 파일을 업로드 하는것의 맞춰져있고 TransferManager대용량 파일의 업로드에 맞춰져 있는 것이 특징입니다.

또한 다중 업로드의 경우 업로드가 완료될때까지 기다려주는 기능이 있습니다. upload.waitForCompletion();
해당 기능을 사용하여 완료를 보장 받을 수 있습니다.

 

TransferManager 사용시 주의할 점

  1. 권한 오류
    업로드시에 Error Code: SignatureDoesNotMatc 이러한 오류가 발생할 수 있습니다.
    구글링을 해보면 권한이 없다는 비스무리한 내용의 오류라는것을 확인 할 수 있습니다.

다만 저의 경우는 업로드 하는 Path를 확인했어야 했습니다. Directory의 구분자가 연속적으로 2개가 붙어있을 경우에도 해당 오류가 발생합니다. EX) TEST /(빈공간)/ A.JPG

 

  1. 주의할 점

uploadFileList(bucket, "AWS Directory Text", new File(AWS Directory 내부에서 저장될 DirectoryPath), files);

List 업로드와 Directory의 업로드는 결과적으로 List 업로드를 사용합니다.
Directory업로드는 내가 업로드할 new File(Directory Path)를 사용하면 됩니다.

다만 List 업로드시에는 주의를 해야할 점이 있습니다.

 

저의 경우 업로드하는 파일은 C드라이브에, 프로젝트는 D드라이브에 있다보니 new File(".")을 사용하면 오류가 발생하였고 new File("./.")를 사용하면 업로드는 가능했으나, 내가 원치 않는 위치에 디렉토리명도 잘려서 저장되었습니다.

실제로 AWS안에 업로드 되는 위치는 다음과 같습니다.


AWS Directory Text + new File(AWS Directory 내부에서 저장될 DirectoryPath).subString(내가 업로드한 파일의 위치.length)

 

실제로 controller를 통하여 파일을 받을 경우 파일의 저장 장소는 tomcat/bin 위치이기 때문에
저는 new File("tomcat/bin")을 사용하여 제가 저장하고 싶은 위치에 저장될 수 있도록 하였습니다.

해당 내용을 참고하셔서 원하시는 위치에 저장하시길 바랍니다.

반응형