Lambda 재귀 루프 감지를 사용하여 무한 루프 방지 - AWS Lambda

Lambda 재귀 루프 감지를 사용하여 무한 루프 방지

함수를 간접적으로 호출하는 동일한 서비스 또는 리소스로 출력하도록 Lambda 함수를 구성하면 무한 재귀 루프를 생성할 수 있습니다. 예를 들어 Lambda 함수는 Amazon Simple Queue Service(Amazon SQS) 대기열에 메시지를 작성한 다음 동일한 함수를 간접적으로 호출할 수 있습니다. 이 간접 호출로 인해 함수는 대기열에 다른 메시지를 작성하고 다시 함수를 호출합니다.

의도하지 않은 재귀 루프로 인해 예상치 못한 요금이 AWS 계정에 청구될 수 있습니다. 루프로 인해 Lambda가 규모를 조정하고 계정의 사용 가능한 모든 동시성을 사용할 수도 있습니다. 의도하지 않은 루프의 영향을 줄이기 위해 Lambda는 특정 유형의 재귀 루프가 발생한 직후 이를 감지할 수 있습니다. 기본적으로 Lambda가 재귀 루프를 감지하면 함수 간접 호출을 중지하고 알려줍니다. 의도적으로 재귀 패턴 사용을 설계하는 경우 함수의 기본 구성을 변경하여 재귀 패턴 사용을 허용할 수 있습니다. 자세한 정보는 Lambda 함수가 재귀 루프에서 실행되도록 허용을 참조하세요.

재귀 루프 감지에 대한 이해

Lambda의 재귀 루프 감지는 이벤트 추적을 통해 작동합니다. Lambda는 특정 이벤트가 발생할 때 함수 코드를 실행하는 이벤트 기반 컴퓨팅 서비스입니다. 예를 들어 항목이 Amazon SQS 대기열 또는 Amazon Simple Notification Service(SNS) 주제에 추가되는 경우를 들 수 있습니다. Lambda는 이벤트를 시스템 상태 변경에 대한 정보가 포함된 JSON 객체로 함수에 전달합니다. 이벤트로 인해 함수가 실행되는 경우를 간접 호출이라고 합니다.

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

참고

이 기능을 작동하기 위해 X-Ray 활성 추적을 활성화할 필요는 없습니다. 재귀 루프 감지는 기본적으로 모든 AWS 고객에 대해 켜져 있습니다. 이 기능은 무료로 사용할 수 있습니다.

요청 체인은 동일한 트리거 이벤트로 인해 발생하는 일련의 Lambda 간접 호출입니다. 예를 들어 Amazon SQS 대기열이 Lambda 함수를 간접적으로 호출한다고 가정해 보겠습니다. 그러면 Lambda 함수가 처리된 이벤트를 동일한 Amazon SQS 대기열로 다시 전송하여 함수를 다시 간접적으로 호출합니다. 이 예제에서 함수의 각 간접 호출은 동일한 요청 체인에 속합니다.

함수가 동일한 요청 체인에서 약 16번 호출되는 경우 Lambda는 해당 요청 체인에서 다음 함수의 간접 호출을 자동으로 중지하고 사용자에게 알립니다. 함수가 여러 트리거로 구성된 경우 다른 트리거에서의 간접 호출은 영향을 받지 않습니다.

참고

소스 대기열의 리드라이브 정책에 대한 maxReceiveCount 설정이 16보다 높은 경우에도 Lambda 재귀 보호는 재귀 루프가 감지되고 종료된 후 Amazon SQS가 메시지를 재시도하는 것을 막지 않습니다. Lambda는 재귀 루프를 감지하고 후속 간접 호출을 삭제하면 RecursiveInvocationException을(를) 이벤트 소스 매핑으로 반환합니다. 이로 인해 메시지의 receiveCount 값이 증가합니다. Amazon SQS가 maxReceiveCount를 초과했다고 판단하여 구성된 DLQ(Dead Letter Queue)로 메시지를 보낼 때까지 Lambda는 메시지를 계속 재시도하고 함수 호출을 계속 차단합니다.

함수에 대해 실패 시 대상 또는 DLQ(Dead Letter Queue)가 구성되어 있는 경우에도, Lambda는 중지된 간접 호출에서 이벤트를 대상 또는 DLQ로 전송합니다. 함수에 대한 대상 또는 DLQ(Dead Letter Queue)를 구성하는 경우 함수가 이벤트 트리거 또는 이벤트 소스 매핑으로도 사용하는 Amazon SNS 주제 또는 Amazon SQS 대기열을 사용하지 마십시오. 함수를 간접적으로 호출하는 동일한 리소스에 이벤트를 보내면 또 다른 재귀 루프를 만들 수 있습니다.

지원되는 AWS 서비스 및 SDK

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

지원되는 AWS 서비스

Lambda는 현재 함수, Amazon SQS, Amazon SNS 간의 재귀 루프를 감지합니다. Lambda는 또한 동기식 또는 비동기식으로 서로를 간접적으로 호출할 수 있는 Lambda 함수로만 구성된 루프를 감지합니다. 다음 다이어그램은 Lambda가 감지할 수 있는 루프의 몇 가지 예를 보여줍니다.

Lambda 함수, Amazon SNS, Amazon SQS 대기열 간의 재귀 루프 다이어그램.

Amazon DynamoDB 또는 Amazon Simple Storage Service(Amazon S3)와 같은 다른 AWS 서비스가 루프의 일부인 경우 현재 Lambda는 이를 감지하고 중지할 수 없습니다.

Lambda는 현재 Amazon SQS 및 Amazon SNS와 관련된 재귀 루프만 감지하기 때문에 다른 AWS 서비스와 관련된 루프로 인해 Lambda 함수가 의도치 않게 사용될 수 있습니다.

AWS 계정에 예기치 않은 요금이 청구되지 않도록 하려면 비정상적인 사용 패턴을 알리도록 Amazon CloudWatch 경보를 구성하는 것이 좋습니다. 예를 들어 Lambda 함수 동시성 또는 간접 호출의 급증에 대해 알리도록 CloudWatch를 구성할 수 있습니다. 계정 지출이 지정한 임계값을 초과할 때 알림을 받도록 결제 경보를 구성할 수도 있습니다. 또는 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

SDK V2 (최신 버전 사용)

Python 및 Node.js와 같은 일부 Lambda 런타임에는 AWS SDK 버전이 포함되어 있습니다. 함수의 런타임에 포함된 SDK 버전이 필요한 최소 버전보다 낮은 경우 지원되는 SDK 버전을 함수의 배포 패키지에 추가할 수 있습니다. Lambda 계층을 사용하여 지원되는 SDK 버전을 함수에 추가할 수도 있습니다. 각 Lambda 런타임에 포함된 SDK 목록은 Lambda 런타임 단원을 참조하세요.

재귀 루프 알림

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

AWS Health Dashboard 알림

Lambda가 재귀 간접 호출을 중지하면 AWS Health Dashboard는 계정 상태 페이지의 미결 및 최근 문제 아래에 알림을 표시합니다. Lambda가 재귀 간접 호출을 중지한 후 이 알림이 표시되기까지 최대 3시간이 걸릴 수 있습니다. AWS Health Dashboard에서 계정 이벤트 보기에 대한 자세한 내용은 AWS Health 사용 설명서에서 Getting started with your AWS Health Dashboard – Your account health를 참조하세요.

이메일 알림

Lambda가 함수의 재귀 간접 호출을 처음 중지하면 이메일 알림이 전송됩니다. Lambda는 AWS 계정의 각 함수와 관련된 이메일을 24시간마다 최대 한 번 보냅니다. Lambda가 이메일 알림을 보낸 후 Lambda가 함수의 추가 재귀 간접 호출을 중지하더라도 그다음 24시간 동안 해당 함수에 대한 이메일이 더 이상 전송되지 않습니다. Lambda가 재귀 간접 호출을 중지한 후 이 이메일 알림을 받을 때까지 최대 3시간이 걸릴 수 있습니다.

Lambda는 AWS 계정의 기본 계정 연락처 및 대체 작업 연락처에 재귀 루프 이메일 알림을 보냅니다. 계정의 이메일 주소 보기 또는 업데이트에 대한 자세한 내용은 AWS 참조 가이드에서 Updating contact information을 참조하세요.

Amazon CloudWatch 지표

CloudWatch 지표 RecursiveInvocationsDropped는 단일 요청 체인에서 함수가 16회 넘게 간접적으로 호출되어 Lambda가 중지한 함수 간접 호출 수를 기록합니다. Lambda는 재귀 간접 호출을 중지하는 즉시 이 지표를 내보냅니다. 이 지표를 보려면 CloudWatch 콘솔에서 지표 보기 지침을 따르고 지표 RecursiveInvocationsDropped를 선택하세요.

재귀 루프 감지 알림에 응답

동일한 트리거 이벤트에 의해 함수가 16회 넘게 간접적으로 호출되면 Lambda는 해당 이벤트에 대한 다음 함수 간접 호출을 중지하여 재귀 루프를 중지합니다. Lambda가 중지한 재귀 루프의 재발을 방지하려면 다음을 수행합니다.

  • 함수의 사용 가능한 동시성을 0으로 줄이면 향후 모든 간접 호출이 제한됩니다.

  • 함수를 간접적으로 호출하는 트리거 또는 이벤트 소스 매핑을 제거하거나 비활성화합니다.

  • 함수를 간접적으로 호출하는 AWS 리소스에 이벤트를 다시 기록하는 코드 결함을 식별하고 수정합니다. 일반적인 결함은 변수를 사용하여 함수의 이벤트 소스와 대상을 정의할 때 발생합니다. 두 변수에 동일한 값을 사용하고 있지 않은지 확인하세요.

또한 Lambda 함수의 이벤트 소스가 Amazon SQS 대기열인 경우 소스 대기열에서 DLQ(Dead Letter Queue)를 구성하는 것이 좋습니다.

참고

Lambda 함수가 아닌 소스 대기열에서 배달 못한 편지 대기열을 구성해야 합니다. 함수에서 구성하는 배달 못한 편지 대기열은 이벤트 소스 대기열이 아닌 함수의 비동기식 호출 대기열에 사용됩니다.

이벤트 소스가 Amazon SNS 주제인 경우 함수에 대해 실패 시 대상을 추가하는 것이 좋습니다.

함수의 사용 가능한 동시성을 0으로 줄이려면(콘솔)
  1. Lambda 콘솔의 함수 페이지를 엽니다.

  2. 함수의 이름을 선택합니다.

  3. 제한을 선택합니다.

  4. 함수 제한 대화 상자에서 확인을 선택합니다.

함수의 트리거 또는 이벤트 소스 매핑을 제거하려면(콘솔)
  1. Lambda 콘솔의 함수 페이지를 엽니다.

  2. 함수의 이름을 선택합니다.

  3. 구성 탭을 선택한 다음 트리거를 선택합니다.

  4. 트리거에서 삭제하려는 트리거 또는 이벤트 소스 매핑을 선택한 다음 삭제를 선택합니다.

  5. 트리거 삭제 대화 상자에서 삭제를 선택합니다.

함수에 대한 이벤트 소스 매핑을 비활성화하려면(AWS CLI)
  1. 비활성화하려는 이벤트 소스 매핑의 UUID를 찾으려면 AWS Command Line Interface(AWS CLI) list-event-source-mappings 명령을 실행합니다.

    aws lambda list-event-source-mappings
  2. 이벤트 소스 매핑을 비활성화하려면 다음 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 및 AWS CloudFormation에서 함수의 재귀 루프 감지 설정을 구성할 수도 있습니다.

기본적으로 Lambda는 재귀 루프를 탐지하고 종료합니다. 의도적으로 재귀 루프 사용을 설계하는 경우 함수의 기본 구성을 변경하지 않는 것이 좋습니다.

재귀 루프를 허용하도록 함수를 구성할 때는 CloudWatch 지표 RecursiveInvocationsDropped가 생성되지 않는다는 점에 유의하세요.

Console
함수가 재귀 루프에서 실행되도록 허용하려면 다음을 수행하세요(콘솔).
  1. Lambda 콘솔의 함수 페이지를 엽니다.

  2. 함수의 이름을 선택하여 함수의 세부 정보 페이지를 엽니다.

  3. 구성 탭을 선택한 다음 동시성 및 재귀 감지를 선택합니다.

  4. 재귀 루프 감지 옆에서 편집을 선택합니다.

  5. 재귀 루프 허용을 선택합니다.

  6. Save(저장)를 선택합니다.

AWS CLI

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를 사용하여 함수 구성을 편집합니다.

Console
재귀 루프가 종료되도록 함수를 구성하려면 다음을 수행하세요(콘솔).
  1. Lambda 콘솔의 함수 페이지를 엽니다.

  2. 함수의 이름을 선택하여 함수의 세부 정보 페이지를 엽니다.

  3. 구성 탭을 선택한 다음 동시성 및 재귀 감지를 선택합니다.

  4. 재귀 루프 감지 옆에서 편집을 선택합니다.

  5. 재귀 루프 종료를 선택합니다.

  6. Save(저장)를 선택합니다.

AWS CLI

PutFunctionRecursionConfig API를 사용하여 Lambda가 재귀 루프를 감지할 때 이를 종료하도록 함수를 구성할 수 있습니다. 재귀 루프 파라미터에 대해 Terminate를 지정합니다. 예를 들어, put-function-recursion-config AWS CLI 명령으로 이 API를 직접적으로 호출할 수 있습니다.

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

Lambda 재귀 루프 감지를 위해 지원되는 리전

Lambda 재귀 루프 감지는 다음 AWS 리전에서 지원됩니다.

  • 미국 동부(버지니아 북부)

  • 미국 동부(오하이오)

  • 미국 서부(캘리포니아 북부)

  • 미국 서부(오레곤)

  • 아프리카(케이프타운)

  • 아시아 태평양(홍콩)

  • 아시아 태평양(뭄바이)

  • 아시아 태평양(오사카)

  • 아시아 태평양(서울)

  • 아시아 태평양(싱가포르)

  • 아시아 태평양(시드니)

  • 아시아 태평양(도쿄)

  • 캐나다(중부)

  • 유럽(프랑크푸르트)

  • 유럽(아일랜드)

  • 유럽(런던)

  • 유럽(밀라노)

  • 유럽(파리)

  • 유럽(스톡홀름)

  • 중동(바레인)

  • 남아메리카(상파울루)