1. Serverless란?
서버를 올리고 잘 동작하는지 모니터링하는 등 서버를 관리하는데 많은 비용이 들어갑니다. serverless는 그러한 서버를 관리하는데 들어가는 리소스가 필요하지 않습니다. 트래픽이 많아지거나 줄어들 때 자동으로 스케일링해주며 사용한 만큼만 지불할 수 있습니다. AWS에서 관리를 해주기 때문에 보안에 큰 신경을 쓰지 않아도 된다는 장점이 있습니다.
2. Serverless Service 종류
AWS에서 제공하는 서비스로는 Lambda, Fargate, S3, Aurora serverless, DynamoDB, API Gateway, SQS, SNS, Kinesis 등이 있습니다.
3. Lambda 함수
3.1 Lambda 함수란?
Lambda 함수는 함수 기반의 실행환경을 제공합니다. 실행환경을 작성할 때 여러 언어(Node.js, Python, Java, C#, Go, Ruby, Runtime API)를 사용할 수 있습니다.
3.2 Lambda 함수 실행 프로세스
Lambda 함수의 실행 프로세스는 아래 이미지에 나온 것과 같습니다. 데이터 상태의 변화, endpoints로의 요청, 리소스 상태의 변화 등을 트리거로 설정하여 이러한 이벤트가 발생할 경우 Lambda 함수를 호출할 수 있습니다. 그 후에 여러 서비스들과 함께 어울려 business logic을 수행합니다.
3.3 Handler function
Handler function은 Lambda 함수 1개마다 1개의 handler function이 있어야 합니다. 트리거로 Lambda 함수가 호출됐을 때 handler function으로 요청이 들어오게 됩니다. event 객체는 Lambda 호출 시 들어오는 데이터(s3 트리거 시 해당 파일 이름 등등)가 들어오게 되고, context는 runtime과 관련된 정보(reqeust ID, log group 등)들이 들어있습니다.
import json
def lambda_handler(event, context):
# TODO implement
return {
'statusCode' : 200,
'body' : json.dumps('Hello World!')
}
3.5 실행환경
Lambda 함수는 한 개당 실행환경 한 개를 가집니다. Lambda 함수가 여러 개가 호출될 경우 여러개의 실행환경이 실행됩니다. 다만, 실행환경은 재사용이 가능해서 초기화와 관련된 함수들은 handler function 밖에 두는 것이 함수의 사용 시간을 줄이는 방법입니다.
3.6 Lambda 설정
1) Power Rating
- 메모리 128MB ~ 10GB 사이에서 선택 가능
- CPU는 메모리에 따라 성능 향상 가능
- CPU, 메모리, 네트워크는 성능에 따라 가격 변동
2) Timeout
- 15분까지 설정 가능
- 동기 vs 비동기
- API Gateway timeout은 30초
3) Network Access
- VPC로 접근 설정
- 보안 그룹 역할 적용
- VPC는 함수의 보안 향상 X
3.7 The function lifecycle
1) cold start : Lambda 함수가 처음 호출되어 실행환경을 준비하는 시간으로 코드 다운로드, 실행환경 시작, 런타임 부트스트랩하는 시간을 의미합니다. 이때, 앞단계는 AWS에서 최적화해주는 시간이고, 런타임 부트스트랩은 사용자가 직접 최적화할 수 있습니다.
2) warm start : cold start 이후로 실제 코드가 실행되는 시간을 의미합니다.
3) 재사용시 시간을 단축시키는 방법
- handler function을 어떻게 작성하느냐에 따라 Lambda 함수의 실행시간이 크게 단축될 수 있습니다.
200-300 ms 실행시간
import json
import boto3
def lambda_handler(event, context):
print("inside handler")
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('lambda-config')
response = table.get_item(Key={'pkey':'dynamodb'})['Item']['value']
return {
'statusCode': 200,
'body: Json.dumps(response)
}
double digit ms 실행시간
import json
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('lambda-config')
def lambda_handler(event, context):
print("inside handler")
response = table.get_item(Key={'pkey':'dynamodb'})['Item']['value']
return {
'statusCode': 200,
'body: Json.dumps(response)
}
4) cold start를 줄이는 방법
- INIT 단계에서 필요한 클래스 로딩
- Java의 경우 Reflection 가급적 피하기
- 패키지 사이즈는 작게
- Memory 사이즈를 크게(비용 고려)
- Lambda Language(Java는 로드하는 시간이 길어서 대체할 수 있는 스크립트 언어가 있다면 대체하는 것이 좋습니다.)
- Provisioned Concurrency
4. Lambda Concurrency
4.1 concurrency 이해하기
1) 사용자 요청이 들어오면 cold start를 마치면 함수가 실행이 됩니다.
2) 이 때, 사용자의 요청이 끝나기 전까지는 해당 실행환경은 blocking 되므로 새로운 요청이 발생했을 때에는 새로운 실행환경이 생깁니다.
3) request6 생길 당시에 request1의 실행환경이 요청이 끝난 free 상태(=warm 상태)이므로 cold start 없이 warm start를 할 수 있습니다.
4) concurrency count는 시간당 처리한 요청의 수가 아닌 요청을 처리 중인 실행환경의 수를 의미합니다.
4.2 Lambda function scaling
1) 요청이 들어오면 실행환경들이 빠르게 생성이 되다가 Burst limit에 도달하면 분당 500개의 실행환경들이 새롭게 생성되도록 제한됩니다.
2) 이 때, 실행환경의 생성 개수가 제한됨에 따라 요청량이 실행환경 개수보다 많아 throttling 될 수 있는데 이는 다른 기법을 활용하여 제어할 수 있습니다.
3) concurrency limit보다 많은 요청량이 들어올 경우에도 마찬가지로 throttling이 발생할 수 있습니다. concurrency limit은 region별로 다르며, aws support에 요청하면 상한선을 높일 수 있습니다.
4) 요청량이 줄어듦에 따라 Lambda의 실행환경 수도 같이 줄어듭니다.
5) Provisioned concurrency : cold start 없이 warm 상태인 실행환경을 만들어두어 급격하게 대량의 요청(쇼핑몰 이벤트)이 들어올 때를 대비할 수 있습니다.
6) Reserved concurrency : 해당 Lambda 함수에 대해서만 사용할 수 있는 pool을 미리 만들어두어 다른 Lambda 함수가 급격하게 호출되더라도 실행환경 할당량을 보장받을 수 있습니다.
5. Lambda - More Features
1) Lambda Layers - cold start를 줄일 수 있는 방법 중 하나입니다. 문자 인코딩하는 라이브러리, 크기가 큰 패키지 등을 불러올 때, 빈번하게 잘 바뀌지 않는 코드일 경우 한 번 업로드해놓고 여러 Lambda 함수에서 이를 참조하여 실행환경을 실행할 수 있습니다.
2) Dead-Letter Queue - 비동기 방식으로 요청을 처리할 때 요청이 끊어지거나 예외가 발생할 때 내부적으로 2번 재시도를 한 후 실패하면 버리게 됩니다. 이러한 실패한 요청들을 Dead-Letter Queue에 모아두어 나중에 확인하여 재처리를 할 수 있습니다. Dead-Letter Queue에 알람 설정을 해두어 한건이라도 들어오면 어떤 에러가 발생했는지 어떤 처리를 하다가 발생했는지 알 수 있게 구성할 수 있습니다.
3) RDS-Proxy
관계형 DB에서 Lambda 함수를 사용하는 것은 적합하지 않습니다. 1000개의 요청이 들어와 Lambda 함수가 호출되었을 때 1000개의 DB connection을 잡고 있는 상태가 되고 RDS는 이를 효율적으로 관리하는데 적합하지 않습니다. RDS proxy는 Shared connection pool을 사용하여 connection을 줄여주고, secret manager로 간단한 인증을 할 수 있습니다.
4) Versioning, Aliasing
versioning을 통해 쉽게 배포, rollback 등을 할수 있습니다. aliasing을 통해 Lambda 함수에 태그를 달아 참조할 수 있습니다.
5) Monitoring and debugging Lambda functions
1) 기본적으로 monitoring을 제공하며 throttling이나 error에 대한 알람 설정을 하는 것이 좋습니다.
출처