Regular Motion

개발자가 상팔자

Category: aws (page 1 of 3)

AWS S3 Transfer Accelerator

AWS의 S3는 Static한 파일을 저장/배포하기에 매우 훌륭한 저장소지만, 버킷의 Region이 접속지역과 멀리 떨어진 경우 응답시간과 전송시간 모두 사용자들의 인내심을 테스트하게 만드는 단점이 있다. 사실 다운로드의 경우 CDN(CloudFront)을 이용해 개선 할 수 있지만, 업로드는 방법이 없다.

현재 회사에서 운영중인 서비스는 유럽에 위치한 주요 고객(이라 적고 갑이라 읽는다)을 위해 대부분의 버킷을 eu-west-1에 위치시키고 있다.  eu-west-1의 버킷의 경우 100KB의 파일을 업로드/다운로드하는데 1~3초, 5MB 정도의 파일은 수십초가 소요된다.  (편리함의 대가로 시간을 지불하고 있었던 것이다).

매일같이 시간을 지불하고 있던 어느날, S3에 Transfer Acceleration을 활용하면 적게는 2~3배에서 많게는 10배 정도 업로드/다운로드 속도가 빨라진다는 글을 접하게 됐다.  평소 의심이 많고, 두눈으로 보기전엔 믿지 않는 분들은 AWS에서 제공하는 속도비교 페이지에 접속해보시기 바란다.  7번 정도 확인을 해봤는데 eu-west-1의 경우 6~21배 정도 속도차이가 있었다.

이제 Transfer Acceleration의 효과를 봤으니, 1) 속도 개선이 어떻게 이루어지고 2) 적용 방법은 어떻게 되며 가장 중요한 그래서 3) 얼마를 더 내야 되는지 알아보자.

Overview

공식 설명은 ‘S3 Transfer Acceleration은 AWS S3로 데이터를 전송 할 때, AWS의 Edge 인프라와 네트워크 프로토콜을 최적화하여 전송 속도를 개선하는 기능’ 이라고 되어 있습니다.

사용자가 S3 Bucket에 데이터를 전송 할 때, 직접 Origin 서버로 전송하는게 아니라 AWS의 Edge 인프라를 활용하여 사용자는 가장 가까운 Edge 서버로 데이터를 전송하고, Edge 서버에서 Origin 서버로 최적화된 네트워크 프로토콜과 전용회선을 활용하여 데이터를 전송함으로써 속도를 개선합니다. 그림으로 표현하면 아래와 같습니다.

Before

After

자칫 복잡해 보일 수 있는 아래의 방식이 5~10배 이상 빠르다는건 Edge 서버와 S3 사이의 네트워크 프로토콜과 데이터 이동이 최적화되었다는 반증일겁니다. 실제로 Edge 인프라를 활용하기 위해 Transfer Acceleration을 사용하는 요청은 Endpoint가 기존과 다릅니다.

  • Original Endpoint: https://{your-bucket}.s3.amazonaws.com/
  • Accelerated Endpoint: https://{your-bucket}.s3-accelerate.amazonaws.com/

 

버킷에서 Transfer Acceleration 설정

Transfer Acceleration은 Bucket 레벨에서 적용할 수 있는 기능이기 때문에, 적용을 원하는 버킷의 속성에서 Transfer Acceleration을 활성화(Enable)해주면 됩니다.  활성화 방법은 아래 세가지 방법 중 평소 본인이 흠모하던 방법으로 하시면 됩니다. 자세한 방법은 링크를 참고하시는게 글을 쓰는 사람과 읽는 사람 모두의 정신건강에 이로울 것 같아 링크로 대체합니다.

Transfer Acceleration 활용

아쉽게도, 버킷에서 Transfer Acceleration 속성을 활성화하는 것으로 갑자기 빨라지는 건 아니고, 버킷에 파일을 업로드/다운로드를 하는 부분도 약간의 수정을 해야 합니다. SDK를 사용하고 있었다면 Flag를 활성화하는 수준이고, REST API를 사용하고 있었다면 Endpoint를 대체하는 수준으로 가능합니다. (역시나 우리 모두의 정신 건강을 위해 링크로 대체합니다)

Transfer Acceleration 비용

저장 비용에는 변화가 없으며, Transfer Acceleration을 이용한 전송에 추가 비용이 발생합니다. GB당 추가로 $0.04가 부과됩니다. (스벅에서 카페라떼 한잔을 참으면 약 100GB를 빠르게 전송 할 수 있습니다. 반대로 100GB를 느긋하게 전송하면 카페라떼를 한잔 사먹을 수 있습니다)

Benchmark Test

평소 의심이 많던 저는 AWS의 속도 비교 페이지를 온전히 믿지 못하고, 직접 벤치마크 테스트를 해봤습니다. 아래 표는 eu-west-1 버킷에 CLI를 이용하여 파일을 업로드/다운로드한 결과입니다. 파일의 크기가 크면 클수록 속도 개선이 드라마틱하게 이루어짐을 알 수 있습니다. 15MB 정도되는 파일의 경우 평균 43초 정도 소요되던 다운로드 속도가 4.7초로 개선된 것을 확인 할 수 있습니다.

 

주의사항
  • 설정 후 반영까지 최대 30분정도가 소요 될 수 있습니다.

[AWS] Delivery Dynamic Content through CloudFront

회사에서 운영 중인 대부분의 서비스들의 웹서버가 AWS의 Elastic Beanstalk로 구성되어 있다. 기존에는 Beanstalk에 직접 DNS를 설정하여 운영중이었는데 WAF(Web Application Firewall) 구성을 위해 Beanstalk 앞에 CloudFront를 연동 한 뒤, TTL(Time to live)을 0으로 설정하여 매번 원본 저장소에서 콘텐츠가 전송되도록 설정했는데도 서비스가 빨라진 느낌적인 느낌을 받았다.

빨라진 느낌을 객관화하기 위해 CloudFront 연동 전/후 서비스의 페이지 로드 시간과 API Latency를 테스트 했는데 약 1.6배 정도 속도 향상이 있었다.  TTL을 0으로 설정했는데도 빨라진 이유는 ‘Edge 서버와 Origin 서버가 AWS 내부망으로 연결되어 있어 더 빠르겠지’ 하는 막연한 추측만 갖고 있었다.
* CloudFront 연동 전/후의 속도 차이는 테스트 환경과 Origin 서버의 지리적인 거리에 직접적인 영향을 받기 때문에 차이가 발생 할 수 있습니다. 저는 Ireland에 구축된 웹서버를 기준으로 테스트 했습니다.

나의 막연한 추측을 기술적으로 설명해주는 2개의 글을 읽고, 페이지 로드 시간이 빨라진 이유를 이해하게 됐다.

글에서 설명하는 이유를 정리하면 아래와 같다.

요청에 대한 응답 시간은 크게 4가지 요소의 합이다.
응답 시간 = DNS Lookup + TCP Connection + Time to First Byte + Content Download

  • CloudFront의 Edge 서버와 Origin 서버는 Keep Alive Connection을 통해 연결을 유지 및 재사용하기 때문에 TCP 3-way handshake 과정에서 SYN, SYN-ACK, ACK 과정을 생략 할 수 있는 경우가 많다.  지리적으로 거리가 떨어진 경우 높은 RTT(Round-Trip Time)로 인해 위의 SYN, SYN-ACK, ACK 과정의 생략을 통해 얻을 수 있는 속도 향상이 크다. Edge와 Origin과의 Keep Alive Connection을 통한 속도 향상은 TTFB(Time to First Byte) 시간의 감소로 확인 할 수 있다.
  • Gzip 압축을 통해 실제 전송되는 컨텐츠의 크기를 줄임으로써 Content Download에 필요한 시간을 줄일 수 있고, 비용도 절감 할 수 있다.
  • AWS Edge 서버와 Origin 서버 사이의 네트워크는 고성능 및 가용성을 유지함으로써 Content Download에 필요한 시간을 줄일 수 있다.
  • CloudFront의 최적의 라우팅 기술이 Route 53의 LBR(Latency Based Routing)과 통합되어 DNS Lookup 시간을 단축 할 수 있다.

 

결론

  • CloudFront의 Cache 기능을 사용하지 않는다고 하더라도 CloudFront 연동을 통해 1.6~1.8배 사이의 성능 향상을 기대 할 수 있다.
  • CloudFront에서 L3/L4 Flood Attack을 방어해주기 때문에 설정하는 것 만으로도 DDoS 방어 효과가 탁월하다.
  • CloudFront + WAF 구성을 통해 일반적인 웹 취약점 공격으로부터 보호하는 데 도움이 된다.
  • CloudFront의 gzip 옵션을 통해 전송되는 콘텐츠의 사이즈를 줄여 비용을 절감 할 수 있고, 콘텐츠 전송 속도를 줄일 수 있다.
  • GB당 컨텐츠 전송 비용은 설정 전/후 큰차이를 보이지 않는다. 다만 텍스트와 같이 gzip 옵션을 통해 높은 압축 효과를 기대 할 수 있는 콘텐츠의 경우는 비용 절감 효과도 기대 할 수 있다.
  • 속도와 보안 두마리 토끼를 잡을 수 있으니 CloudFront를 설정하지 않을 이유가 없다.

[AWS] Lambda to generate thumbnails

사용자가 업로드한 이미지를 다양한 용도로 재사용하는 앱을 개발하다보면,

업로드한 이미지에 대해 다양한 사이즈의 Thumbnail을 필요로 하게된다.

따라서 서버는 클라이언트가 업로드한 고해상도 이미지에 대해 여러벌의 Thumbnail을 자동생성해야되는 경우가 발생한다.

하지만 이미지 프로세싱이라는게 CPU와 메모리를 동시에 많이 필요로하는 작업이라,

동시간대에 다수의 사용자가 이미지를 업로드하기 시작하면 서버가 감당하기 어려울 것이다.

그래서 좋은 방법이 없을까 검색을 하다보니, AWS의 Lambda라는 서비스가 위와 같은 상황에서 좋은 해결책이 될 수 있을 것 같다.

(* Lambda는 데이터 트리거 또는 예약된 시간에 원하는 작업을 수행할 수 있는 AWS 서비스다.)

 

아래 그림을 보고 Lambda를 이용해 업로드되는 이미지의 Thumbnail을 자동생성하는 방법을 알아보자.

1. 사용자가 Source Bucket에 이미지를 업로드한다.

2. AWS S3는 ObjectCreated 이벤트를 감지한다.

3. AWS S3에 등록된 Invocation Role은 등록된 Lambda 함수를 호출한다.

4. Lambda 함수의 Execution Role을 통해 Lambda 함수를 실행한다.

5. Lambda 함수는 원본 이미지를 다운로드한 뒤, Thumbnail을 생성하여 Target Bucket에 업로드한다.

 

생각보다 간단하게 AWS의 S3와 Lambda 함수를 이용하여 원본 이미지가 업로드 될 때, 자동으로 Thumbnail을 생성하도록 설정할 수 있다.

다만 현시점(2015.03)에서 아쉬운 부분은 현재 Lambda를 지원하는 Region이 Oregon과 Verginia, Ireland 뿐이라는 사실이다.

물론 Cloud front를 통해 다운로드에 대해서는 속도를 빠르게 가져갈 수 있다.

 

실제 AWS Console에서 수행해야 할 To Do List를 적어보면 아래와 같다.

1. Source Bucket과 Target Bucket을 생성한다. (* Lambda 함수와 동일한 Region에 위치해야 한다.)

2. Invocation role을 생성한다. (* S3 Source Bucket에 부여하기 위해 필요하다.)

3. Execution role을 생성한다. (* Lambda 함수에 부여하기 위해 필요하다.)

4. Lambda 함수를 생성한다. Lambda 함수를 생성하는 방법은 아래 링크에 자세히 나와있다.(* http://docs.aws.amazon.com/lambda/latest/dg/walkthrough-s3-events-adminuser-create-test-function.html)

5. Source Bucket에 Event Notification을 활성화한다.(* http://docs.aws.amazon.com/AmazonS3/latest/UG/SettingBucketNotifications.html)

 

위의 순서대로 진행 한 뒤, 문제가 있으면 CloudWatch의 로그를 참조하면서 문제를 해결해야 한다.

 

[CloudFront] Distribute privately.

AWS에서 Static한 Data를 Service 할 때 S3를 가장 많이 이용한다.

그리고 S3에 업로드된 파일을 Globally distribute 할 때는 CloudFront를 사용하여, Latency를 낮추고, Data transfer 속도는 높인다.

여기에 하나의 요구사항이 더 추가될 수 있다. Access Control!!

즉, 저장된 데이터에 허가받지 않은 사용자가 접근할 때, 이를 제어할 수 있어야 한다.

CloudFront는 Origin Access Identity를 통해 이를 제공한다.

* S3 Bucket을 생성한 뒤, 생성한 Bucket에 CloudFront를 연결하고, Origin Access Identity를 설정하여 Access Control을 해보자.

 

1. Bucket 생성 및 파일 업로드.

S3 Console이 워낙 잘 만들어져 있어서, S3 Bucket 생성과 파일 업로드는 누구나 쉽게 할 수 있다. 업로드한 파일의 경로는 아래와 같다.

https://[S3 region].amazonaws.com./[bucket-name]/[filename]

e.g) https://s3-ap-northeast-1.amazonaws.com/bucket-name/filename

* Bucket 생성 후 특별한 설정을 하지 않았다면, Owner 계정만 Open/Download/View/Edit 할 수 있도록 Permissions이 설정되어 있다. 현재 상태에서 추가한 파일을 요청해보면 403 Forbidden과 함께, AccessDenied라는 메시지를 확인할 수 있다.

 

2. Bucket에 CloudFront를 설정해보자.

CloudFront Console에서 CloudFront를 생성하는 과정 역시 매우 쉽다.

Console -> Create Distribution -> Origin Domain Name -> Dropdown의 S3 Bucket 리스트중에서 원하는 Bucket 선택 -> 생성.

* 생성한 CloudFront가 Enable되는데는 15분 정도가 소요된다.

CloudFront가 Enable된 이후에 CloudFront로 Bucket에 업로드된 파일에 접속해보자. 위에서와 동일하게 403 Forbidden과 함께, AccessDenied라는 메시지를 반환한다. (기본적으로 Bucket의 Permission 설정을 따라간다.)

S3 URL) https://s3-ap-northeast-1.amazonaws.com/bucket-name/filename

CloudFront URL) http://[cloudfront-domain-name]/filename

 

3. CloudFront distribution에 Origin Access Identity 추가.

Distribution 설정의 Origins Tab에 추가되어있는 Origin을 아래와 같이 수정하자.

* Restrict Bucket Access : Yes

* Origin Access Identity : Create a New Identity (기존에 사용하던게 있으면 Use a Existing Identity)

* Grant Read Permissions on Bucket : Yes, Update Bucket Policy

위와 같이 Origin 설정을 수정하면 CloudFront와 연결된 Bucket의 Policy에 Origin Access Identity 조건이 추가된다.

http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

 

4. S3 Console에서 Bucket Policy 확인.

S3 Console -> Choose Bucket -> Permissions -> Edit bucket policy (확인)

(* 지금까지 제대로 됐다면 위와 같이 Origin Access Identity Policy가 Bucket에 제대로 설정되어 있다.)

 

1~4번까지 설정이 완료됐다면, AWS의 구성은 완료됐다.  Client에서 Signed URL을 생성한 뒤 접근하는 과정만 남았다. 

 

5. CloudFront Key Pair 생성 (이미 발급 받았으면 Skip)

Security Credential 페이지에 접속하면 CloudFront key fair를 발급 받을 수 있다. .pem으로 발급되는 Key를 Client Platform에 맞게 변경하여 사용해야 한다.

e.g) Java : DER Format, .Net : XML Format

http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html#private-content-reformatting-private-key

(* Private Key의 경우 재발급이 되지 않으니, 직사광선을 피해 잘 보관해야 한다.)

 

6. Signed URL 생성.

Signed URL을 생성하기 위해서는 Private KeyCloudFront Key Pair ID가 필요하다.

5번까지 정상적으로 진행했으면 2가지가 뭘 의미하는지 알아야한다.

Signed URL은 Base URL + 만료기간 + 허용 IP + Signature로 구성된 URL을 의미한다.

Signature 생성에 Private Key가 필요하고, CloudFront Key Pair ID를 동봉하여, 서버에서 Signed URL이 Valid한지 확인 할 수 있도록 한다.

e.g) http://d92s70lgx4e93.cloudfront.net/drmt.jpg?

Expires=1398919860&

Key-Pair-Id=APKAJRMC2OMX2MG46AEA&

Signature=gF9U0TBb7Hosg3rMbBdULbxTM9QZ-oHk8-gq1gaVkQABojKb5ynCeuJ8vJ5eWOTu4PlQvEnrsFLmr1mfvqNveQY8PLW3T-deUTU1FnJ9f-AzNihcuxLSILH0BX9~-Zz2wVArzB-zil15klQRxFf2PNhgKEgorO1ANqIpI7JYKhMl26O8nzah5xWfxa-Phni29Yl1RNS3MPyxO8UgoYk376jfFYFx8lq1r8r1aaQ1lZWNfKx1X0uS~oIuObMwCe~7yXGFWha-HSkDLoWObHgIi0nqUpVQyLaLf8VqMSJpH19Em8QZ-k2DH8GXovInX5xjOoRqQzTLixi70W-oB9-aPQ__

 

7. Create a Signed URL Using Java

아래 링크를 참고하면 JetS3t Library를 사용하여 Signed URL을 만들 수 있다.

http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CFPrivateDistJavaDevelopment.html

 

8. Edge 서버에 Cache되는 시간 설정.

Edge 서버에 얼마나 오래 데이터를 캐싱하고 있을지는 CDN을 사용할 때, 항상 고려되어야 하는 부분이다.  Origin Data가 변경될 일이 거의 없는 경우라면 당연히 Longer is better다. 다만 Origin Data가 변경될 확률이 있다면, 이를 잘 고려해야한다.

* S3 Object의 Metadata중 Cache-Control 값을 통해 캐싱 시간을 설정할 수 있다. (Default는 24 hour.)

e.g) Cache-Control: max-age=seconds

http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html

 

9. Check Cached? or Not?

CloudFront를 사용해서 데이터를 요청할 때, Edge 서버에 제대로 캐싱이 됐는지 확인하려면 Response Header의 X-Cache 필드를 확인하면된다.

Edge 서버에서 데이터를 내려줄 때는 ‘Hit from cloudfront’, Origin server에서 내려줄 경우에는 ‘Miss from cloudfront’ 라고 전달된다.

 

10. Edge 서버에 캐싱된 데이터 제거.

Edge 서버에 캐싱된 데이터가 유효하지 않다고 판단될 때, 캐싱된 데이터를 제거할 수 있다.

Invalidating Object 문서를 참고하자.

http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html

 

* References

[AWS에 APM 환경 구축하기] 6. EU 서버와 JP 서버간의 접속 속도 차이.

* 실제로 AWS에서 웹서비스를 운영하기 위해서는 속도가 종요한 부분일 수 밖에 없다.

  EU 서버와 JP 서버에 접속을 시도했을 때 의 속도차이는 아래 표와 같다. (왼쪽이 JP, 오른쪽이 EU)

  실험은 동일하며 간단한 html 파일을 서버에 올려두고 시도했습니다.

 

왼쪽이 JP, 오른쪽이 EU

* 그냥 참고들 하시라고.

Older posts

© 2017 Regular Motion

Theme by Anders NorenUp ↑