AWS Lambda는 다양한 분야에서 사용하는 코드형 기반 서버리스 서비스입니다. 하지만 Lambda는 Cold Start라는 초기 지연 시간이 발생할 수 있는데, Cold Start는 지연시간을 발생할 수 있습니다.
AWS Lambda를 실행하면 바로 함수가 실행되지 않습니다.
Lambda 실행 시 Lambda에 올려둔 코드를 이미지 형태로 다운 받아 실행하며, 이후 컨테이너가 유지됩니다.
하지만 Lambda는 컨테이너 생성 후 5분동안 사용하지 않으면 사용하던 컨테이너가 중지되며, 종료됩니다.
이에 람다는 경우에 따라 초기 응답이 늦어지는 것을 Cold Start라고 합니다.
언어 및 코드에 따라 Cold Start 시간이 다르게 나타납니다.
위 사진처럼 Python, Node.js 같은 경우 상당히 빠르지만, C#, JAVA는 느립니다.
1. Lambda Event 처리 방법 (Work Flow)
외부로부터 어떤 이벤트(요청)가 들어왔을 때 다음과 같은 순서로 이벤트를 처리합니다.
1) 실행환경 (컨테이너) 준비합니다.
컨테이너에 코드를 다운 받습니다.
Lambda에 설정된 Memory, Runtime, Configuration 기반으로 환경 설정합니다.
2) 초기화 코드 (Init Code)를 실행합니다.
3) Lambda 함수 코드 (Event Handler)를 실행하여 이벤트를 처리합니다.
1번부분에서는 비용이 발생하지 않지만 람다 컨테이너가 실행될 때까지 해당부분에서도 Latency가 발생합니다.
2, 3번은 Lambda가 실제로 실행되는 시간이므로 비용이 발생합니다.
다만, Initialization Code 부분의 경우, 첫 번째 이벤트에 대해서만 실행되는 코드이며, 두번째 호출부터는 실행되지 않습니다.
따라서 2번도 Cold Start에 포함됩니다.
2. Lambda Life Cycle
Lambda는 총 3단계의 Life Cycle을 가집니다.
1) init 단계
위에서 언급한 Cold Start가 해당 부분에 속합니다. 새로운 실행환경(컨테이너)를 요청하여 준비된 실행환경(컨테이너)가 람다 함수 코드를 다운로드 받고, 사용자가 람다 함수를 생성했을 때 지정해둔 Runtime, Memory, Configuration 등을 세팅하는 과정입니다. 또한, 람다 함수 코드에서 init code부분(라이브러리 및 global 변수 세팅)을 실행합니다.
2) invoke 단계
실제 람다 함수 핸들러가 호출되어, 코드가 실행되는 단계입니다. 하나의 Request(Event)에 대한 처리가 완료되면, 람다는 다음 Request(Event)를 처리할 준비를 합니다.
3) shutdown 단계
람다 함수 실행을 위해 세팅되어 있던 실행환경(컨테이너)가 죽는 단계입니다. 람다 함수는 일정 기간동안 호출을 받지 않으면 런타임을 종료하고 실행환경(컨테이너)을 제거합니다.
3. Lambda 통신 과정
1) Sequential
외부에서 어떠한 요청이 들어오면, Lambda는 새로운 실행환경(컨테이너)을 띄우고, 해당 실행환경에서 람다 함수의 코드를 실행할 수 있도록 이벤트를 발생시킵니다. 이 때, 하나의 컨테이너는 하나의 이벤트만 처리할 수 있으며, 해당 컨테이너가 이벤트를 처리하는 동안 freeze 상태가 됩니다.
이벤트 처리가 완료되면, 해당 컨테이너는 idle 상태가 됩니다.
이때, 아래 2개의 상태가 오래 지속되면 해당 컨테이너는 Shutdown 됩니다.
컨테이너가 idle 상태가 오래 지속되면 Shutdown됩니다.
요청받은 Request(이벤트)가 오래 지속되면 폐기 후 Shutdown됩니다.
2) concurrent
위에서 언급한 바와 같이, 하나의 실행환경(컨테이너)은 한 번에 하나의 Request(Event)만 처리합니다. 따라서 Request(Event)를 처리하는 동안 해당 실행환경(컨테이너)은 freeze 상태가 됩니다.
이 때, 만약 실행환경(컨테이너)들이 전부 freeze상태임에도 불구하고 새로운 Request(Event)가 계속해서 들어오는 경우, 람다는 새로운 실행환경(컨테이너)을 가져오도록 트리거합니다. (즉, 새로운 인스턴스를 생성합니다.)
concurrent하게 처리할 Request(Event)들에 대해 실행환경(컨테이너)는 계속해서 생성됩니다.
Lambda 함수마다 concurrent 인스턴스 용량을 할당할 수 있도록 Reserved Concurrency와 Provisioned Concurrency를 설정할 수 있도록 되어있습니다.
Region 별 Concurrent Instance 할당량은 1000개에서 시작합니다.
AWS Service Quotas을 통해 해당 Limit을 증가시킬 수 있습니다.)
적절한 런타임을 선택합니다.
(언어마다 처리속도가 다르므로, 가능한 빠른 환경을 실행하는 것이 좋습니다. / Python, Node.js 등)
자체적인 Warm Starat로 구성하기
Lambda Memory 사양을 늘립니다.
Provisioned Concurrency를 사용합니다.
지속적으로 트래픽이 들어오게 설정합니다.
(5분이 끝나기 전인 4분59초에 컨테이너가 반복적으로 실행되게 구성합니다.)
코드를 최적화합니다.
초기화 코드를 최소화합니다.
(초기화 시 필요한 작업만 수행하도록 코드 구조를 최적화합니다. / 불필요한 글로벌 변수나 라이브러리 로딩을 피합니다.)
테스트 및 모니터링합니다. (Lambda 함수의 성능을 지속적으로 모니터링하여, Cold Start가 발생 패턴을 파악하고 이를 기반으로 최적화합니다. AWS CloudWatch를 통해 지연 시간 및 Cold Start 빈도를 확인할 수 있습니다.
여러 리전을 사용합니다.
(트래픽이 높은 Application의 경우, 여러 AWS Region에서 Lambda 함수를 운영하여 부하분산시키고 Cold Start 빈도를 줄입니다.)