S3 Transfer Acceleration 활용하기
S3 Transfer Acceleration을 활용하여 파일 업로드/다운로드 속도를 향상시킨 경험과 글로벌 서비스 적용 시 고려사항을 소개합니다.
Contents
배경
사내에서 유저의 파일 업로드/다운로드 시 AWS S3 의 signed url 을 사용하였다. 기능을 완성한 후 라이브에 배포하였고, 업로드/다운로드 기능은 정상적으로 동작하였다. 그런데, 파일 업로드 시간이 너무 오래 걸린다는 VOC 가 들어왔다. 이 글은 해당 이슈를 해결하는 과정을 정리하는 글이다.
현상
VOC 인입된 것을 확인하고, 서버 로그를 살펴보고 큰 파일을 업로드하는 테스트를 진행해 보았다. 하지만, 파일 업로드는 매우 빠르게 잘 동작하였다. 또한, 다른 유저들로부터는 이와 같은 현상을 제보받지 못했다. 이 유저의 네트워크 대역폭이 문제였던 것일까? 하지만 해당 유저는 네트워크의 동작에 대해서는 잘 아는 분이었다. 개발 강의를 업로드하는 과정에서 이와 같은 현상이 발생했으니, 로컬 PC 의 네트워크 문제라면 유저가 이미 알아챘을 것이라고 생각했다. 무엇이 문제였을까 ?
그러던 도중, HTTP 요청 헤더에서 유의미한 정보를 얻을 수 있었다. Amazon Cloudfront 문서 를 확인해 보면, 요청을 보낸 유저의 위치 정보를 대략적으로 확인할 수 있다.

AWS Cloudfront > Headers for determining the viewer's location
유저에게 확인해 보니, 미국에서 서비스를 이용중이셨다. 사내 서버는 AWS 의 서울 리전을 이용하고 있었으므로, 패킷들이 수많은 네트워크 홉들을 지나면서 오랜 시간이 지났을 것이다. 그렇다면 해외 유저의 경우, 어떻게 하면 빠른 서비스를 제공할 수 있을까 ?
해결방안
역시 AWS 답게, 이러한 상황에서도 쉽게 이슈를 해결할 수 있었다. AWS S3 는 S3 Transfer Acceleration 라는 기능을 제공한다. AWS 는 어떻게 물리적으로 멀리 떨어져 있는 네트워크 패킷을 빠르게 보낼 수 있는 것일까 ? AWS 는 다음과 같은 방식으로 전송을 최적화한다.
- Transfer Acceleration 을 이용하면, S3 업로드시 파일 업로드를 진행하는 Endpoint URL 이 가속화된 Endpoint 로 변경된다.
 - 유저가 파일을 업로드/다운로드시, 유저는 가깝게 위치한 엣지 로케이션으로 데이터를 전송한다.
 - 엣지 로케이션으로 전송된 데이터는 AWS 의 최적화된 백본 네트워크를 통해 도착지까지 전송된다.
 
다만 Transfer Acceleration 은 별도의 설정을 해야 하며 추가적인 비용이 발생하므로, 유념하여 사용해야 한다.
다음은 CLI 를 통해 Transfer Acceleration 을 간단히 설정해 보는 예제이다.
-- S3 버킷에서 Transfer Acceleration을 활성화합니다. AWS Management Console, AWS CLI, 또는 SDK를 사용하여 이러한 작업을 할 수 있습니다.
aws s3api put-bucket-accelerate-configuration --bucket <bucket_name> --accelerate-configuration Status=Enabled
-- S3 버킷에 업로드시, 가속화된 Endpoint 를 사용하도록 설정합니다.
aws s3 cp myfile.txt s3://<bucket_name>/ --endpoint-url https://<bucket_name>.s3-accelerate.amazonaws.com
각 언어의 SDK 를 사용하는 경우, S3 Client 를 생성할 때 Transfer Acceleration 옵션을 사용할 수 있다.
다음은 Typescript(Node.js) 를 통해 가속화된 S3 Client 를 생성하는 예제이다.
import { S3, S3ClientConfig } from '@aws-sdk/client-s3';
const option = {
  region: 'ap-northeast-2',
  /* 
   * Transfer Acceleration 을 사용하면, 
   * 최적화된 Endpoint 를 사용해야 하므로, 
   * Custom Endpoint 는 이용이 불가하다. 
   */
  // endpoint: '',
  useAccelerateEndpoint: this.useAccelerateEndpoint,
} satisfies S3ClientConfig;
const s3 = new S3(option);
  이러한 간단한 조치만으로, 고객님의 문제를 쉽게 해결할 수 있었다. 사내 서비스가 글로벌 확장을 계획하고 있는데, 글로벌 서비스 사용시에는 이런 문제가 더 많이 발생할 것으로 예상된다. 간단한 해결을 위해서는 S3Client 를 모두 Transfer Acceleration 을 사용하면 되지만, 위에도 언급했듯이 비용이 많이 청구될 수 있다. 따라서, 유저의 위치 정보를 바탕으로 국내용/해외용 S3Client 를 생성하여 사용하는 것도 좋은 방법이 될 것이다. S3ClientFactory 혹은 S3ClientProxy 등을 생성하여 사용하면 쉽게 구현할 수 있을 것 같다.
아래는 간단한 수도코드이다.
import { S3, S3ClientConfig } from '@aws-sdk/client-s3';
type S3ClientType = 'domestic' | 'foreign';
/**
  * 미리 S3Client Bean 들을 Singleton 으로 생성해 둔 후,
  * 업로드시 필요한 Client 를 골라서 사용
  */
export class S3ClientProxy {
  private readonly domesticS3Client: S3Client;
  private readonly foreignS3Client: S3Client;
  ...
  async upload(type: S3ClientType, file: any): Promise<void> {
    switch(type) {
      case 'domestic':
        return await this.domesticS3Client.upload(file);
      case 'foreign':
        return await this.foreignS3Client.upload(file);      
    }
  }
}
/**
  * 원하는 타입의 S3Client 를 직접 생성하여 사용
  */
export class S3ClientFactory {
  static create(type: S3ClientType, option: S3ClientConfig) {
    const useAccelerateEndpoint = type === 'foreign';
    return new S3({
      ...option,
      useAccelerateEndpoint,
    });
  }
}
            
            이것도 읽어보세요