본문 바로가기

Compute/Lambda

AWS Lambda Edge 콜드스타트?

 

Lambda Edge(이하 LE) 도입을 위해 성능을 측정

 

비교는 LE를 적용한 CF와 적용하지 않은 CF의 레이턴시 및 에러률 측정

 

원본은 동일하게 S3로 정적이미지 URL

 

LE의 동작은 Viwer Response에 커스텀 헤더를 추가

 

성능 측정은 locust로, RPS 5,000 / 인터벌 1~3초 / 커넥션 50,000

 

그 결과 콜드스타트 문제를 넘어 RPS가 1,000을 넘어갈 때 약 3% 이상의 503(람다 실행 초과)가 발생

반면 LE를 적용하지 않은 CF의 경우 특이사항은 발견되지 않음

Lambda Edge

사실 LE의 RPS 기본 쿼터는 1,000으로 아주 정확하게 동작하고 있는 듯 보임

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html

 

Quotas - Amazon CloudFront

Lambda dynamically scales capacity in response to increased traffic, within your account’s quotas. For more information, see Function scaling in the AWS Lambda Developer Guide.

docs.aws.amazon.com

 

LE의 RPS 쿼터를 높이기 위해서는 사유가 있어야 상향 요청이 이루어지기 때문에 성능 측정을 위해서라고 물어보면 해줄 지도 의문이고 귀찮아서 패스

 

하지만 LE를 적용한 CF 로그와 LE를 적용하지 않은 CF 로그의 time-taken을 보면 꽤나 큰 차이가 발생

 

LE를 적용한 CF 로그의 time-taken의 경우 느렸던 요청들의 시간은 1초 이상

LE를 적용하지 않은 CF 로그의 time-taken의 경우 느렸던 요청들의 시간은 0.6초 수준

 

그럼 여기서 두 가지를 알 수 있는데

1) 먼저 LE를 1,000 RPS 이상 발생되는 곳에 사용하기 위해서는 쿼터를 높여야 하고,

2) 그렇지 않다면 LE로 인해 503 장애 및 지연이 발생된다는 것을 알 수 있음

(503 에러의 경우 LE의 쿼터 혹은 Lambda 실행 타임아웃으로 인해 발생)

 

추가로 도큐먼트를 보면 쿼터를 높인다고 하더라도 람다의 Provisioned Concurrency랑은 별개

https://aws.amazon.com/ko/blogs/korea/new-provisioned-concurrency-for-lambda-functions/

 

AWS Lambda 함수, Provisioned Concurrency를 통해 빠른 성능 제공 (서울 리전 포함) | Amazon Web Services

AWS Lambda가 출시되고 5년이 흘렀지만 여전히 팀은 더 쉽게 애플리케이션을 구축하고 실행할 수 있는 새로운 방법을 찾고 있습니다. 특히, 중요 애플리케이션이 서버리스로 이동하면서 애플리케

aws.amazon.com

 

위 테스트를 보면, 스파이크성 서비스의 경우 LB의 핸들링에 어려움이 있듯이 LE도 비슷한 상황이 발생될 것이라 예상

 

따라서 LE를 사용한다면 콜드스타트를 고민하기 앞서 LE 쿼터 관리를 어떻게 해야 할 지가 더 중요하다는 것을 알 수 있음

 

 

1,000 RPS 제한을 넘지 않기 위해 150, 750 RPS로 추가 테스트 진행

150 RPS의 경우 기존 LE를 적용하지 않은 CF와 time_taken 수치가 거의 동일(느린 로그들이 0.6초 수준)

150 RPS

750 RPS의 경우 time_taken이 1.6초까지 넘어감.... 아쉬운 부분

750 RPS(LE)

 

테스트 결과를 바탕으로 AWS 측에 문의해보고 업데이트 하겠지만, 실제 대규모 트래픽을 받는 서비스에 Lambda@Edge를 적용할 때는 주의가 필요한 듯 싶음

 

 

위 내용을 토대로 AWS Support 회신 받음

먼저 LE의 RPS는 1,000이 맞음

아쉬운 건 750 RPS에서도 왜 지연이 발생됐는지는 언급이 없음

 

그리고 LE의 concurrency의 쿼터는 계정당 최대 2,500 RPS까지 가능(분당 500씩 증가)

만약 LE에서 프로세싱 타임이 1초 보다 낮다면 더 2,500 RPS 보다 더 많은 RPS 처리는 가능

LE concurrency를 늘리고 싶으면 기존과 같은 리밋 해제 요청이 아니라 따로 요청을 해야 함

즉 현재까진 대규모 서비스의 니즈가 없었던 듯? (있었다면 서포트 리밋 해제에 해당 기능이 존재했을 듯)

 

또한 문제는 concurrency 쿼터를 높였다고 동시성이 보장되는 것이 아니라 쿼터가 늘어난 것임

앞서 말했듯이 concurrency 버스팅이 1분당 500 RPS씩 증가하며, 이것이 Provisioned concurrency를 말하는 것이 아님

따라서 중간(?) 이상 규모의 트래픽을 받는 서비스는 사용에는 어려움이 있을 듯

 

이전 성능 측정 결과를 보면 1분정도 503 에러가 발생되고 다시 503 에러가 사라진 이유를 유추할 수 있었음

뭐 그렇다고 레이턴시도 줄어든 것은 아님...

 

결론적으로 대규모 스파이크성 트래픽에 사전 AWS 협의 없이 LE를 사용하기엔 리스크가 큼

 

다만 캐싱이 가능한 오리진 트리거 사용 시에는 중간급(?) 규모의 트래픽을 받는 서비스에도 어느 정도 사용 가능할 듯

 

추가로 개발 언어마다 Lambda 콜드스타트를 잘 정리한 포스팅은 아래를 참고

https://filia-aleks.medium.com/aws-lambda-battle-2021-performance-comparison-for-all-languages-c1b441005fd1

 

AWS Lambda battle 2021: performance comparison for all languages (cold and warm start)

Let’s compare the performance of all supported runtimes + 2 custom runtimes (Rust and GraalVM).

filia-aleks.medium.com

 

Lambda 콜드스타트 및 모니터링 참고

https://blog.leedoing.com/231

 

AWS Lambda X-ray 및 Insight(Serverless, MSA 모니터링)

재미와 학습으로 시작했던 서버리스 MSA로 구성한 서비스가 어느 새 2년이라는 시간이 지났다. 사용자도 꽤 늘어 기능을 추가하다 보니, 현재 40개가 좀 넘는 Lambda가 돌아가고 있다. (비용은 월 $15

blog.leedoing.com

 

 

Lambda@Edge Sample

Redirect(Viewr Request, Origin Request)

'use strict';


/* This is an origin request function */
exports.handler = (event, context, callback) => {
    /*
     * Generate HTTP redirect response with 301 status code and Location header based on region.
     */
    const request = event.Records[0].cf.request;
    const request_uri = request.uri;
    const host = request.headers.host[0].value
    const path = "/kr/img.jpg"
    
    if(request_uri != "/test"){
        return callback(null, request)
    }
    
    console.log('https://' + host + path)

    const response = {
        status: '302',
        statusDescription: 'Found',
        headers: {
            location: [{
                key: 'Location',
                value: 'https://' + host + path,
            }],
        },
    };


    callback(null, response);
};

 

Reponse 커스텀 헤더 추가(Viewer Response)

'use strict';
exports.handler = (event, context, callback) => {
   console.log('Adding additional headers to CloudFront response.');

   const response = event.Records[0].cf.response;
   
   response.headers['strict-transport-security'] = [{
      key: 'Strict-Transport-Security',
      value: 'max-age=86400',
   }];
   
   response.headers['custom-header'] = [{
      key: 'custom-header',
      value: 'lambda-edge',
   }];
   
   response.headers['leedoing'] = [{
      key: 'leedoing',
      value: 'test',
   }]


   callback(null, response);
};