일단은 Proxy가 정확하게 뭔지 잘 몰라서 해당 내용 부터 살펴 본다면,

Proxy

'대리', '대신' 의 뜻, 주로 보안 상의 문제를 방지하기 위해 직접 통신하지 않고 중계자를 거친다는 개념

여기서의 중계자가 'Proxy Server'

클라이언트가 프록시 서버에 요청한 내용을 서버에 캐시로 저장해두면, 전송 시간을 절약할 수 있고, 특정 사이트는 접근 불가능하도록 제한을 걸 수도 있다. → Forward Proxy

 

클라이언트가 바로 서버에 데이터를 요청해 받을 수 있지만, DB가 노출될 수 있는 위험이 존재한다. 중간에 프록시 서버를 두고 내부망을 보호하는 역할을 할 수도 있다. → Reverse Proxy

 

RDS Proxy

  • Connection Pooling
    • 커넥션을 열고 닫으며 많은 커넥션을 동시에 열린 상태로 유지하는 데 관련된 오버헤드를 줄이는 최적화 기능
    • connection multiplexing: 커넥션 재사용(하나의 DB 연결을 사용해 한 트랜잭션에 대한 모든 작업 수행)
  • 데이터베이스 장애조치(failover)와 같은 오류 시나리오 동안 애플리케이션 가용성 개선
    • 장애 조치 동안 애플리케이션 연결 유지
  • TLS/SSL 및 IAM을 포함한 RDS 보안 기능을 사용해 애플리케이션 코드에서 연결에 대한 자격 증명 불필요
    • AWS Secrets Manager와 통합되어 하드 코딩할 필요가 없음(DB 자격 증명을 중앙에서 관리)
  • CloudWatch 메트릭 및 로깅
    • 주요 메트릭: ClientConnections, QueryRequests, DatabaseConnections
    • 로그 그룹 내에서 모니터링: /aws/rds/proxy/[proxy-name]

 

VPC 생성

cloudformation으로 생성

더보기

AWSTemplateFormatVersion: "2010-09-09"
Description: 'Cloudformation template to create VPC for workshop (Optimize Serverless Application on AWS)'
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: serverless-app
  
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: serverless-app-igw

  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-2a
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: lambda-subnet-a

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-2c
      CidrBlock: 10.0.2.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: lambda-subnet-c

  PrivateSubnet3:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-2a
      CidrBlock: 10.0.10.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: rds-subnet-a

  PrivateSubnet4:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-2c
      CidrBlock: 10.0.20.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: rds-subnet-c

  PrivateSubnet5:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-2a
      CidrBlock: 10.0.100.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: secret-subnet-a

  PrivateSubnet6:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-2c
      CidrBlock: 10.0.200.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: secret-subnet-c

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-2a
      CidrBlock: 10.0.0.0/24
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: cloud9-subnet-a

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: serverless-app-routes

  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet1

Outputs:
  VPC:
    Description: serverless-app-vpc
    Value: !Ref VPC

보안 그룹 생성

  • lambda-sg
  • rds-sg: MySQL / lambda-sg

 

RDS 생성

  • 서브넷 그룹 생성: 10.0.10.0/24(a az), 10.0.20.0/24 (c az)
  • DB 생성:
    • MySQL 5.7.33 버전
    • db.m5.large / gp2 20GB
    • VPC쪽 위에서 생성했던 것들..

 

Lambda 생성

  • python 3.8
  • VPC 활성화: 10.0.1.0/24, 10.0.2.0/24 /  lambda-sg
  • 코드
더보기
import json
import pymysql

def lambda_handler(event, context):
    db = pymysql.connect(
        host='YOUR RDS ENDPOINT', 
        user='YOUR DATABASE MASTER USERNAME', 
        password='YOUR MASTER PASSWORD'
        )

    cursor = db.cursor()
    
    cursor.execute("select now()")
    result = cursor.fetchone()

    db.commit()
    db.close()
    
    return {
        'statusCode': 200,
        'body': json.dumps(result[0].isoformat())
    }

현재는 db 연결 테스트를 위한 작업으로 로그인이 하드코딩으로 이루어져 있다. 이후에 RDS Proxy를 통해 변경할 예정

 

Lambda Layer 추가

pymysql 패키지를 추가해줘야...

 

그 후에 lambda test를 돌려보자("statusCode: 200"이면 성공한 것)

 

API Gateway 구성

  • REST API / 새 api
  • 리소스 - 작업 / GET 추가
    • lambda func: 위에서 설정했던 lambda 이름
  • 리소스 - 작업 / API 배포: 새 스테이지 - 이름

URL 클릭해보면 아까 lambda에서 테스트 했던 결과와 똑같이 나옴..

lambda 함수 개요로 다시 돌아가보면 api gateway가 트리거로 잡혀있다.


https://github.com/aws-samples/the-evolution-of-aws-serverless-applications/blob/main/module3/README.md

이제 RDS Proxy를 적용해보자!

 

AWS Secrets Manager 구성

암호는 RDS 생성 시 넣어줬던 비밀번호로 설정해주면 된다.

자동 교체의 경우는 비활성화로 진행한다.(테스트 용이니까)

 

Secrets Manager를 사용하면 기본적으로 퍼블릭 통신을 통해 DB 크리덴셜을 가져오지만, VPC Endpoints를 사용하면 프라이빗 엔드포인트를 통해 VPC 내의 리소스가 직접 액세스 할 수 있음!

 

VPC로 돌아가 생성되었던 VPC 선택 후

  • 작업 → DNS 호스트 이름 편집 활성화

VPC Endpoints 설정에는 보안 그룹이 필요하다. Secrets Manager의 경우 Lambda에 접근 가능해야함..

  • 보안그룹: secret-sg / HTTPS - lambda-sg

VPC Endpoints 설정

  • AWS 서비스 - 위에서 설정했던 Secrets Manager
  • VPC: 위에서 생성했던 대로.. 서브넷 (secret-subnet-a/c), 보안그룹: secret-sg

 

RDS Proxy 구성

서버리스에서 사실 RDS를 사용하기엔 어려움이 있다.

(서버리스 아키텍처를 기반으로 구축된 애플리케이션은 DB에 다수의 커넥션을 만들어 max_connections 옵션을 초과하는 에러가 발생하거나 빠른 속도로 DB 커넥션을 여닫아 과도하게 메모리와 컴퓨팅 리소스를 소진할 수도 있음.)

RDS Proxy를 사용할 경우 애플리케이션과 DB 사이의 연결을 풀링하고 공유가 가능해 조금이나마 도움이 될 수 있음!

따라서 lambda와 rds 커넥션을 하고 싶다면 Proxy를 활용해라

  • MySQL
  • 위에서 생성했던 rds, secrets manager, 서브넷은 rds-subnet-a/c 확인 후 나머지 제거
  • 보안그룹 rds-sg 추가

 

Lambda 함수 변경

구성 → 권한 → IAM Role 수정

해당 Secrets Manager에 대한 권한을 부여한다.

그 후에 코드 변경

더보기
import json
import pymysql
import boto3
import base64
import time
from botocore.exceptions import ClientError

secret_name = "serverless-app-rds-secret"
region_name = "ap-northeast-2"

def get_secret():    
    session = boto3.session.Session()
    client = session.client(
        service_name = 'secretsmanager',
        region_name = region_name
    )

    get_secret_value_response = client.get_secret_value(
        SecretId=secret_name
    )

    if 'SecretString' in get_secret_value_response:
        secret = get_secret_value_response['SecretString']
        return secret
    else:
        decoded_binary_secret = base64.b64decode(get_secret_value_response['SecretBinary'])
        return decoded_binary_secret

def lambda_handler(event, context):
    secret = get_secret()
    json_secret = json.loads(secret)

    db = pymysql.connect(
        host = 'YOUR RDS PROXY ENDPOINT',
        user = json_secret['username'], 
        password = json_secret['password']
        )

    cursor = db.cursor()
    
    cursor.execute("select now()")
    result = cursor.fetchone()

    db.commit()
    
    return {
        'statusCode': 200,
        'body': json.dumps(result[0].isoformat())
    }

해당 RDS Proxy 엔드포인트 쪽만 변경

 

이제 다 구성했으니 제대로 작동하는지 확인해보자.

  • API Gateway로 이동해 아까 생성했던 스테이지로 가서 Invoke URL 후 호출해보자
  • 연결하는데 시간이 초과한다는 에러가 나면 lambda 함수 제한 시간을 늘려주자..ㅠ
    • 이래서 서버리스는 서버리스끼리 사용하라는 듯..
    • 아니면 구성을 다시 한번 되집어 보자...(중간에 엇갈렸었음;;)

부하테스트

사실상 메인 테스트, 내가 하고 싶은 테스트를 진행해볼까 한다!

 

Cloud9 - 부하테스트 도구 Locust 구성

  • c5.24xlarge
  • VPC 변경- cloud9-subnet
pip3 install locust
locust -v

 

locustfile.py 파일 생성 후 코드 넣어주기(단순히 GET을 통한 테스트)

import time
from locust import HttpUser, task, between

class QuickstartUser(HttpUser):

    @task
    def hello_world(self):
        self.client.get("/")

 

터미널에 다음 명령어 입력해 실행하기

locust

 

web interface에서 편하게 진행하기 위해 ec2로 간다.

해당 cloud9 인스턴스에서 보안그룹을 변경해준다.

  • Custom TCP 8089 / Anywhere

http://public ip:8089를 입력해 Locust web interface에 접속한다.

  • Number of users: 동시에 실행하는 최대의 Locust user
  • Spawn rate: 초당 생성하는 Locust user
  • Host: 부하를 발생할 호스트 - 오늘의 테스트는 API Gateway Endpoint

 

1차 부하테스트

  • Number of users: 10000 / Spawn rate: 500 / Host: API Gateway Invoke URL

chart메뉴

Lambda 모니터링으로 돌아와 확인해보면, Burst Limit에 도달한 뒤 1분당 500씩 Concurrent executions이 증가하는 것을 볼 수 있다. 최초 스케일링 전 스로틀 발생했다가 Lambda가 스케일링 되면서 해소되는 것을 확인 할 수 있다.

(but, AWS에서 제공하는 기본 Concurrent executions 제한이 1000이여서 스케일링에 대한 부분 확인이 어려울 수 있음)

 

Lambda 코드 최적화

Lambda의 스로틀링을 회피해야 성능이 좋아질 듯?

그 방법에는

1) Lambda provisioned concurrency를 통해 지정한 갯수 만큼의 실행 환경을 구성해 두는 것

2) 동시성의 최소화를 위해 Lambda 함수의 실행 시간을 최적화 하는 것(얘는 모범 사례 중 하나)

 

지금 현재의 코드는 lambda_handler() 내에서 get_secret()을 통해 DB 크리덴셜 정보를 읽고 DB와 연결을 맺는 구조로 되어 있음. 이는 Lambda 가 호출될 때마다 고정된 값인 DB 크리덴셜을 읽고 새롭게 DB와 연결하는 구조라 비효율적..

 

이를 최적화 한다. 의 의미는 실행환경의 재사용성을 극대화 하는 것

현재 Lambda test를 해보면 실행시간이 약 700ms이다.

 

import json
import pymysql
import boto3
import base64

secret_name = "serverless-app-rds-secret"
region_name = "ap-northeast-2"

def get_secret():    
    session = boto3.session.Session()
    client = session.client(
        service_name = 'secretsmanager',
        region_name = region_name
    )

    get_secret_value_response = client.get_secret_value(
        SecretId=secret_name
    )

    if 'SecretString' in get_secret_value_response:
        secret = get_secret_value_response['SecretString']
        return secret
    else:
        decoded_binary_secret = base64.b64decode(get_secret_value_response['SecretBinary'])
        return decoded_binary_secret

secret = get_secret()
json_secret = json.loads(secret)

db = pymysql.connect(
    host = 'YOUR RDS PROXY ENDPOINT', 
    user = json_secret['username'], 
    password = json_secret['password']
    )

cursor = db.cursor()

def lambda_handler(event, context):
    cursor.execute("select now()")
    result = cursor.fetchone()

    db.commit()
    
    return {
        'statusCode': 200,
        'body': json.dumps(result[0].isoformat())
    }

위 코드와 같이 최적화 후에 테스트 해보면,

실행시간이 약 7ms로 최적화 된 것을 확인할 수 있음!!!

 

2차 부하테스트

Newtest 클릭!

위의 설정과 같게 돌려보자.

1차 테스트와 비교해보면 코드 최적화 이후 줄어든 Throttles와 Concurrent executions, Duration 등을 확인할 수 있다.

(Lambda 모니터링에서)

 

 

 

❗ 여기에 덧붙일만한 건 X-Ray로 모니터링 추적하는 기능 추가 정도...? 이는 다른 포스팅에 있으니.. 확인하시오!! ❗

'Cloud > AWS' 카테고리의 다른 글

[AWS] Step Functions  (0) 2022.11.18
[AWS] Spot Fleet  (0) 2022.11.16
[AWS] EC2 인스턴스 자동 중지 및 시작  (0) 2022.11.13
[AWS] GPU 인스턴스 Spot Fleet  (0) 2022.11.12
[AWS] GPU 인스턴스 유형(EC2)  (0) 2022.11.12

 

일단 방법에 뭐가 있는지 생각해보자.

그냥 단순하게 생각해봤을 떄, 제일 먼저 생각 나는 건 lambda이다.

해당 lambda가 인스턴스를 시작/중지 시킬 수 있을 것이다. 그럼 다음으로 생각해봐야 할 것은 lambda를 누가 호출 할 것이냐인데... 이 기준은 사용자가 정하면 된다. 보통 EventBridge로 스케줄링 한다.

 

정리해보면 EventBridge가 Lambda를 호출하고 해당 Lambda가 인스턴스를 중지/시작 시켜 줄 것이다.

이를 잘 활용해서 사용하면 원하는 시간대에 자동으로 시작/중지를 할 수 있을 것 같다!


인스턴스 생성

위와 같은 태그를 가진 인스턴스를 생성해준다.

- auto-schedule: True 인 태그를 가진 인스턴스만 스케줄링

 

Lambda 생성

1) IAM Role과 Policy 생성

Lambda에 EC2 인스턴스 시작 및 종료에 관한 권한이 필요하다.

인라인 정책으로 넣어줬다

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:Describe*",
                "ec2:Start*",
                "ec2:Stop*"
            ],
            "Resource": "*"
        }
    ]
}

2) EC2 start 함수 생성

위에서 만들었던 역할로 연결해줘야한다.

import boto3
region = 'ap-northeast-2'
instances = []
ec2_r = boto3.resource('ec2')
ec2 = boto3.client('ec2', region_name=region)

for instance in ec2_r.instances.all():
    for tag in instance.tags:
        if tag['Key'] == 'auto-schedule':
            if tag['Value'] == 'True':
                instances.append(instance.id)

def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances)
    print('started your instances: ' + str(instances))

제한 시간을 30초로 변경해준다.

그리고 그냥 아무 테스트 만들어서 돌려준다. 성공 로그 뜨면 완료.

 

3) EC2 stop 함수 생성

코드만 바뀌고 다른 과정은 위의 EC2 start 함수와 같다.

import boto3
region = 'ap-northeast-2'
instances = []
ec2_r = boto3.resource('ec2')
ec2 = boto3.client('ec2', region_name=region)

for instance in ec2_r.instances.all():
    for tag in instance.tags:
        if tag['Key'] == 'auto-schedule':
            if tag['Value'] == 'True':
                instances.append(instance.id)

def lambda_handler(event, context):
    ec2.stop_instances(InstanceIds=instances)
    print('stopped your instances: ' + str(instances))

해당 ec2가 중지 중인걸 볼 수 있음!

 

EventBridge 설정

규칙을 원하는대로 설정해서 생성하면 된다.(월-금 오전 9시 - 오후 6시까지 start, 나머지 stop)

  • 이름: auto-ec2-start-rule / auto-ec2-stop-rule
  • 이벤트 버스: 일단은 default로 진행
  • 규칙 유형: 일정 선택
  • 일정 패턴: cron " 0 0 ? * MON-FRI * " / " 0 9 ? * MON-FRI * " 

  • 대상: AWS 서비스 - lambda 위에서 생성한 함수 지정

시간은 UTC 기준이니 참고!!(00:00 UTC는 한국 시간으로 오전 9시)

'Cloud > AWS' 카테고리의 다른 글

[AWS] Spot Fleet  (0) 2022.11.16
[AWS] Lambda와 RDS Proxy  (0) 2022.11.14
[AWS] GPU 인스턴스 Spot Fleet  (0) 2022.11.12
[AWS] GPU 인스턴스 유형(EC2)  (0) 2022.11.12
[AWS] Lambda에 X-Ray 적용하기  (0) 2022.11.06

AWS X-Ray

  • 애플리케이션이 제공하는 요청에 대한 데이터를 수집하고 해당 데이터를 보고, 필터링하고, 통찰력을 확보하여 문제와 최적화 기회를 식별하는데 사용할 수 있는 도구를 제공
    • 마이크로 서비스 아키텍처, 서버리스 같은 분산 애플리케이션 분석 및 디버깅
    • "성능 추적(Tracing) → 트레이스 저장 → 서비스 맵 보기 → 문제 분석 "
  • 장점:
    • 애플리케이션의 전반적인 과정을 추적할 수 있다
    • 애플리케이션의 문제를 시각적으로 확인이 가능하다
    • bottleneck이 어디서 걸리는지 알고 이를 성능 향상으로 이어지게 할 수 있다
  • X-Ray Daemon:
    • Amazon Linux AMI, RHEL, Ubuntu, OS X 및 윈도 서버 설치 가능
    • {서버 내부에 X-Ray SDK - (Localhost UDP) - X-Ray Daemon} - (HTTPS) - X-Ray API
  • 비용:
    • 프리티어(영구): 100,000개의 트레이스 저장 / 1,000,000개의 스캔 및 검색
    • 추가 요금: 1백만 트레이스 저장 당 $5 / 1백만 트레이스 스캔 및 검색 당 $0.5

  • Trace: 클라이언트 부터 전체 서비스 기록(최대 크기 500KB / 저장 기간 30일)
  • Segments: 개별 서비스에서 생성된 데이터
  • Sub-segments: 원격 호출이나 개별 서비스 내 데이터 처리
  • Annotations: 별도 필터로 추적가능한 사용자 정의 데이터
  • Metadata: 필터로 추적하지 않는 비즈니스 데이터
  • Errors: 정규화된 오류 메시지

DynamoDB 테이블 생성

  • Table name: x-ray-demo
  • Primary key = id (string)
  • 나머지는 default
  • create item 을 대충 해주자.

 

Lambda  함수 생성

  • Function name= x-ray-demo
  • Runtime = Node.js 12.x
const AWS = require('aws-sdk')
exports.handler =  function(event, context, callback) {
const dynamodb = new AWS.DynamoDB()
    var params = {
        TableName: 'x-ray-demo'
    }    
    var body
    dynamodb.scan(params, function(err, data) {
        
        if (err) {
            console.log("error")
            console.log(err, err.stack)
            callback(err)
        } else {
            const response = {
                statusCode: 200,
                body: JSON.stringify(data.Items)
            }
            callback(null, response)
        }
    })
}

 

Lambda 함수를 API Gateway와 연동

Lambda 역할에 DynamoDB의 권한을 추가적으로 부여해주자

후에 API endpoint 클릭하면 DynamoDB의 레코드를 확인할 수 있다.

 

X-Ray tracing

lambda 설정에서 tracing 활성화

그 다음에 API Endpoint로 여러번 접속한 뒤에 X-Ray 대시보드로 이동해 Service Map과 Traces 확인.

Service map
Traces

DynamoDB에 대한 정보는 보이지가 않는다..

 

Lambda Layer

해당 layer를 lambda 함수에 적용해주자

const AWSXRay = require('aws-xray-sdk');
const AWS = AWSXRay.captureAWS(require('aws-sdk'));

exports.handler = function(event, context, callback) {
const dynamodb = new AWS.DynamoDB()
    var params = {
        TableName: 'x-ray-demo'
    }    
    var body
    dynamodb.scan(params, function(err, data) {
        
        if (err) {
            console.log("error")
            console.log(err, err.stack)
            callback(err)
        } else {
            const response = {
                statusCode: 200,
                body: JSON.stringify(data.Items)
            }
            callback(null, response)
        }
    })
}

 

더보기

위의 코드로 Lambda 함수 코드 수정해준다.

(참고로 Layer 생성할 때 썼던 s3 버킷 안의 코드의 경우 아래와 같은 명령어로 생성)

mkdir nodejs
cd nodejs
npm install aws-xray-sdk
zip node-xray-sdk.zip ../nodejs -r

다시 API Endpoint 몇 번 호출하고 X-Ray에서 변경된 사항을 확인해보자.

Service map
Traces

 

만약 MySQL 데이터베이스라면 아래와 같은 코드로 정의하고 사용하면 된다..

const mysql = AWSXRay.captureMySQL(require('mysql'))

 


전체적으로 어렵거나 하는 부분은 없는 느낌..(개인적으로)

이 서비스를 얼마나 어디에 잘 사용하느냐가 중요한듯

서버리스로 구성하는 경우나 그럴 때 찍어서 지연 시간이나 오류 부분 찾는 것도 나쁘지 않은듯...?!

참고: https://www.youtube.com/watch?v=xmacMfbrG28 


(Asynchronous)

Poller: 큐에서 이벤트 가져와서 데이터 처리

  • event
    • SQS에서 얻은 페이로드를 전달하여 Lambda Function을 동기 호출
    • 장애 발생 시 재시도 관리
    • 정기적으로 하트비트 보내기
    • Lambda Function 실행 결과 데이터를 Destination configuration에 지정된 AWS 서비스로 전송
  • stream
    • 샤드를 구독하고 대상 Lambda Function의 메타데이터, 배치 크기 변경을 모니터링
    • 스트리밍 소스에서 데이터를 수신하고 배치 규칙(배치 크기, 배치 창 설정)에 따라 Lambda Function을 시작
    • 스로틀링이 발생하면 재시도
    • 정기적으로 하트비트 보내기
    • 스트리밍 소스가 비활성화되거나 삭제될 때 Poller 할당 삭제

State Manager / Stream Tracker: Scaling 관리(Poller 및 event/streaming source)

Leasing Service: 이벤트 소스 또는 스트리밍 소스에서 작동하도록 Poller 할당(Poller unhealty 표시되면 새로 할당)

 

Event Processing - Handling Asynchronous and Event Based Invokes

  • 사용자가 ALB에 Lambda 비동기 실행 (InvocationType = Event 지정)을 요청
  • ALB가 Front End Invoke에 요청을 전달
  • Front End Invoke가 SQS에 메시지 보내기(SendMessage)
  • 대상 대기열을 폴링하는 Poller가 SQS에서 메시지를 수신 (ReceiveMessage)
  • Poller가 Front End Invoke에 Lambda의 동기화 호출을 요청
  • 이 후의 흐름은 동기 호출과 같다

 

Event Destinations - Providing Callbacks After Processing

  • 사용자가 ALB에 요청을 발행 ~ Poller가 동기 호출을 할 때까지 이전의 비동기 호출 시퀀스와 유사
  • 동기 호출의 결과 (성공 / 실패)에 따라 Event Destinations에 지정된 리소스에 대해 Poller가 메시지를 전달
  • Poller는 SQS에서 메시지를 삭제 (DeleteMessage)

 

Scaling Up and Down - Incoming Event Volume

State Manager - Leasing Service를 활용

State Manager는 대기열과 관련 Poller를 확장하여 수신된 이벤트를 Lambda Functions에 설정된 concurrency 까지 처리할 책임이 있음

  • State Manager가 SQS의 메시지를 확인
  • State Manager가 SQS 변경을 감지하고 Lambda Function의 동시 실행 수가 큰 경우 Leasing Service에 Poller 할당을 요청하여 새로운 큐 생성
  • Lambda Function의 동시 실행 수가 작 으면 기존 큐를 그대로 사용
  • Leasing Service는 DynamoDB에 Poller 할당 정보 작성
  • State Manager는 지정된 리소스에 여러 개의 Poller를 할당하여 중복성을 보장
  • Poller는 DynamoDB에서 할당 정보를 읽고 대기열 폴링을 시작

 

Handling Errors

Leasing Service: 정기적으로 Poller의 상태확인을 수행, heartbeat 안보낸 poller 감지 후 새 poller 할당

  • 이벤트 소스를 처리하도록 할당된 Poller가 중지됨
  • Leasing Service는 한 점 기간 내에 Poller에서 하트비트가 전송되는지 확인
  • 하트비트가 전송되지 않은 경우 Leasing Service는 새로운 Poller를 할당
  • 새 Poller가 할당 정보를 읽고 이벤트 소스 처리를 시작

 

Retry Policies

이벤트 수명: 0초 ~ 6시간

재시도 횟수 0 ~ 2 번

ex) retry 1번, DLQ 설정 O

  • 사용자가 ALB에 요청을 발행 ~ Poller가 동기 호출을 할 때까지는 위의 동기 호출 순서와 유사
  • Front End Invoke에서 오류가 반환됨
  • Poller는 대기 시간이 지나면 다시 동기화 호출을 시도
  • Front End Invoke에서 오류가 반환됨
  • Poller는 DLQ에 메시지 보냄 (SendMessage)
  • Poller는 SQS에서 메시지 삭제 (DeleteMessage)

(Stream: Poll-based)

Stream Processing

  • 사용자가 Kinesis에 레코드 추가
  • Kinesis의 샤드에 할당 된 Poller가 레코드를 얻는다
  • Front End Invoke에 Lambda의 동기화 호출

 

  • Stream Tracker가 이벤트 소스 (Kinesis 샤드 등)의 상태를 읽는다
  • Stream Tracker가 Leasing Service에 Poller 할당을 요청
  • 할당된 Poller는 이벤트 소스 샤드 구독을 시작

 

Scaling Up and Down - Incoming Event Volume

스트리밍 소스가 활성화된 경우 활성 샤드 수에서 필요한 Poller 수 계산/결정

Stream Tracker는 스트림을 처리하는 데 필요한 동시 실행 수를 계산하고 Leasing Service에 추가 Poller 요청

https://aws.amazon.com/jp/blogs/compute/new-aws-lambda-scaling-controls-for-kinesis-and-dynamodb-event-sources/

  • Stream Tracker가 listShardsAPI를 호출하여 샤드 수 변경을 감지
  • Stream Tracker는 Leasing Service를 통해 Poller 수를 조정
  • Leasing Service는 DynamoDB에 Poller 할당 정보를 쓴다
  • Poller는 DynamoDB에서 새 할당 정보를 읽고 샤드 구독을 시작

 

Handling Errors - Stream

DLQ, Exponential Backoff 지원

스트리밍 소스를 순서대로 처리하고 처리에 실패한 배치는 레코드가 만료될 때 까지 처리를 재시도

  • 사용자가 Kinesis에 레코드 추가
  • Kinesis의 샤드에 할당 된 Poller가 레코드를 얻는다
  • Front End Invoke에 Lambda의 동기화 호출
  • 처리가 실패하고 Front End Invoke가 Poller에 오류를 반환
  • Poller는 실패한 배치를 두 개의 배치로 분할하고 다시 Front End Invoke에 Lambda의 동기 호출을 수행
  • 두 배치 중 하나가 성공하면
    • Front End Invoke가 Poller에게 성공을 반환
    • Front End Invoke가 Poller에 오류를 반환
  • Poller는 재시도 후 오류가 반환된 배치를 DLQ에 보낸다

Lambda - Scale Out(Provisioned Concurrency)

왜 Provisioned Capacity가 아닌가?

  • 용량은 하드웨어에 의존한다.
    • 특정 워크로드에 필요한 용량은 하드웨어 성능에 따라 다르다. 하드웨어가 새로운 CPU, 더 빠른 메모리로 변경되면 그에 따라 필요한 용량도 변경됨.
    • 이는 고객이 하드웨어 성능에 대한 이해가 필요하다. → 서버리스의 의미에서 벗어남
  • 내결함성
    • 용량 모델은 호스트 및 AZ 장애를 고려하여 AZ 장애가 발생했을 때에도 충분한 용량을 얻을 수 있도록 설계해야함
  • 용량 모델에서 비즈니스 로직 변경이 용량 사용 효율에 영향을 줄 수 있다.
    • 비즈니스 로직 구현 팀이 기능을 추가하면 프로비저닝 된 용량에서 얻은 처리량이 변경된다.

Scale Up

  • 실행 환경이 확장되면 cold start 발생 → 지연 시간 발생(EC2나 컨테이너 기반)
  • Lambda의 경우 concurrency 기반으로 scale-up

 

우수한 웹 서비스 구축하려면..

  • 부하 제어: 처리량이 떨어지기 시작하는 전환점을 초과하지 않도록 제어
  • 빠른 Scale: 빠르게 확장 및 용량 추가가 가능해야한다.
  • 사전 프로비저닝 가능: Provisioned Concurrency 사용

'Cloud > AWS' 카테고리의 다른 글

[AWS] GPU 인스턴스 유형(EC2)  (0) 2022.11.12
[AWS] Lambda에 X-Ray 적용하기  (0) 2022.11.06
[AWS] Serverless Service - Lambda 편 (2)  (0) 2022.11.05
[AWS] Serverless Service - Lambda 편 (1)  (0) 2022.11.05
[AWS] API Gateway - Websocket API  (0) 2022.11.01

참고: https://www.youtube.com/watch?v=0PRjqEQ2J3g&t=56s 

https://www.slideshare.net/awskorea/aws-lambda-aws-aws-summit-seoul-2019


Front End Invoke: 실제 API call을 받는 역할(동기 / 비동기 호출 모두 관장)

(Synchronous Inoke)

Counting Service: 사용자가 얼마나 많은 API 요청을 하는지 모니터링하고 제한 기능 제공

Worker Manager: 실제 Container의 상태를 관리하고 API 요청을 가용 가능한 Container로 중계

Worker: 고객 함수(코드)가 안전하게 실행되는 실제 Container 환경

Placement Service: Worker에 Sandbox 구성을 자원 활용률이 높고, 고객 서비스 영향이 없도록 관리

 

Load Balancing & Auto Scaling

Load Balancing(Worker 배정 과정)
Auto Scaling(Worker Node 추가)

(Worker가 있는 건 알겠는데 얼마나 바쁜지 일을 더 줘도 되는지 Mgr가 Placement에게 물어본다.)

(필요한 Function이 일하고 사라지는 개념, 일을 다하면 리소스에 대한 return → 이 역할도 Placement 담당)

 

Handling Failures

멀티 AZ로 관리 되기 때문에 한 AZ에서 장애 발생해도 상관 없다!

 

Isolation

고객의 Workload = function = code는 항상 안전한 환경에서 실행한다.

Firecracker (하나의 host 내에서 수백개 ~ 수천개 단위의 vm 돌아갈 수 있음)

→ 하나의 코드가 그냥 독립되어서 돌아간다고 생각하면 됨

https://github.com/firecracker-microvm/firecracker

이렇게 되면 굉장히 많은 vm이 동시에 제한된 하드웨어 리소스를 공유하는 건데 충돌 발생 안하나???

→ Guest OS에서 Host OS로 접근할 때의 Driver를 개선! (firecracker device 안에서 직접적으로 하드웨어를 액세스)

(VirtIO: 게스트 커널의 디바이스 드라이버와 협력해 게스트 커널을 부팅하는데 필용한 하드웨어를 가상으로 제공)

  • Guest OS가 VirtIO 드라이버에 쓰기 요청
  • VirtIO 드라이버가 커널 링 버퍼의 공유 메모리에 요청을 PUSH
  • Firecracker가 쓰기 요청을 풀고 물리 디스크에 쓰기

Utilization

"Lambda의 경우 사용한 만큼 요금을 지불하기에 주어진 시간 내 최대한 시스템을 바쁘게 돌려야 좋다."

→ 균형 잡힌 분배가 아닌 몰빵

동일한 Workload를 한 곳에 담게 되면 자원에 대한 충돌이 일어날 확률이 높다.

→ 각 각 다른 타이밍에 다른 자원을 사용하는 멀티태스킹을 해라!

Worker 외부의 RemoteNAT 컴포넌트로 ENI와의 NAT 처리 진행

https://aws.amazon.com/ko/blogs/compute/announcing-improved-vpc-networking-for-aws-lambda-functions/

  • 시간이 많이 걸리는 처리는 Lambda Function의 스케일 시가 아닌 Lambda Function 작성 시에 실행되므로 스케일이 빨라진다
  • VPC Lambda의 대기 시간이 낮아지고 대기 시간이 예측하기 쉬워진다
  • ENI 및 IP 주소 범위에 제한을 두지 않고 VPC Lambda를 실행할 수 있다
  • 하나의 ENI를 많은 Worker에서 공유하고 이용하기 때문에 IP 주소의 소비 수가 줄어 NW 관리가 간소화된다

Lambda 와 RDS/RDBMS 접근

전형적인 DB 접근

  • 여러 가용 영역 내 Subnet에 ENI 사용: AZ 레벨의 이벤트 또는 IP 소모 문제 피할 수 있음
  • Lambda는 VPC 내 ENI로 접근: 가용 IP에 따른 확장성의 제약을 고려해야한다, ENI 신규 구성은 시간이 소모됨.
  • Public host name DNS 쿼리를 피할 수록 좋음
  • 기본적으로 VPC의 Lambda는 인터넷 접근 불가능: NAT 추가하고 Routing Table 구성 필요

 

DB 커넥션 관리는 어떻게 해야할까?

(수많은 Lambda가 필요할 때)

  • Connection Pooling과 Lamdba
    • Container 당 하나의 connection 만 사용: Connection Pool Size = 1
    • Handler 밖에 Global section 에 DB connect 객체를 생성, 재활용

 

위처럼 하면 생기는 문제점

  • Lambda container가 사라지는 지 인지할 수 없음: Connection을 명시적으로 닫을 수 없음(Database TTL에 의지)
  • Lambda container의 생성 삭제를 조정할 수 없음: Idle(대기) connection이 많이  생성될 수 있음
  • 여러 Lambda 함수 실행은 여러 다른 Container에서 실행될 수 있음: Connection 재사용 보장 못함

 

해결 방법 1: Concurrency limit

  • 계정 Concurrency 제한 / 함수 Concurrency 제한
    • AWS support - Account 제한 요청
  • Lambda는 호출 제한이 있을 경우 retry 수행/관리

"Concurrency limit: 본인의 전체 서비스에 문제가 없도록 보호하기 위해 존재, 필요에 따라 조절 가능"

  • Account level: 계정 내 모든 lambda에 적용되어 DB 접근 함수 제한이 간단하지 않음
  • Function level: 어떤 Lambda 함수가 DB 접근이 필요한지 확인, Peak 발생하기 전에 알고 App 레벨의 이해 필요

 

해결 방법 2: 동적 Connection 관리

  • 확장 가능한 구조 구현
  • Connection 수를 관리 가능, Lambda 함수 개수와 무관
  • 고려 사항: 관리 리소스 증가, Connection 재사용 불가, 약간의 Latency 증가
더보기

❗ 그래서 결론적으로 뭔 소리냐...? ❗

(Lambda + RDS의 경우 문제점)

1) lambda와 rds가 connection을 맺었는데 lambda가 명시적으로 connection 종료를 하지 않은 채 없어졌는데, 또다른 요청이 들어왔을 경우 새로운 connection을 맺게 됨...(max_connection 문제)

2) lambda가 과도하게 invoke, 실행되는 동안 모든 lambda가 connection을 맺게 되면 또 max_connection 초과

 

(해결 방안)

1) Connection 관리: handler 하나에 1 Connection / globel scope으로 connection 관리

2) RDS Proxy: Connection Pool은 Proxy가 가지고 있고, Lambda는 프록시를 통해 대신 Connection을 사용

3) API 호출 최적화: lambda가 동시에 적게 실행 + Connection이 빠르게 반환되게

 

그래도 가능하다면 DynamoDB나 AWS Aurora와 같이 Scale Out이 가능한 DB를 사용하는 것이 좋다.

 

참고: https://velog.io/@jdd04026/Lambda

 

Tip. Lambda 함수 트레이싱

  • 필요한 이유("lambda는 실행 후 사라지는 개념..")
    • 서버리스 아키텍처/애플리케이션 개발 시 Debug 편의성
    • 서버리스 아키텍처/애플리케이션 동작 시 성능 문제 해결의 편의성
  • 방법
    • CloudWatch를 통한 Metrics 모니터링
    • CloudWatch log 통한 log 분석
    • log와 metric으로 부족한 경우:
      • 전체 요청 처리 시 서버리스 함수 간의 관계 파악 확인
      • 요청 처리 시 다른 리소스 접근에 대한 관계 파악 확인
    • X-ray 서비스 활용: 서버리스 아키텍처를 만들고 람다로 서비스 개발 시 전체 흐름 확인

 

Tip. Lambda 커스텀 런타임 사용

  • Layer 기능을 활용하자!

 

'Cloud > AWS' 카테고리의 다른 글

[AWS] Lambda에 X-Ray 적용하기  (0) 2022.11.06
[AWS] Serverless Service - Lambda 편 (3)  (0) 2022.11.06
[AWS] Serverless Service - Lambda 편 (1)  (0) 2022.11.05
[AWS] API Gateway - Websocket API  (0) 2022.11.01
[AWS] Lambda Warm Start / Cold Start  (0) 2022.10.28

 Managed Level - Console

  • 구성
    • 일반구성: 기본 설정 관련
      • 메모리: 메모리에 비례하는 CPU가 함수에 할당/Compute Optimizer 옵트인 가능
      • 임시 스토리지: /tmp 디렉터리, 최대 10GB까지 대기 시간이 짧은 안전한 임시 파일 시스템 액세스
      • 제한 시간, 실행 역할
    •  트리거
      • 소스: Alexa, Apache Kafka, API Gateway, ALB, CW Logs, CodeCommit, Cognito Sync Trigger, DynamoDB, EventBridge, Kinesis, MQ, MSK, S3, SNS , SQS 등..
    • 권한
      • Lambda 실행 역할 / 태그 기반 액세스 제어 / 리소스 기반 정책 등..
    • 대상
      • 소스가 비동기식 호출: SNS, SQS, Lambda, EventBridge
      • 소스가 스트림 호출: Kinesis, DynamoDB
    • 함수 URL: Lambda에 고유한 HTTP(S) 엔드포인트 추가
      • 언제 사용할까?
    • 환경 변수: key-value
    • 태그
    • VPC: (default로 퍼블릭으로 액세스 가능한 리소스로 deploy)
    • 모니터링 및 운영 도구: CW, X-Ray, CW Lambda Insights
    • 동시성: 함수에 대한 최대 동시 실행 횟수 설정
    • 비동기식 호출: 처리되지 않은 이벤트 처리
      • lambda가 자체적으로 재시도를 처리(최대 2번)
      • 그래도 스로틀 발생, 오류 반환 시 대기열에 보관(최대 6시간)
      • 보관 이후에 삭제하는데 이를 SQS나 SNS로 전송(배달 못한 편지 대기열)
    • 코드 서명: 신뢰할 수 있는 코드만 함수에서 실행되도록
    • 데이터베이스 프록시
      • 데이터베이스 연결 풀 관리
    • 파일시스템: EFS 연결
    • 상태 머신: Step Functions
  • 별칭: 함수 버전을 매핑
  • 버전

Code Level(Python 기준)

  • Lambda Handler Function:
    • Lambda 콘솔의 기본 이름: lambda_function.lambda_handler
      • lambda_handler: 함수 이름(핸들러 이름 바꾸고 싶으면 여길 바꾸면 됨)
      • lambda_function: 핸들러 코드가 저장된 파일
##Global Scope

def lambda_handler(event, context):
	## business logic here
    return response
  • event: 
    • Lambda가 Invoke 될 때 다른 서비스에서 이벤트 (혹은 데이터) 를 전달 받는다.
    • 어떤 서비스로부터 Invoke 되었는지에 따라 event의 구조가 달라진다.
    • Invoke 방식에는 Event / RequestResponse 로 나뉨.
      • RequestResponse: API Gateway → Lambda
      • Event: Response를 바라진 않음. 이벤트 전달이 목적!(Asynchronous)
    • Lambda가 Event 방식으로 호출된 경우, 실행 결과로 response 값이 있으면 이 데이터는 Invoke를 요청한 클라이언트에게 다시 전달될까? → NO!
import os

def lambda_handler(event, context):
    print('## ENVIRONMENT VARIABLES')
    print(os.environ)
    print('## EVENT')
    print(event)
더보기

 여기서 착각했던게 있는데...

이 테스트 이벤트의 경우에는 테스트를 위한거고 실제적으론 함수를 invoke 하는 서비스의 이벤트를 받는 것!

테스트 용으로 람다 함수가 잘 작동하는지 확인하고 해당 서비스와 트리거를 하던 연결을 하던 해서 사용하면 될듯..

(아마 서비스마다 들어오는 이벤트 형식이 지정되어있는 것 같다... 테스트 이벤트 템플릿 보면 겁네 많음)

  • context:
    • Lambda의 Runtime 정보를 핸들러에게 제공
      • function_name, function_version, invoked_function_arn, memory_limit_in_mb, aws_request_id, log_group_name 등..(로깅 등의 용도로 사용할 수 있는 메타데이터)
      • 오랫동안 실행되는 Lambda의 경우 get_remaining_time_in_millis() 가 쓸모 있을지도..
import time

def lambda_handler(event, context):   
    print("Lambda function ARN:", context.invoked_function_arn)
    print("CloudWatch log stream name:", context.log_stream_name)
    print("CloudWatch log group name:",  context.log_group_name)
    print("Lambda Request ID:", context.aws_request_id)
    print("Lambda function memory limits in MB:", context.memory_limit_in_mb)
    # We have added a 1 second delay so you can see the time remaining in get_remaining_time_in_millis.
    time.sleep(1) 
    print("Lambda time remaining in MS:", context.get_remaining_time_in_millis())
  • Global Scope:
    • 핸들러 바깥의 영역으로 init(cold start 시)에만 실행되는 부분
    • Worker 노드가 종료되지 않으면 메모리에 남아있음(캐시처럼 사용할 수 있는 트릭)
    • 모놀리식 구조로 코드 작성했을 때 RDS 커넥션 추가해도 괜찮다..
      • but, 함수를 기능별로 나눴을 경우 RDS 커넥션 해두고 끊지 않으면 DB 쪽에서 max_connection에 걸릴 수도.. → Global Scope에 연결하는 것보다 사용할 때마다 연결 하고 끊는게 좋다
    • init은 했는데 terminate을 따로 안해주니까 이런 경우에 시스템이 어떻게 동작할까에 대한 고민을 해라!
  • 로깅:
  • 오류:
    • Lambda invoke → 호출 요청 수신 → 검증 과정
      • 실행 역할 권한 검증 → 이벤트 문서가 유효한 JSON 문서인지 확인 → 파라미터 값 검사
    • 요청이 검증을 통과하면 Lambda가 함수 인스턴스로 요청을 보냄
      • Lambda 런타임 환경의 경우 이벤트 문서를 객체로 변환한 후 함수 핸들러에 전달
    • 오류 발생 반환: 예외 유형(오류의 원인), 메시지 및 HTTP 상태 코드

Infra Level

  • Lambda Invoke:
    • Invocation Type: Invoke 시 어떤 방식으로 실행할지 결정 가능
      • Event: Asynchronous 방식
        • Lambda 함수가 성공했는지 여부를 알 수 없음
        • Invoke Event를 잘 수신했다(Accept의 의미): "StatusCode: 2XX"
        • → 코드가 잘 동작했는지 확인할 수 있는 방법이 없어 DLQ가 필수다!
        • S3, SNS, EventBridge (CloudWatch Events)
      • RequestResponse(default): Synchronous 방식
        • "StatusCode: 200" : 성공적으로 잘 수행했다
        • Kinesis, DynamoDB Streams, SQS, ALB, API Gateway
      • DryRun: 파라미터 및 권한을 검사해서 실행 가능한지에 대한 체크(실제 Invoke는 아님)
    • Asynchronous invocation:
      • event를 queue(SQS)에 넣는다 : Lambda 내부적으로 queue를 가지고 있음
        • lambda 함수가 적절한 타이밍에 큐에 쌓인 이벤트를 처리를 못하면 이벤트가 손실 될 수 있음
        • 따라서, 반드시 수행되어야하는 태스크는 별도의 고객 소유 SQS를 통해 Invoke 시켜야함
          • lambda + sqs + lambda 의 구조가 best practice
      • 하나의 이벤트를 중복처리하는 경우도 존재:
        • Event-driven 방식으로 동작하는 함수는 반드시 Idempotency(멱등성)를 고려하여 작성
      • 함수 실패의 경우 Dead Letter Queue를 통해 알림 받기 가능
    • Invocation Type에 따른 Lambda 트러블 슈팅:
      • 대량의 데이터를 SQS에 넣었다. Lambda를 Invoke 시키는 시나리오에서 Lambda 실패, 데이터는 어디로 갈까? Lambda 함수는 기다리고 있으면 다시 또 실행될까?
        • SQS는 RequestResponse(Synchronous) 방식: retry를 몇 번 시도 후 그래도 실패하면 실패 이벤트 처리로 넘어감. → 실패 시 고객이 SQS의 처리상태를 통해 직접 알 수 있음
      • 대량의 파일을 S3에 업로드해서 Lambda를 Invoke 시키는 시나리오에서 실패했다, 이벤트는 어디로 갈까? Lambda 함수는 기다리고 있으면 다시 또 실행될까?
        • S3 는 Event(Asynchronous) 방식: retry 몇 번 시도 후 실패시 이벤트 손실이 생길 수 있음 → DLQ를 지정하는 방법밖에 없음(Lambda 내부 문제)

 

Lambda 내부 아키텍처

  • 컴포넌트들이 달성하고자 하는 목표?
    • Load Balancing
    • Scaling Up and Down
    • Handling Failures
    • Predictable Low Latency
    • Security Isolation
    • Managing Utilization
    • ...

 

  • Synchronous Invoke:
    • Front End Invoke: IAM Policy, Role 확인(authentication) / Concurrency 더 수행할 수 있는지 / 메타데이터 확인 등
    • Counting Service: concurrency limit을 넘지 않는지
      • 근데 concurrency를 초과해서 실행될 수 있음 → limit에 도달하자마자 막으면 고객들이 maximum concurrency를 누릴 수 없음
    • Worker Manager: Front End와 함께 AutoScaling
    • Worker: sandbox 구성(해당 cpu, memory limit 설정, 고객 코드, runtime, 실행환경 초기화 등..)
    • Placement Service

(Alb(우리한텐 안보임)가 받아 Front End로 Front End가 Worker Mgr에게 sandbox 가져오라고 명령

sandbox 있으면 Worker 가져오고,

없으면 Placement 에게 sandbox 만들 수 있는 Worker 달라고 요청, Worker를 Worker Mgr에게 전달, Worker Mgr가 sandbox에 init command 날리고 Front End에게 전달 Front End가 코드 invoke 명령어 내리고

결과가 Alb를 통해 나간다.)

→ Warm Sandbox 존재: Claim Worker 과정과, init 과정이 필요 없음! (빠르게 invoke 가능) ⇒ Warm Start

Warm Sandbox 없음: Claim Worker 과정과 init 과정 필요 (지연이 있음) ⇒ Cold Start

 

  • Asynchronous Invoke:
    • Poller: 큐에 저장된 이벤트 꺼내와서 처리되는 과정을 전부 관리
    • State Manager/Stream Tracker: Poller 서비스를 스케일링, 이벤트 소스 스트림을 관리하거나 등..
    • Leasing Service: 어떤 Poller 서비스가 어떤 이벤트를 담당할건지

(synchronous와 Front End까진 같다, Font End에서 Worker Mgr로 가면 sync / SQS로 가면 async

Front End에서 SQS로 넣게 되면 함수 결과값으로 StatusCode: 2XX 던져주고 끝.

SQS에서 Poller가 이벤트 가져와야하는데 어떤 Poller가 어떤 이벤트 담당할지 결정하는게 Leasing Service(그림엔 없음)

SQS에서 메시지를 가져온 Poller가 새로운 클라이언트가 되어서 Front End를 호출할 때 RequestResponse 방식으로 호출 - 이 뒤로는 sync와 똑같이 이루어진다.)

 

Firecracker

 

+ Recent posts