AWS Lambda 기본 구조: 서버리스 아키텍처와 Cold Start 이해하기

2026. 6. 7. 06:46Cloud/AWS

반응형

API Gateway 뒤에 Lambda를 연결했는데, 첫 번째 요청만 유독 느립니다. 이후 요청은 50ms 이내로 응답하지만, 트래픽이 없다가 다시 들어오면 1~2초가 걸립니다. 서버를 직접 관리하지 않아도 된다는 서버리스의 장점은 분명하지만, 이 지연은 어디서 오는 걸까요? Lambda의 실행 환경 구조를 이해하면 이 문제의 원인과 대응 방법이 명확해집니다.

요약

항목 내용
서비스 유형 FaaS (Function as a Service) — 이벤트 기반 서버리스 컴퓨팅
실행 환경 수명 주기 Init → Invoke → (재사용 또는) Shutdown
Cold Start 원인 새 실행 환경 생성 시 Init 단계에서 발생하는 초기화 지연
런타임별 Cold Start Python/Node.js: 100~300ms, Java/.NET: 1~5초 (SnapStart 미적용 시)
완화 전략 Provisioned Concurrency, SnapStart, 경량 패키징, 메모리 증가
과금 기준 요청 수 + (메모리 × 실행 시간), 1ms 단위
Free Tier 월 100만 요청 + 400,000 GB-초 (상시 무료)
주요 제약 최대 실행 시간 15분, 메모리 128MB~10,240MB

1. Lambda란 무엇인가: 서버리스 컴퓨팅의 핵심

AWS Lambda는 코드를 실행할 서버를 프로비저닝하거나 관리하지 않고, 이벤트가 발생할 때만 코드를 실행하는 FaaS(Function as a Service)입니다.

서버리스의 핵심 특성:

  • 인프라 관리 불필요: OS 패치, 스케일링, 가용성을 AWS가 처리
  • 이벤트 드리븐: API 호출, S3 업로드, SQS 메시지, CloudWatch 스케줄 등 다양한 트리거에 반응
  • 사용한 만큼 과금: 요청이 없으면 비용이 0원 — EC2처럼 유휴 상태에서 비용이 발생하지 않음
  • 자동 스케일링: 동시 요청 수에 따라 실행 환경이 자동으로 생성/제거
Lambda 서버리스 아키텍처 개념
Lambda 서버리스 아키텍처 개념

실무 시나리오: 언제 Lambda를 선택하는가

스타트업에서 이미지 업로드 서비스를 운영한다고 가정합니다. 사용자가 S3에 이미지를 업로드하면 썸네일을 생성하고, 메타데이터를 DynamoDB에 저장하는 작업이 필요합니다.

  • EC2를 사용하면: 트래픽이 없는 새벽에도 인스턴스가 돌아가며 비용이 발생합니다. Auto Scaling을 설정해도 최소 1대는 유지해야 합니다.
  • Lambda를 사용하면: S3 이벤트가 발생할 때만 코드가 실행됩니다. 하루 1,000건이든 100,000건이든 자동으로 확장되고, 요청이 없으면 비용이 0원입니다.

이 패턴이 Lambda의 가장 대표적인 사용 사례입니다. 다만 모든 워크로드에 적합한 것은 아닙니다. 15분 이상 실행되는 배치 작업, 상태를 유지해야 하는 WebSocket 연결, 일정한 부하가 계속되는 서비스에는 ECS/EKS나 EC2가 더 적합할 수 있습니다.

2. Lambda 실행 환경의 수명 주기

Lambda 함수가 호출되면 AWS는 격리된 실행 환경(Execution Environment)을 생성합니다. 이 환경은 세 단계를 거칩니다.

Lambda 실행 환경 수명 주기
Lambda 실행 환경 수명 주기

Init 단계 (초기화)

실행 환경이 처음 생성될 때 한 번 실행됩니다.

  1. 런타임 초기화: Lambda가 지정된 런타임(Python, Node.js, Java 등)을 시작
  2. Extension 초기화: Lambda Layer나 Extension이 있다면 함께 초기화
  3. 함수 초기화: 핸들러 밖에 위치한 코드 실행 (모듈 임포트, DB 커넥션 생성, 설정 로드 등)
import boto3
import json

# Init 단계에서 실행됨 — 실행 환경이 재사용되는 동안 유지
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Users')

def lambda_handler(event, context):
    # Invoke 단계에서 실행됨 — 매 요청마다 실행
    user_id = event['pathParameters']['id']
    response = table.get_item(Key={'userId': user_id})
    return {
        'statusCode': 200,
        'body': json.dumps(response.get('Item', {}))
    }

Init 단계의 제한 시간은 10초입니다. 이 시간을 초과하면 Lambda가 첫 번째 호출 시점에서 전체 함수 타임아웃을 적용해 재시도합니다.

Invoke 단계 (실행)

이벤트를 받아 핸들러 함수를 실행하는 단계입니다. 응답을 반환하거나 타임아웃에 도달할 때까지 지속됩니다. 하나의 실행 환경은 한 번에 하나의 요청만 처리합니다.

Shutdown 단계 (종료)

일정 시간 동안 요청이 없으면 AWS가 실행 환경을 제거합니다. 정확한 유휴 시간은 공개되지 않았지만, 일반적으로 5~15분 사이로 알려져 있습니다. Extension이 등록되어 있다면 종료 전 정리 작업을 수행할 기회가 주어집니다.

실행 환경 재사용 (Warm Start)

Init 이후 실행 환경이 살아있는 동안은 Invoke 단계만 반복됩니다. 이것이 "Warm Start"입니다. Init 단계의 오버헤드가 없으므로 응답 시간이 크게 줄어듭니다.

설계 관점에서 중요한 점: 핸들러 밖의 코드는 실행 환경이 유지되는 동안 한 번만 실행됩니다. DB 연결, SDK 클라이언트 초기화, 설정 파일 로드 같은 비용이 큰 작업은 핸들러 밖에 배치해야 합니다.

3. Cold Start란 무엇인가

Cold Start는 새로운 실행 환경을 생성해야 할 때 Init 단계에서 발생하는 추가 지연입니다. 사용자 입장에서는 "첫 요청이 느린 현상"으로 체감됩니다.

Cold Start 발생 흐름
Cold Start 발생 흐름

Cold Start가 발생하는 상황

상황 설명
첫 번째 호출 함수 배포 후 아직 실행 환경이 없을 때
유휴 후 재호출 일정 시간 요청이 없어 환경이 종료된 후
동시성 급증 기존 환경이 모두 사용 중일 때 새 환경을 추가로 생성
코드 업데이트 새 버전 배포 시 기존 환경이 교체됨

런타임별 Cold Start 차이

Cold Start 시간은 런타임, 패키지 크기, 할당 메모리에 따라 크게 달라집니다.

런타임 일반적인 Cold Start 범위 특성
Python 100~400ms 인터프리터 방식으로 초기화가 빠름
Node.js 100~500ms V8 엔진 시작이 가벼움. SDK v3 내장
Go 50~200ms 컴파일된 바이너리로 가장 빠름
Java 1~5초 JVM 시작 + 클래스 로딩 오버헤드 (SnapStart로 완화 가능)
.NET 1~3초 CLR 초기화 오버헤드 (SnapStart로 완화 가능)

이 수치는 최소 의존성 기준이며, 실제 프로덕션 함수에서는 패키지 크기와 초기화 로직에 따라 더 길어질 수 있습니다.

Cold Start에 영향을 주는 요소

  1. 패키지 크기: 배포 패키지가 클수록 다운로드·압축 해제 시간 증가
  2. 메모리 설정: Lambda는 메모리에 비례하여 CPU를 할당 — 메모리가 작으면 Init도 느림
  3. VPC 연결: VPC에 연결된 Lambda는 ENI(Elastic Network Interface) 생성이 필요 (다만 2019년 이후 개선되어 이전만큼 크지 않음)
  4. 런타임 특성: JVM, CLR처럼 VM을 시작하는 런타임은 인터프리터 방식보다 느림
  5. 초기화 코드: SDK 클라이언트 생성, 외부 설정 로드, 연결 풀 초기화 등

4. Cold Start 완화 전략

Cold Start를 완전히 제거할 수는 없지만, 실무에서 사용하는 완화 전략이 있습니다.

Cold Start 완화 전략 비교
Cold Start 완화 전략 비교

Provisioned Concurrency

미리 지정한 수만큼 실행 환경을 Warm 상태로 유지합니다. 항상 Init이 완료된 환경이 대기하므로 Cold Start가 발생하지 않습니다.

aws lambda put-provisioned-concurrency-config \
  --function-name my-api-handler \
  --qualifier prod \
  --provisioned-concurrent-executions 10

trade-off: - 장점: Cold Start 완전 제거, 일정한 응답 시간 보장 - 단점: 유휴 상태에서도 비용 발생 — 서버리스의 "사용한 만큼 과금" 이점이 줄어듦 - 적합한 경우: API Gateway 뒤의 사용자 대면 API, 지연 시간 SLA가 있는 서비스

SnapStart

Java, Python, .NET 함수에서 사용할 수 있는 기능으로, Init 단계 완료 후의 메모리 스냅샷을 저장해두고 Cold Start 시 이를 복원합니다. 2022년 re:Invent에서 Java용으로 발표되었고, 2024년 11월에 Python과 .NET으로 확장되었습니다.

# SAM 템플릿 예시
Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: python3.13
      SnapStart:
        ApplyOn: PublishedVersions

trade-off: - 장점: 추가 비용 없이 Cold Start를 수백 ms 이내로 줄일 수 있음 - 단점: 함수 버전 발행 시 스냅샷 생성에 시간이 걸림, 네트워크 연결이나 난수 생성기 같은 고유 상태(uniqueness) 주의 필요 - 적합한 경우: Java/Python/.NET 함수에서 Provisioned Concurrency 비용 없이 Cold Start를 줄이고 싶을 때

코드 레벨 최적화

전략 설명
패키지 경량화 사용하지 않는 의존성 제거, Tree-shaking 적용
메모리 증가 1,769MB 이상에서 전체 vCPU 1개가 할당되어 Init 속도 향상
Graviton2 (ARM) 선택 x86 대비 20% 저렴하고 초기화 성능 향상
전역 초기화 활용 DB 연결, SDK 클라이언트를 핸들러 밖에 배치
지연 로딩 핸들러 내에서 필요할 때만 무거운 모듈 임포트

아키텍처 레벨 선택

모든 API에 Lambda를 사용해야 하는 것은 아닙니다. 지연 시간에 민감하고 트래픽이 일정한 서비스라면 ECS Fargate나 App Runner가 더 적합할 수 있습니다. Lambda는 이벤트 드리븐 워크로드, 간헐적 트래픽, 빠른 스케일링이 필요한 경우에 강점이 있습니다.

5. Lambda 과금 구조와 비용 설계

Lambda 비용은 세 가지 요소로 결정됩니다.

과금 요소 단가 (x86, us-east-1 기준)
요청 수 $0.20 / 100만 요청
실행 시간 $0.0000166667 / GB-초
Provisioned Concurrency $0.0000041667 / GB-초 (유휴 포함)

Free Tier (상시 무료): 월 100만 요청 + 400,000 GB-초

비용 계산 예시: 128MB 메모리 함수가 월 300만 회 호출되고, 평균 실행 시간이 200ms라면: - 요청 비용: (300만 - 100만) × $0.20 / 100만 = $0.40 - 실행 시간: 300만 × 0.2초 × 0.125GB = 75,000 GB-초 - 무료 공제: 75,000 - 400,000 = 0 (Free Tier 내) - 총 비용: 약 $0.40/월

소규모 서비스에서 비용이 거의 발생하지 않는 이유가 여기에 있습니다. 다만 트래픽이 크게 늘거나 Provisioned Concurrency를 사용하면 비용 구조가 달라집니다.

2025년 8월 과금 변경: INIT 단계 표준화

2025년 8월부터 ZIP 패키지 + 매니지드 런타임을 사용하는 함수의 INIT 단계도 과금 대상에 포함됩니다. 이전에는 INIT 시간이 과금되지 않았으나, 이제 Init을 포함한 전체 실행 시간에 대해 동일하게 과금됩니다. 초기화 코드를 효율적으로 작성하는 것이 비용 관점에서도 중요해졌습니다.

6. 실무 적용: API 서비스에 Lambda를 사용할 때 판단 기준

Lambda가 적합한 경우

  • 트래픽이 간헐적이거나 예측 불가능 (스타트업 초기, 내부 도구)
  • 이벤트 처리 파이프라인 (S3 → Lambda → DynamoDB)
  • 마이크로서비스의 개별 API 엔드포인트
  • 스케줄 기반 배치 작업 (15분 이내)
  • 비용을 최소화해야 하는 초기 서비스

Lambda가 부적합할 수 있는 경우

  • p99 지연 시간 SLA가 엄격하고 Cold Start를 허용할 수 없을 때 (Provisioned Concurrency 비용 대비 ECS가 효율적일 수 있음)
  • 15분 이상 실행되는 작업
  • 상시 높은 부하 (비용 역전: 일정 트래픽 이상에서는 EC2/Fargate가 더 저렴)
  • WebSocket, 장시간 연결이 필요한 서비스
  • GPU가 필요한 ML 추론

의사결정 흐름

질문 순서로 판단할 수 있습니다:

  1. 실행 시간이 15분을 초과하는가? → Yes: ECS/EC2
  2. 트래픽이 일정하고 높은가? → Yes: Fargate/EC2 (비용 역전 분석 필요)
  3. Cold Start가 비즈니스에 영향을 주는가? → Yes: Provisioned Concurrency 또는 SnapStart 적용 가능한지 확인
  4. 이벤트 기반인가, 간헐적인가? → Yes: Lambda 적합

마무리

Lambda의 Cold Start는 서버리스 아키텍처의 구조적 특성에서 비롯됩니다. 서버를 미리 유지하지 않기 때문에 비용은 줄어들지만, 새 환경 초기화 지연이 발생합니다. 이 trade-off를 이해하고, 워크로드 특성에 맞는 완화 전략을 선택하는 것이 설계의 핵심입니다.

관련 글: - AWS VPC란 무엇인가: Subnet, Route Table, Internet Gateway 개념 정리 — Lambda를 VPC에 연결할 때 네트워크 구조 이해 - NAT Gateway와 VPC Endpoint 차이 — VPC Lambda의 외부 통신 설계 - AWS ECS vs EKS 차이 — Lambda 대안으로 컨테이너 오케스트레이션을 고려할 때

반응형