일반적인 EC2를 생각해 보겠습니다.
EC2는 클라우드 서비스이기 떄문에 가상의 컴퓨터를 하나 빌리는 행위이고 이로인해서 프로비저닝을 해주어야 합니다.
중단을 통해서 최적화 할수는 있지만, 그렇지 않으면 지속적으로 실행이 되며
오토 스케일링 그룹으로 스케일링 가능합니다.
그럼 람다는 이런 EC2와 어떠한 점이 다를까요
람다는 가상의 함수입니다.
관리할 서버가 없어, 그냥 코드를 프로비저닝하고 함수를 실행합니다.
실행 시간이 최대 15분 정도 걸리며, 온디맨드로 동작을 하기 떄문에 사용하지 않으면 비용이 발생하지 않습니다.
또한 스케일링도 자동으로 동작합니다.
람다의 장점은 다음과 같습니다.
1. 가격 책정이 쉽습니다.
수신하는 요청의 숫자에 따라 청구가 됩니다.
2. 프리티어 에서도 넉넉하게 제공됩니다.
요청 1백만 개와 컴퓨터 시간 40만 GB입니다.
3. 다양한 AWS 서비스와 통합되며, 많은 프로그래밍 언어를 지원합니다.
4. CloudWatch의 모니터링 통합도 쉽습니다.
이외에도 생각하는 거의 모든 기능에 대해서 서비스를 제공합니다.
좋은 예시를 하나 들어보게습니다.
서버리스 썸네일 생성입니다.
S3버킷이 있고 여기서 바로 썸네일을 생성하고자 합니다.
S3에 새 이미지가 업로도 되는 이벤트가 생기고 이벤트에 따라서 람다가 동작을 합니다.
이떄 람다 함수에는 썸네일을 생성하는 코드가 있으며, 해당 썸네일은 다른 S3버킷이나, 같은 버킷으로 푸시 됩니다.
부수적으로는 DynamoDB에도 삽입이 되게 됩니다.
동기식은 일반적으로 async/await 와 같이 결과를 기다리는 행위를 말합니다.
거의 대부분을 동기식으로 호출하고 있습니다.
또 다른 람다의 동기식 호출 입니다.
주로 요청이 애플리케이션에 도착하기 전에 필터링 할떄 사용이 되기도 하고, 글로벌적인 서비스를 사용할떄 사용이 됩니다.
즉각 반응하는 애플리케이션을 위해서 사용이 되고 서버를 개발자가 관리하지 않기 떄문에 전역으로 배포가 됩니다.
수정을 할 수 있는 단계는 총 4가지로 구성이 되어 있습니다.
1. 뷰어 요청
CloudFront가 사용자로부터 요청을 받았을 경우를 말하며 이 요청을 수정 가능합니다.
2. 오리진 요청
CloudFront가 오리진으로 전달하기 전인 요청입니다.
3. 오리진 응답
CloudFront가 오리진으로부터 받은 응답을 말합니다.
4. 뷰어 응답
CloundFront가 뷰어에 다시 응답을 해주는 것을 말합니다.
쉽게 말해 모든 과정에 대해서 수정이 가능합니다.
람다 함수를 뒤에서 요청을 기다리지 않고 호출 하는 것을 말하며 대표적으로는 S3, SNS, CloudWatch가 많이 사용합니다.
구체적인 예시를 하나 들어 보겠습니다.
S3버킷이 있고, 새 파일에 대한 이벤트가 있습니다.
해당 이벤트가 이제 람다 서브시에 이동할 것이고 이벤트는 내부의 대기열에 위치하게 됩니다.
이후 람다 함수가 대기열을 읽음으로써 이벤트를 처리하려고 할 것이고, 만약 문제가 발생을 하며 자동으로 재 시도 할 것입니다.
이떄 재시도는 총 세번 동작을 하며 첫번쨰는 바로 시도되고, 이후는 1분후, 이후는 2분 후에 발생합니다.
이러한 재시도는 로그가 CloudWatch에 기록이 됩니다.
만약 세번이 지났는데도 동작을 하지 않으면 이제 DLQ로 보내어 나중에 처리가 되게 합니다.
위와 같은 예시에서 굳이 비동기를 사용하는 이유는 다음과 같습니다.
1. 몇몇 서비스는 반드시 비동기를 사용합니다.
2. 결과를 굳이 기다릴 필요가 없다면 더 빠른 속도를 제공합니다.
그러기 떄문에 대부분 로그를 발생시키거나 이벤트를 발생시키는 서비스들은 모두 비동기로 동작하게 됩니다.
람다가 이벤트를 처리하는 마지막 유형입니다.
람다가 서비스에 레코드를 요청해야 동작을 하며, 이는 서비스들로부터 람다가 폴링을 해야 한다는 의미 입니다.
이런 경우에는 람다는 동기적으로 호출 됩니다.
예를 들면 이와 같습니다.
Kinesis와 람다 서비스가 있습니다.
람다가 Kinesis에서 읽고자 한다면, 이벤트 소스 매핑이 람다 내부적으로 생성이 되고 이후 폴링하게 됩니다.
이후 데이터가 생겨나면 람다가 함수를 동기적으로 호출합니다.
ALB와 결합하여 사용하고자 한다면 람다를 대상 그룹에 등록을 해야 합니다.
이러한 기능을 사용하는 이유는 사용자들이 HTTP, HTTPS 형태로 ALB를 호출하고 람다 함수를 실행ㅇ시키는데에 목적이 있습니다.
문제는 ALB가 HTTPs요청을 어떻게 람다 호출로 바뀌는가 입니다.
이는 ALB에서 람다로 갈떄 요청을 JSON문서로 변환하기 떄문에 동작이 됩니다.
이후 람다가 응답으로 JSON형태롤 주고, ALB가 다시 HTTPS로 변환하면서 동작합니다.
일단 기본적으로 람다는 CloudWatch Log와 통합되어 있습니다.
모든 로그는 자동으로 저장이 되지만 람다가 CloudWatch에 저장 할 수 있도록 IAM역할을 지정해 주어야 합니다.
또한 X-Ray기능 또한 활용이 가능합니다.
람다 구성에서 단순히 Active Tracing만 활성화 해주면 되며, 이 또한 IAM역할이 필요합니다.
기본적으로 람다함수는 자체 VPC 외부에서 실행이 됩니다.
따라서 저의 VPC에 있는 리소스에는 액세스가 불가능 합니다.
저의 VPC같은 경우에는 EC2나 RDS나 혹은 일래스틱 캐시 등에 사용이 됩니다.
람다는 모든 공용 웹사이트에 액세스 가능하고, 외부 API에 액세스가 가능합니다.
하지만 자체 VPC가 있다면 개인 RDS로 인해서 람다는 이 RDS에 액세스 불가능합니다.
자체 VPC에 배포를 하면 개인의 RDS에는 접근이 가능하며, 만약 외부 API와 소통을 하고자 한다면
공용 서브넷을 거쳐야 합니다.
즉 공용 서브넷을 거치고, 이후 공용 서브넷에서 외부 API에 대한 액세스를 허용해 줌으로써 동작합니다
쉽게 말해 공용 VPC에 배포를 하면 사설 VPC에 있는 정보는 접근이 불가능하고,
사설 VPC에 배포를 하면 외부 API에 대해서 추가적인 조치를 해주어야 합니다.
RAM같은 경우에는 최대 10GB까지 확장이 가능하며 추가 할수록 더 많은 비용이 청구가 됩니다.
만약 애플리케이션이 많은 연산을 요구한다면 단순히 RAM을 늘리면 됩니다.
시간 제한같은 경우에는 기본적으로 3초로 설정되어 있지만 이는 900초까지도 설정이 가능합니다.
하지만 15분이 넘어가는 서비스는 람다에 적합하지 못하고, 이러한 서비스는 ECS, EC2를 사용해야 합니다.
람다는 실행 컨텍스트라는 것이 존재합니다.
임시 시간 제한 환경으로 외부 종속성을 초기화 합니다.
즉 이 컨텍스트를 사용하여 DB를 연결하고 HTTP, SDK를 생성 가능합니다.
장점으로는 람다 함수가 실행 될 것을 예상하고 일정시간 유지된다는데에 있고 이러한 방식은 람다의 속도를 늘리고, 성능을 향상시키는데에 아주 유용합니다.
실행 컨텍스트에는 /tmp라는 디렉터리가 포함되며 여기는 파일을 직접 쓸 수 있는 공간이자 전반적으로 이용이 되는 공간입니다.
또한 임시파일을 작성하여 재사용해야 하는 공간 같은경우에는 /tmp space를 사용합니다.
가령 작업을 위해서 용량이 큰 파일을 다운로드 해야 하거나, 디스크 공간이 필요할경우 /tmp에 저장을 하고 이후 사용을 합니다.
해당 디렉터리는 람다가 실행하는 동안 유지가 되며, 함수가 중단된 후 재 호출해도 동일하게 존재하기 떄문에 시간 절약이 가능합니다.
람다는 온디맨드 형태로 동작하고 자동으로 스케일링 하기 떄문에 확장이 매우 쉽고 빠르게 일어납니다.
만약 낮은 규모에서 갑자기 큰 이벤트가 동작을 한다면 최대 1000개까지 람다는 동작하게 될 것입니다.
하지만 너무 과소비가 유발 될 수 있기 떄문에 동시 실행 갯수를 제한하는 것이 좋고 이를 위해서 예약된 동시성을 설정해야 합니다.
예를들면 최대 50개만 동시 실행을 하게 설정을 하는 것 입니다.
동시성을 제한을 초과하는 각 호출은 스로틀을 트리거 합니다.
스로틀 같으 경우에는 여러개가 있을 수 있습니다.
만약 동기식이라면 ThrottleError - 429
가 반환되고
비동가라면 자동으로 재시도 한 후에 DLQ로 이동합니다.
만약 동시성에 대해서 제한을 두지 않는다면 다음과 같은 상황이 발생할 수 있습니다.
람다 함수에 ALB가 연결이 되어 있습니다.
API게이트 웨이를 통해 다른 람다 함수에 연결돼 있으며 마지막 애플리케이션은 SDK, CLI를 활용하여 람다를 호출 합니다.
낮은 처리량은 문제가 없으나 갑자기 많은 이벤트가발생을 하였다고 가정하면, ALB는 무수히 많은 요청을 람다에 보내게 되고 람다는 1000개까지 최대값으로 늘어나 동시 실행이 이루어 집니다.
잘 처리가 되었지만 문제가 몇가지 있습니다.
1. 동시 실행이 ALB즉 하나에만 발생하는데에서 문제가 발생을 합니다.
이로 인해 API 게이트웨이의 애플리케이션 사용자도 조절대상이 되고 CLI, SDK도 조절 대상이 됩니다.
- 즉 하나의 함수에 대해서 동시성을 조절해도, 계정 단위로 적용이 되기 떄문에 다른 함수도 조절대상이 됩니다.
다음은 동시성과 비동기식 호출입니다.
S3버킷에 파일을 업로드하면 새로운 이벤트가 생성이 되고, 많은 파일을 업로드 하면 그만큼 이벤트가 발생을 할 것입니다.
이떄 동시성으로 인해서 충분한 람다를 사용 불가능 할떄 스케일링이 불가능해지고 추가적인 요청은 스로틀 됩니다.
하지만 비동기 요청이기 떄문에 해당 이벤트들은 이벤트 대기열로 반환됩니다.
그러기 떄문에 비동기 모드에서는 내부 이벤트 대기열이 있으므로 최대 6시간에 걸쳐 함수를 실행하려고 시도를 하고,
조절 등으로 인해서 재시도가 무수히 많이 발생하게 될 것입니다.
그러면 최소 1초 또는 5분마다 람다를 재 실행함으로써 올바르게 실행하 수 있는 동시성과 용량을 찾게 됩니다.
계층이란 람다의 새로운 기능으로 두가지 일을 제공합니다.
- 람다에 사용자 지정 런타임을 생성할 수 있습니다.
람다에 사용할 수 없는 언어들을 커뮤니티에서 람다 계층을 통해 지원합니다.
대표적으로 Rust, C++가 있습니다.
- 재사용을 위해 종속성을 외부화 하는 경우가 있습니다.
압축되어 있는 애플리케이션은 매우 큰 경우가 있습니다.
그리고 람다 함수 업데이트 할 떄에는 해당 zip파일을 계속 다시 업로드 해야 하지만 사용하는 종속성이 바뀌지 않는 경우도 종종 있습니다.
이런 상황이라면 그냥 종속성을 외부화하여 계층에 보관을 하는 것이 더 용이합니다.
즉 쉽게 말하면 종속성을 따로 설치하지 않고 계층을 따로 만들어 거기에서 자동으로 람다가 참조하게 구성을 하는 것을 말합니다.
기본적으로 새로운 람다를 배포하면 코드가 수정이 됨으로써 배포가 됩니다.
이를 $LATEST버전이라고 합니다.
하지만 가끔씩은 현재의 코드 상태에 만족하고 있을떄 새 버전을 생성 할 수도 있습니다.
이건 게시를 하면 바로 V1이 되는데 이는 변경이 불가능합니다.
변경이 불가능 하다는 의미는 코드나, 환경 변수 등을 바꿀 수 없다는 의미이고, 하나의 버전으로 고정이 되는 겁니다.
이러한 상황에서 사용자들에게 안정적인 엔드 포인트를 제공하고자 한다면 람다 별칭을 써야 합니다.
별칭은 람다 함수 버전을 알리는 포인터가 되어 줍니다.
예를들어 $LATEST버전의 람다를 A, 그 이후로 생성된 버전을 B,C라고 하겠습니다.
- 이떄 B,C는 A와 코드가 같습니다.
만약 사용자가 A와 소통을 하고자 한다면 DEV라는 별칭을 만들어 소통을 하고
이후 C와 테스트를 진행하고자 한다면 TEST라는 별칭을 만듬으로써 사용합니다.
이런것을 구현하는 이유는 비중 떄문입니다.
예를들어 B에 100%를 전송하다가 C에 5%를 전송하고자 한다면,
해당 별칭을 통해서 일부는 C로 전송을 하게 구성이 가능하고 이는 블루/그린 이라고도 합니다.