Lambda 재귀 루프 감지로 무한 루프 방지

Lambda 재귀 루프 감지로 무한 루프 방지

Lambda 함수가 함수를 호출하는 것과 같은 서비스나 리소스로 출력하도록 구성하면 무한 재귀 루프가 생길 수 있습니다. 예를 들어 Lambda 함수가 Amazon Simple Queue Service(SQS) 큐에 메시지를 쓰면, 그 큐가 같은 함수를 호출합니다. 이 호출로 함수가 큐에 또 메시지를 쓰고, 그게 다시 함수를 호출하는 식입니다.

출처: AWS Lambda 개발자 안내서

본문

의도치 않은 재귀 루프는 AWS 계정에 예상 밖의 비용이 청구되고, Lambda가 계정의 사용 가능한 모든 동시성을 사용하도록 확장될 수도 있습니다. 의도치 않은 루프의 영향을 줄이기 위해 Lambda는 특정 유형의 재귀 루프를 발생 직후 감지합니다.

기본적으로 Lambda는 재귀 루프를 감지하면 함수 호출을 중지하고 알려줍니다. 설계상 의도적으로 재귀 패턴을 사용한다면 함수의 기본 구성을 변경해 재귀적으로 호출되도록 할 수 있습니다. 자세한 내용은 'Lambda 함수가 재귀 루프에서 실행되도록 허용'을 참고하세요.

이 페이지의 내용:

  • 재귀 루프 감지 이해
  • 지원되는 AWS 서비스와 SDK
  • 재귀 루프 알림
  • 재귀 루프 감지 알림에 대응
  • Lambda 함수가 재귀 루프에서 실행되도록 허용
  • Lambda 재귀 루프 감지 지원 리전

재귀 루프 감지 이해

Lambda의 재귀 루프 감지는 이벤트를 추적하는 방식으로 작동합니다. Lambda는 특정 이벤트가 발생하면 함수 코드를 실행하는 이벤트 기반 컴퓨팅 서비스입니다. 예를 들어 Amazon SQS 큐나 Amazon Simple Notification Service(Amazon SNS) 토픽에 항목이 추가될 때 등입니다. Lambda는 시스템 상태 변화에 대한 정보를 담은 JSON 객체로 이벤트를 함수에 전달합니다. 이벤트가 함수를 실행하게 할 때 이를 **invocation(호출)**이라고 합니다.

재귀 루프를 감지하기 위해 Lambda는 AWS X-Ray 추적 헤더를 사용합니다. 재귀 루프 감지를 지원하는 AWS 서비스가 이벤트를 Lambda에 보내면 그 이벤트는 자동으로 메타데이터로 주석 처리됩니다. Lambda 함수가 지원되는 버전의 AWS SDK를 사용해 이러한 이벤트 중 하나를 다른 지원 AWS 서비스에 쓰면 이 메타데이터를 갱신합니다. 갱신된 메타데이터에는 이벤트가 함수를 호출한 횟수가 포함됩니다.

이 기능이 작동하기 위해 X-Ray 활성 추적을 켤 필요는 없습니다. 재귀 루프 감지는 모든 AWS 고객에게 기본적으로 켜져 있습니다. 이 기능 사용에는 비용이 들지 않습니다.

**요청 체인(chain of requests)**은 같은 트리거 이벤트로 인한 일련의 Lambda 호출입니다. 예를 들어 Amazon SQS 큐가 Lambda 함수를 호출한다고 가정해보세요. Lambda 함수는 처리된 이벤트를 같은 Amazon SQS 큐로 다시 보내고, 그 큐가 함수를 다시 호출합니다. 이 예제에서 함수의 각 호출은 같은 요청 체인에 속합니다.

함수가 같은 요청 체인에서 약 16회 호출되면 Lambda는 해당 요청 체인의 다음 함수 호출을 자동으로 중지하고 알려줍니다. 함수에 여러 트리거가 구성되어 있다면 다른 트리거의 호출에는 영향을 주지 않습니다.

소스 큐의 redrive 정책에서 maxReceiveCount 설정이 16보다 높아도, Lambda 재귀 보호는 재귀 루프가 감지·종료된 뒤 Amazon SQS가 메시지를 재시도하는 것을 막지 않습니다. Lambda가 재귀 루프를 감지하고 후속 호출을 버리면 이벤트 소스 매핑에 RecursiveInvocationException을 반환합니다. 이는 메시지의 receiveCount 값을 증가시킵니다. Lambda는 Amazon SQS가 maxReceiveCount가 초과됐다고 판단해 메시지를 구성된 데드레터 큐로 보낼 때까지 메시지를 계속 재시도하고 함수 호출을 계속 차단합니다.

함수에 on-failure 대상이나 데드레터 큐가 구성되어 있다면 Lambda는 중지된 호출의 이벤트도 대상이나 데드레터 큐로 보냅니다. 함수의 대상이나 데드레터 큐를 구성할 때는 함수도 사용하는 이벤트 트리거나 이벤트 소스 매핑을 사용하지 않도록 주의하세요. 함수를 호출하는 것과 같은 리소스로 이벤트를 보내면 또 다른 재귀 루프가 생길 수 있고 이 루프도 종료됩니다. 재귀 루프 감지를 해제(opt out)했다면 이 루프는 종료되지 않습니다.

지원되는 AWS 서비스와 SDK

Lambda는 특정 지원 AWS 서비스를 포함하는 재귀 루프만 감지할 수 있습니다. 재귀 루프가 감지되려면 함수도 지원되는 AWS SDK 중 하나를 사용해야 합니다.

지원되는 AWS 서비스

Lambda는 현재 함수, Amazon SQS, Amazon S3, Amazon SNS, Amazon EventBridge 사용자 지정 이벤트 버스 사이의 재귀 루프를 감지합니다. Lambda는 서로 동기적·비동기적으로 호출할 수 있는 Lambda 함수만으로 구성된 루프도 감지합니다. Lambda가 감지할 수 있는 루프의 예시는 위 다이어그램에서 확인하세요.

Amazon DynamoDB 같은 다른 AWS 서비스가 루프의 일부를 이루면 Lambda는 현재 이를 감지·중지할 수 없습니다.

Lambda는 현재 Amazon SQS, Amazon S3, Amazon SNS, Amazon EventBridge 사용자 지정 이벤트 버스를 포함하는 재귀 루프만 감지하므로, 다른 AWS 서비스를 포함하는 루프는 Lambda 함수의 의도치 않은 사용으로 이어질 수 있습니다.

AWS 계정에 예상 밖의 비용이 청구되는 것을 막기 위해 Amazon CloudWatch 경보를 구성해 특이한 사용 패턴을 알려주는 것을 권장합니다. 예를 들어 CloudWatch가 Lambda 함수 동시성이나 호출 수 급증을 알리도록 구성할 수 있습니다. 또한 계정 지출이 지정한 임계값을 초과할 때 알려주는 결제 경보(billing alarm)를 구성할 수도 있습니다. 또는 AWS Cost Anomaly Detection을 사용해 특이한 결제 패턴을 알릴 수 있습니다.

지원되는 AWS SDK

Lambda가 재귀 루프를 감지하려면 함수가 다음 SDK 버전 중 하나 이상을 사용해야 합니다.

런타임 최소 요구 AWS SDK 버전
Node.js 2.1147.0 (SDK 버전 2) / 3.105.0 (SDK 버전 3)
Python 1.24.46 (boto3) / 1.27.46 (botocore)
Java 8 및 Java 11 2.17.135
Java 17 2.20.81
Java 21 2.21.24
.NET 3.7.293.0
Ruby 3.134.0
PHP 3.232.0
Go V2 SDK 1.57.0

Python, Node.js 같은 일부 Lambda 런타임은 AWS SDK 버전을 포함합니다. 함수 런타임에 포함된 SDK 버전이 최소 요구 버전보다 낮다면 지원되는 SDK 버전을 함수 배포 패키지에 추가할 수 있습니다. Lambda 레이어를 사용해 지원되는 SDK 버전을 함수에 추가할 수도 있습니다. 각 Lambda 런타임에 포함된 SDK 목록은 'Lambda 런타임'을 참고하세요.

재귀 루프 알림

Lambda가 재귀 루프를 중지하면 Health Dashboard와 이메일로 알림을 받습니다. 또한 CloudWatch 지표로 Lambda가 중지한 재귀 호출 수를 모니터링할 수 있습니다.

Health Dashboard 알림

Lambda가 재귀 호출을 중지하면 Health Dashboard의 Your account health 페이지에 Open and recent issues 아래 알림이 표시됩니다. Lambda가 재귀 호출을 중지한 뒤 이 알림이 표시되기까지 최대 3.5시간이 걸릴 수 있습니다. Health Dashboard에서 계정 이벤트를 보는 방법에 대한 자세한 내용은 AWS Health User Guide의 'Getting started with your AWS Health Dashboard – Your account health'를 참고하세요.

이메일 알림

Lambda가 함수의 재귀 호출을 처음 중지하면 이메일 알림을 보냅니다. Lambda는 AWS 계정의 각 함수에 대해 24시간마다 최대 한 통의 이메일을 보냅니다. Lambda가 이메일 알림을 보낸 뒤에는, 함수의 추가 재귀 호출을 중지하더라도 24시간 동안 그 함수에 대한 이메일을 더 받지 않습니다. Lambda가 재귀 호출을 중지한 뒤 이 이메일 알림이 도착하기까지 최대 3.5시간이 걸릴 수 있습니다.

Lambda는 재귀 루프 이메일 알림을 AWS 계정의 기본 계정 연락처와 대체 운영 연락처(alternate operations contact)로 보냅니다. 계정의 이메일 주소를 보거나 갱신하는 방법은 AWS General Reference의 'Updating contact information'을 참고하세요.

Amazon CloudWatch 지표

CloudWatch 지표 RecursiveInvocationsDropped는 함수가 단일 요청 체인에서 약 16회 이상 호출되어 Lambda가 중지한 함수 호출 수를 기록합니다. Lambda는 재귀 호출을 중지하자마자 이 지표를 내보냅니다. 이 지표를 보려면 CloudWatch 콘솔의 지표 보기 지침을 따르고 RecursiveInvocationsDropped 지표를 선택하세요.

재귀 루프 감지 알림에 대응

같은 트리거 이벤트로 함수가 약 16회 이상 호출되면 Lambda는 재귀 루프를 끊기 위해 그 이벤트의 다음 함수 호출을 중지합니다. Lambda가 끊은 재귀 루프가 재발하지 않게 하려면 다음을 수행하세요.

  • 함수의 사용 가능한 동시성을 0으로 줄여 향후 모든 호출을 제한(throttle)합니다.
  • 함수를 호출하는 트리거나 이벤트 소스 매핑을 제거하거나 비활성화합니다.
  • 함수를 호출하는 AWS 리소스로 이벤트를 다시 쓰는 코드 결함을 찾아 수정합니다. 흔한 결함 원인은 변수로 함수의 이벤트 소스와 대상을 정의할 때 발생합니다. 두 변수에 같은 값을 사용하지 않는지 확인하세요.

추가로, Lambda 함수의 이벤트 소스가 Amazon SQS 큐라면 소스 큐에 데드레터 큐를 구성하는 것을 고려하세요.

  • 데드레터 큐를 Lambda 함수가 아니라 소스 큐에 구성했는지 확인하세요. 함수에 구성하는 데드레터 큐는 함수의 비동기 호출 큐에 사용되며 이벤트 소스 큐에는 사용되지 않습니다.
  • 이벤트 소스가 Amazon SNS 토픽이라면 함수에 on-failure 대상을 추가하는 것을 고려하세요.

콘솔로 동시성 줄이기:

  1. Lambda 콘솔의 Functions 페이지를 엽니다.
  2. 함수 이름을 선택합니다.
  3. Throttle을 선택합니다.
  4. Throttle your function 대화 상자에서 Confirm을 선택합니다.

콘솔로 트리거 삭제:

  1. Lambda 콘솔의 Functions 페이지를 엽니다.
  2. 함수 이름을 선택합니다.
  3. Configuration 탭을 선택한 뒤 Triggers를 선택합니다.
  4. Triggers 아래에서 삭제할 트리거나 이벤트 소스 매핑을 선택한 뒤 Delete를 선택합니다.
  5. Delete triggers 대화 상자에서 Delete를 선택합니다.

비활성화할 이벤트 소스 매핑의 UUID를 찾으려면 AWS Command Line Interface(AWS CLI) list-event-source-mappings 명령을 실행하세요.

aws lambda list-event-source-mappings

이벤트 소스 매핑을 비활성화하려면 다음 AWS CLI update-event-source-mapping 명령을 실행하세요.

aws lambda update-event-source-mapping --function-name MyFunction \
--uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 --no-enabled

Lambda 함수가 재귀 루프에서 실행되도록 허용

설계가 의도적으로 재귀 루프를 사용한다면 Lambda 함수가 재귀적으로 호출되도록 구성할 수 있습니다. 설계에서 재귀 루프를 사용하는 것은 피할 것을 권장합니다. 구현 오류는 재귀 호출이 AWS 계정의 사용 가능한 모든 동시성을 사용하고 계정에 예상 밖의 비용이 청구되도록 만들 수 있습니다.

재귀 루프를 사용한다면 주의해서 다루세요. 구현 오류의 위험을 최소화하도록 모범 사례 가드레일을 구현하세요. 재귀 패턴 사용의 모범 사례에 대해 자세히 알아보려면 Serverless Land의 'Recursive patterns that cause run-away Lambda functions'를 참고하세요.

Lambda 콘솔, AWS Command Line Interface(AWS CLI), PutFunctionRecursionConfig API를 사용해 함수가 재귀 루프를 허용하도록 구성할 수 있습니다. AWS SAM과 CloudFormation에서도 함수의 재귀 루프 감지 설정을 구성할 수 있습니다.

기본적으로 Lambda는 재귀 루프를 감지·종료합니다. 설계가 의도적으로 재귀 루프를 사용하지 않는다면 함수의 기본 구성을 변경하지 않는 것을 권장합니다.

함수가 재귀 루프를 허용하도록 구성하면 CloudWatch 지표 RecursiveInvocationsDropped는 내보내지지 않습니다.

콘솔로 허용:

  1. Lambda 콘솔의 Functions 페이지를 엽니다.
  2. 함수 이름을 선택해 함수 상세 페이지를 엽니다.
  3. Configuration 탭을 선택한 뒤 Concurrency and recursion detection을 선택합니다.
  4. Recursive loop detection 옆의 Edit을 선택합니다.
  5. Allow recursive loops를 선택합니다.
  6. Save를 선택합니다.

PutFunctionRecursionConfig API로 함수가 재귀 루프에서 호출되도록 허용할 수 있습니다. 재귀 파라미터에 Allow를 지정하세요. 예를 들어 put-function-recursion-config AWS CLI 명령으로 이 API를 호출할 수 있습니다.

aws lambda put-function-recursion-config --function-name yourFunctionName --recursive-loop Allow

함수의 구성을 기본 설정으로 되돌려 Lambda가 재귀 루프를 감지하면 종료하도록 할 수 있습니다. Lambda 콘솔이나 AWS CLI로 함수 구성을 편집하세요.

콘솔로 종료 설정:

  1. Lambda 콘솔의 Functions 페이지를 엽니다.
  2. 함수 이름을 선택해 함수 상세 페이지를 엽니다.
  3. Configuration 탭을 선택한 뒤 Concurrency and recursion detection을 선택합니다.
  4. Recursive loop detection 옆의 Edit을 선택합니다.
  5. Terminate recursive loops를 선택합니다.
  6. Save를 선택합니다.

PutFunctionRecursionConfig API로 함수가 재귀 루프를 감지하면 종료하도록 구성할 수 있습니다. 재귀 파라미터에 Terminate를 지정하세요. 예를 들어 put-function-recursion-config AWS CLI 명령으로 이 API를 호출할 수 있습니다.

aws lambda put-function-recursion-config --function-name yourFunctionName --recursive-loop Terminate

Lambda 재귀 루프 감지 지원 리전

Lambda 재귀 루프 감지는 모든 상용 리전에서 지원됩니다.

더 알아보기 (Learn more)