CertNote/ 출퇴근 학습 노트
로드맵
KOEN
CLF-C02 · FoundationalCloud Practitioner - Foundational
DVA-C02 · AssociateDeveloper - Associate
  • Week 1
    • 1.개발자 시점에서 본 AWS: 리전, 인프라, 그리고 책임의 경계
    • 2.IAM의 4대 엔터티: User, Group, Role, Policy
    • 3.STS와 정책 조건: 임시 자격증명의 깊은 세계
    • 4.AWS CLI와 SDK: 자격증명 체이닝부터 SigV4까지
    • 5.Week 1 종합: 인프라와 IAM이 만드는 신뢰의 사슬
  • Week 2
  • Week 3
    • 1.Lambda Execution Model: Firecracker MicroVM이 함수를 실행하는 방법
    • 2.Lambda 이벤트 소스 매핑: SQS·Kinesis·DynamoDB Streams 내부 폴링 메커니즘
    • 3.Lambda 버전·별칭·레이어: Immutable 배포와 의존성 분리의 원리
    • 4.Lambda 동시성 제어: Token Bucket 알고리즘과 에러 처리 계층
    • 5.Week 3 복습: Lambda 종합 시나리오로 실전 감각 다지기
  • Week 4
  • Week 5
  • Week 6
  • Week 7
  • Week 8
  • Week 9
  • Week 10
  • Week 11
  • Week 12
  • Week 13
SAA-C03 · AssociateSolutions Architect - Associate
SOA-C02 · AssociateCloudOps Engineer - Associate
SAP-C02 · ProfessionalSolutions Architect - Professional
DOP-C02 · ProfessionalDevOps Engineer - Professional
SCS-C03 · SpecialtySecurity - Specialty
MLA-C01 · AssociateMachine Learning Engineer - Associate
AIF-C01 · FoundationalAI Practitioner - Foundational
DEA-C01 · AssociateData Engineer - Associate
MLS-C01 · SpecialtyMachine Learning - Specialty
합격 후기

© CertNote · 주간랩스

  • 소개
  • 수정 기록
  • 문의
  • 이용약관
  • 개인정보처리방침
← DVA-C02/Week 3/Day 4

기준: DVA-C02 시험 가이드·오류 제보

DVA-C02· AssociateWeek 3 · Day 4읽기 약 11분

Day 4 - Lambda 동시성 제어: Token Bucket 알고리즘과 에러 처리 계층

Lambda의 동시성 모델은 처음 보면 단순해 보인다. "함수가 동시에 몇 개 실행되느냐"의 문제처럼 보인다. 하지만 실제로는 계정 전체 한도, 함수별 Reserved 동시성, Provisioned 동시성, 버스트 한도라는 네 개의 다른 메커니즘이 중첩되어 있고, 이 계층 구조를 이해하지 못하면 "내 Lambda가 왜 429를 뱉는지", "왜 다른 팀 함수 때문에 내 함수가 느려지는지"를 설명할 수 없다.

에러 처리도 마찬가지다. 동기, 비동기, ESM 세 가지 호출 방식은 에러가 발생했을 때 완전히 다르게 반응한다. 이걸 모르면 Kinesis 샤드가 통째로 막히거나, SQS 메시지가 영원히 재처리되는 사고로 이어진다.

동시성의 정의와 계산

Lambda 동시성은 특정 시점에 동시에 실행 중인 함수 인스턴스 수다. 공식은 간단하다.

동시성 = 초당 요청 수(RPS) × 평균 실행 시간(초)

예:
- RPS = 1,000, 평균 실행 시간 = 200ms(0.2초)
- 동시성 = 1,000 × 0.2 = 200

- RPS = 100, 평균 실행 시간 = 5초
- 동시성 = 100 × 5 = 500

이 공식에서 보이는 것처럼, 실행 시간이 길수록 동시성 소비가 크다. 타임아웃을 15분으로 설정한 Lambda가 100개 동시 실행되고 있다면, 그 15분 동안 1,500 동시성을 차지한다 — 계정 기본 한도(1,000)를 이미 초과한다.

동시성 네 계층의 완전한 그림

계정/리전 전체 한도: 1,000 (기본, 증가 요청 가능)
│
├── [함수 A] Reserved: 300 → 최대 300개 인스턴스
│   └── Provisioned: 20 → 항상 20개 미리 초기화
│
├── [함수 B] Reserved: 200 → 최대 200개 인스턴스
│
└── [나머지 함수들] 공유 풀: 500 (1000 - 300 - 200)
    └── Reserved 없는 모든 함수가 이 500을 두고 경쟁

Reserved Concurrency(예약 동시성):

  • 함수의 동시성 상한선이자 전용 할당
  • 이 함수는 최대 N개까지만 실행되고, 다른 함수가 이 N개를 쓸 수 없다
  • 0으로 설정하면 완전 차단(ThrottlingException)
  • 비용: 없음

Provisioned Concurrency(프로비저닝된 동시성):

  • 지정한 수만큼 MicroVM을 미리 초기화해 대기
  • 콜드 스타트 없이 즉시 INVOKE 단계만 실행
  • 반드시 버전 또는 별칭에만 설정 가능 ($LATEST 불가)
  • 비용: 초기화된 인스턴스 수 × 시간 × 메모리(GB) × $0.0000097222/GB-초
# Reserved Concurrency 설정
aws lambda put-function-concurrency \
  --function-name payment-api \
  --reserved-concurrent-executions 300
 
# 완전 차단 (모든 요청 즉시 ThrottlingException)
aws lambda put-function-concurrency \
  --function-name maintenance-mode-function \
  --reserved-concurrent-executions 0
 
# Provisioned Concurrency (별칭에)
aws lambda put-provisioned-concurrency-config \
  --function-name payment-api \
  --qualifier prod \
  --provisioned-concurrent-executions 20

⚠️ 함정: Reserved Concurrency를 설정하면 계정 전체 풀에서 그만큼이 차감된다. 함수 A에 Reserved=500을 설정하면 나머지 함수들은 500만 공유한다. 함수들이 많이 동시에 실행되는 피크타임에 "왜 갑자기 다른 함수들이 스로틀링 되지?"라는 상황이 Reserved 설정 때문에 발생하는 경우가 있다.

버스트 동시성 한도: 스케일아웃의 속도 제한

Lambda는 트래픽 급증 시 자동으로 동시성을 늘린다. 하지만 무한정 빠르게 늘릴 수는 없다.

스케일링 속도: 함수마다, 리전마다 10초에 실행 환경 1,000개까지 늘어난다(초당 요청 기준으로는 10초마다 10,000 RPS). 2023년 말 이 방식으로 바뀌었다.

이전 방식: 계정 단위로 첫 1분에 리전별 500~3,000개를 늘리고, 그 뒤 분당 500개씩 늘렸다. 오래된 자료와 문제집에 이 수치가 남아 있으니 구분한다.

이 의미는: 갑자기 5,000 동시성이 필요한 트래픽이 들어오면, 계정 한도가 5,000 이상일 때 약 50초(10초마다 +1,000)에 걸쳐 늘어난다. 계정 한도가 기본값 1,000이면 1,000에서 멈춘다. 속도 한도는 함수 단위라 함수마다 따로 적용된다. 쓰지 않은 속도 여유분은 다음 10초로 이월되지 않는다.

이 속도나 한도를 넘는 요청은 스로틀링 에러(429)를 받는다.

CloudWatch 메트릭으로 동시성 문제 진단

메트릭네임스페이스의미높으면 조치
ConcurrentExecutionsAWS/Lambda현재 동시 실행 수Reserved 한도에 근접하면 증가 고려
ThrottlesAWS/Lambda스로틀된 호출 수Reserved/계정 한도 증가
ProvisionedConcurrencyUtilizationAWS/LambdaPC 사용률80% 이상 지속 시 PC 추가
IteratorAgeAWS/LambdaKinesis/DDB Streams 처리 지연계속 증가 → ParallelizationFactor 늘리기
DeadLetterErrorsAWS/LambdaDLQ 전송 실패DLQ 권한(IAM) 확인
# CloudWatch에서 동시성 메트릭 조회
aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda \
  --metric-name ConcurrentExecutions \
  --dimensions Name=FunctionName,Value=payment-api \
  --start-time 2026-05-31T00:00:00Z \
  --end-time 2026-05-31T23:59:59Z \
  --period 300 \
  --statistics Maximum

💡 관련 이론: IteratorAge는 현재 시간과 Kinesis/DynamoDB Streams에서 처리 중인 레코드의 Put 시간 차이다. 이 값이 계속 증가하면 Lambda가 스트림 속도를 따라잡지 못하는 것이다. 해결책은 Kinesis 샤드 수 증가(처리량 분산), Lambda ParallelizationFactor 증가(샤드당 병렬 Lambda 수), 또는 Lambda 실행 시간 최적화다.

에러 처리 계층: 호출 방식별 완전 비교

에러가 발생했을 때 "누가 재시도하는가", "어디로 실패 이벤트가 가는가"가 호출 방식마다 완전히 다르다.

동기 호출 (API Gateway, ALB, 직접 invoke):

  • Lambda가 에러를 던지면 HTTP 200 + FunctionError 헤더로 응답
  • 재시도는 호출자의 책임 (API Gateway 기본: 재시도 없음)
  • DLQ 없음. 에러 이벤트가 어디로도 가지 않는다
  • 클라이언트가 503이나 500을 받으면 직접 재시도 구현 필요

비동기 호출 (S3, SNS, EventBridge, 직접 invoke Event 타입):

  • Lambda 서비스가 내부 큐에 이벤트를 보관
  • 자동 재시도: 최대 2회, 1분/2분 간격(지수 백오프)
  • 최종 실패 시 DLQ(SQS 또는 SNS) 또는 Destinations OnFailure로 전송
  • 이벤트 나이 최대 21,600초(6시간) — 그 이후엔 처리 안 됨

ESM 폴링 (SQS, Kinesis, DDB Streams):

  • SQS: 가시성 타임아웃 후 메시지가 큐로 복귀. maxReceiveCount 초과 시 SQS DLQ
  • Kinesis/DDB Streams: 기본 무한 재시도(샤드 블록 발생). MaximumRetryAttempts로 제한 필수
  • Lambda 함수의 DLQ와 SQS 큐의 DLQ는 완전히 다른 개념
호출 방식별 에러 처리 흐름

[동기 - API Gateway]
클라이언트 → API GW → Lambda → 에러 발생
                              ↓
              API GW에 FunctionError 응답
                              ↓
              클라이언트에 5XX 반환 (API GW 설정에 따라)
              재시도 = 클라이언트 코드가 결정

[비동기 - S3]
S3 업로드 → Lambda 내부 큐 → Lambda 실행 → 에러 발생
                               ↓
                         1분 후 자동 재시도
                               ↓ (또 실패)
                         2분 후 자동 재시도
                               ↓ (또 실패)
                     → DLQ 또는 Destinations OnFailure

[ESM - SQS]
메시지 → Lambda 폴링 → Lambda 실행 → 에러 발생
                               ↓
         가시성 타임아웃 종료 후 메시지 큐 복귀
                               ↓ (maxReceiveCount 초과)
                     → SQS DLQ (함수 DLQ 아님!)

DLQ vs Lambda Destinations: 정확한 선택 기준

상황권장
비동기 호출 실패 이벤트 보존Destinations OnFailure
비동기 호출 성공 이벤트도 감사 필요Destinations OnSuccess
SQS-Lambda ESM에서 최종 실패 처리SQS 큐 자체에 DLQ 설정
기존 레거시 코드가 DLQ를 이미 사용 중DLQ 유지 (마이그레이션 여유 있을 때 Destinations로)

Destinations가 DLQ보다 나은 이유:

  1. 성공 이벤트 처리 가능: 함수가 성공했을 때도 이벤트를 보낼 수 있다 (감사, 다음 단계 트리거)
  2. 더 다양한 대상: SQS, SNS뿐 아니라 EventBridge와 Lambda도 대상
  3. 풍부한 컨텍스트: 원본 이벤트 + 요청 컨텍스트 + 응답/에러 정보를 모두 포함한 JSON
  4. 표준 비동기 패턴: 이벤트 기반 아키텍처의 팬아웃과 더 잘 맞음
# Destinations OnFailure가 전달하는 이벤트 구조 (예시)
{
  "version": "1.0",
  "timestamp": "2026-05-31T09:30:00Z",
  "requestContext": {
    "requestId": "abc-123",
    "functionArn": "arn:aws:lambda:...:function:payment-api:prod",
    "condition": "RetriesExhausted",
    "approximateInvokeCount": 3  # 원본 1회 + 재시도 2회
  },
  "requestPayload": {
    "customerId": "C001",
    "amount": 9999
  },
  "responseContext": {
    "statusCode": 200,  # Lambda API 수준, 함수 에러가 있어도 200
    "executedVersion": "$LATEST",
    "functionError": "Unhandled"
  },
  "responsePayload": {
    "errorMessage": "Payment gateway timeout",
    "errorType": "TimeoutError"
  }
}

SQS DLQ vs Lambda DLQ: 같은 이름 다른 개념

시험에서 헷갈리기 쉬운 부분이다.

SQS DLQ(Dead Letter Queue):

  • SQS 큐의 속성이다
  • SQS 메시지가 maxReceiveCount 횟수를 초과해 소비됐을 때 SQS DLQ로 이동
  • SQS-Lambda ESM에서 Lambda가 반복 실패하면 → 메시지가 가시성 타임아웃마다 재시도 → maxReceiveCount 초과 → SQS DLQ

Lambda DLQ:

  • Lambda 함수의 설정이다
  • 비동기 호출이 최종 실패(원본 + 2회 재시도 모두 실패)할 때 이벤트를 전송
  • SQS-Lambda ESM에서는 Lambda DLQ가 적용되지 않는다. ESM 실패는 SQS DLQ가 담당
시나리오: SQS → Lambda ESM에서 Lambda가 계속 실패

Lambda DLQ 설정 여부와 무관!
  → 메시지가 가시성 타임아웃 후 SQS 큐로 복귀
  → maxReceiveCount(기본 3) 초과 후
  → SQS 큐에 설정된 DLQ로 이동

Lambda DLQ는 S3/SNS 등 비동기 호출에서 동작

Reserved + Provisioned 동시성을 함께 쓰는 실전 패턴

시나리오: 금융 API (결제 처리)
- 평소 트래픽: 50 동시성
- 피크 트래픽: 200 동시성
- 콜드 스타트 허용 불가 (응답 시간 SLA: p99 < 500ms)

설정:
Reserved Concurrency = 300  (계정 한도에서 300 전용 할당)
Provisioned Concurrency = 50  (항상 50개 웜 상태 대기)

동작:
- 평소: 50개 Provisioned 인스턴스가 처리, 콜드 스타트 없음
- 트래픽 급증 시: 50개를 초과하는 요청은 새 인스턴스 생성(콜드 스타트 발생 가능)
- 트래픽이 300 초과 시: ThrottlingException (Reserved가 상한선 역할)
- 다른 함수들이 이 300을 쓸 수 없음 (전용 할당)

Auto Scaling 설정:
PC를 80% 사용 시 자동으로 PC 추가
# Application Auto Scaling으로 Provisioned Concurrency 자동 조절
aws application-autoscaling register-scalable-target \
  --service-namespace lambda \
  --resource-id function:payment-api:prod \
  --scalable-dimension lambda:function:ProvisionedConcurrency \
  --min-capacity 10 \
  --max-capacity 200
 
aws application-autoscaling put-scaling-policy \
  --service-namespace lambda \
  --resource-id function:payment-api:prod \
  --scalable-dimension lambda:function:ProvisionedConcurrency \
  --policy-name pc-tracking-policy \
  --policy-type TargetTrackingScaling \
  --target-tracking-scaling-policy-configuration '{
    "TargetValue": 0.7,
    "PredefinedMetricSpecification": {
      "PredefinedMetricType": "LambdaProvisionedConcurrencyUtilization"
    }
  }'

비동기 에러 처리 패턴: 비즈니스 에러 vs 시스템 에러

Lambda에서 에러를 모두 같은 방식으로 처리하면 안 된다.

시스템 에러(재시도 가능): DB 연결 실패, HTTP 타임아웃, 일시적 503. 예외를 던져서 Lambda 재시도 메커니즘을 활용한다.

비즈니스 에러(재시도 불필요): 유효하지 않은 데이터, 권한 없음, 도메인 규칙 위반. 재시도해도 결과가 같으므로 예외를 던지지 말고 성공 응답을 반환하거나 에러 이벤트를 다른 큐로 라우팅한다.

import logging
import json
from botocore.exceptions import ClientError
 
logger = logging.getLogger()
logger.setLevel(logging.INFO)
 
class BusinessError(Exception):
    """도메인 규칙 위반 — 재시도해도 의미 없음"""
    pass
 
class RetryableError(Exception):
    """일시적 시스템 오류 — 재시도하면 성공할 수 있음"""
    pass
 
def lambda_handler(event, context):
    try:
        order_id = event.get('orderId')
        if not order_id:
            # 비즈니스 에러 — 재시도해도 소용 없음
            # 예외 대신 에러 응답을 반환하거나 SQS에 직접 보내기
            logger.error(f"유효하지 않은 주문 ID: {event}")
            return {'status': 'BUSINESS_ERROR', 'reason': 'orderId missing'}
        
        result = process_order(order_id)
        return {'status': 'SUCCESS', 'orderId': order_id}
    
    except RetryableError as e:
        # 재시도 필요 — 예외를 다시 던져서 Lambda 재시도 유도
        logger.warning(f"일시적 오류, 재시도 예정: {str(e)}")
        raise  # Lambda 비동기 재시도 메커니즘이 동작
    
    except Exception as e:
        # 예상치 못한 에러 — 재시도하면서 상황 파악
        logger.error(f"예상치 못한 에러: {str(e)}", exc_info=True)
        raise

스로틀링 대응 패턴

동기 호출에서 429를 받는 클라이언트:

import boto3
import random
import time
from botocore.exceptions import ClientError
 
lambda_client = boto3.client('lambda')
 
def invoke_with_retry(function_name, payload, max_retries=3):
    for attempt in range(max_retries):
        try:
            return lambda_client.invoke(
                FunctionName=function_name,
                InvocationType='RequestResponse',
                Payload=payload
            )
        except ClientError as e:
            if e.response['Error']['Code'] == 'TooManyRequestsException':
                wait_time = (2 ** attempt) + (random.random() * 0.5)  # jitter
                logger.warning(f"스로틀링. {wait_time:.2f}초 후 재시도 (시도 {attempt+1}/{max_retries})")
                time.sleep(wait_time)
            else:
                raise
    raise Exception("최대 재시도 횟수 초과")

SQS를 완충재로 사용: 급격한 트래픽 급증이 예상된다면, 호출자가 직접 Lambda를 호출하는 대신 SQS에 넣고, Lambda ESM이 처리 속도를 조절하도록 한다. SQS가 완충재(buffer) 역할을 한다.

[트래픽 급증] → [직접 Lambda 호출] → 429 스로틀링
                                         ↓
[트래픽 급증] → [SQS 큐] → [Lambda ESM] → 처리 속도 자동 조절

정리

Lambda 동시성 제어는 네 개의 다른 메커니즘이 중첩된 시스템이다. Reserved는 함수별 격리와 상한선을 제공하고, Provisioned는 콜드 스타트를 제거하며, 버스트 한도는 스케일아웃 속도를 제한하고, 계정 한도는 전체 상한을 정한다. 에러 처리는 호출 방식마다 완전히 다른 계층에서 일어나며, "어디서 재시도하고 어디로 실패 이벤트가 가는지"를 호출 방식별로 정확히 알아야 한다.

다음 글에서는 이 Week 3 전체를 복습하면서 Lambda의 모든 개념을 시나리오 기반 문제로 점검한다.

📝 연습 문제

선택지를 클릭하면 정답·해설이 펼쳐집니다.

문제 1

Lambda 함수의 초당 요청이 2,000개이고 평균 실행 시간이 300ms일 때 필요한 동시성은?

문제 2

Lambda 함수의 Reserved Concurrency를 0으로 설정했을 때의 결과는?

문제 3

Kinesis Data Streams ESM에서 하나의 레코드가 계속 실패할 때 발생하는 문제와 가장 효과적인 해결책 조합은?

문제 4

SQS DLQ와 Lambda DLQ의 차이점으로 옳은 것은?

문제 5

다음 중 Lambda Destinations의 장점이 아닌 것은?

문제 6

현재 Lambda 함수의 기본 동시성 확장 속도로 옳은 것은?

이전Lambda 버전·별칭·레이어: Immutable 배포와 의존성 분리의 원리Week 3 · Day 3다음 Week 3 복습: Lambda 종합 시나리오로 실전 감각 다지기Week 3 · Day 5

참고 공식 자료

  • DVA-C02 공식 시험 안내(새 탭에서 열림)
  • AWS Lambda 공식 문서(새 탭에서 열림)
  • Amazon SQS 공식 문서(새 탭에서 열림)
  • Amazon Kinesis 공식 문서(새 탭에서 열림)
  • Amazon SNS 공식 문서(새 탭에서 열림)
  • Amazon EventBridge 공식 문서(새 탭에서 열림)

이 페이지

  • 동시성의 정의와 계산
  • 동시성 네 계층의 완전한 그림
  • 버스트 동시성 한도: 스케일아웃의 속도 제한
  • CloudWatch 메트릭으로 동시성 문제 진단
  • 에러 처리 계층: 호출 방식별 완전 비교
  • DLQ vs Lambda Destinations: 정확한 선택 기준
  • SQS DLQ vs Lambda DLQ: 같은 이름 다른 개념
  • Reserved + Provisioned 동시성을 함께 쓰는 실전 패턴
  • 비동기 에러 처리 패턴: 비즈니스 에러 vs 시스템 에러
  • 스로틀링 대응 패턴
  • 정리
  • 연습 문제