

# 다른 AWS 서비스의 이벤트로 Lambda 간접 호출
<a name="lambda-services"></a>

일부 AWS 서비스에서는 *트리거*를 사용하여 바로 Lambda 함수를 간접 호출할 수 있습니다. 이러한 서비스는 Lambda로 이벤트를 푸시하고, 지정된 이벤트가 발생하면 함수가 즉시 간접적으로 간접 호출됩니다. 트리거는 개별 이벤트와 실시간 처리에 적합합니다. [Lambda 콘솔을 사용하여 트리거를 생성](#lambda-invocation-trigger)하면 콘솔은 해당 AWS 서비스와 상호 작용하여 서비스에 대한 이벤트 알림을 구성합니다. 트리거는 실제로 Lambda가 아니라 이벤트를 생성하는 서비스에 의해 저장되고 관리됩니다.

이벤트는 JSON 형식으로 구조화된 데이터입니다. JSON 구조는 JSON 구조를 생성하는 서비스와 이벤트 유형에 따라 다르지만, 모두 함수가 이벤트를 처리하는 데 필요한 데이터를 포함합니다.

함수에는 여러 개의 트리거가 있을 수 있습니다. 각 트리거는 함수를 독립적으로 호출하는 클라이언트 역할을 하며 Lambda가 함수에 전달하는 각 이벤트에는 단일 트리거의 데이터만 있습니다. Lambda는 이벤트 문서를 객체로 변환한 후 함수 핸들러에 전달합니다.

서비스에 따라 이벤트 기반 간접 호출은 [동기식](invocation-sync.md) 또는 [비동기식](invocation-async.md)으로 수행될 수 있습니다.
+ 동기식 간접 호출의 경우 이벤트를 생성하는 서비스는 함수로부터 응답을 기다립니다. 이 서비스는 함수가 응답에 반환되어야 하는 데이터를 정의합니다. 이 서비스는 오류에 대해 재시도할지 여부와 같은 오류 전략을 제어합니다.
+ 비동기식 간접 호출의 경우 Lambda는 이벤트를 함수에 전달하기 전에 대기열에 추가합니다. Lambda가 이벤트를 대기열에 넣으면 이벤트를 생성한 서비스에 즉시 성공 응답을 보냅니다. 함수가 이벤트를 처리한 후 Lambda는 이벤트 생성 서비스에 대한 응답을 반환하지 않습니다.

## 트리거 생성
<a name="lambda-invocation-trigger"></a>

트리거를 생성하는 가장 쉬운 방법은 Lambda 콘솔을 사용하는 것입니다. 콘솔을 사용하여 트리거를 생성하면 Lambda는 함수의 [리소스 기반 정책](access-control-resource-based.md)에 필요한 권한을 자동으로 추가합니다.

**Lambda 콘솔을 사용하여 트리거를 생성하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 트리거를 생성할 함수를 선택합니다.

1. **함수 개요** 창에서 **트리거 추가**를 선택합니다.

1. 함수를 간접 호출하려는 AWS 서비스를 선택합니다.

1. **트리거 구성** 창의 옵션을 입력하고 **추가**를 선택합니다. 함수를 간접적으로 간접 호출하기 위해 선택한 AWS 서비스에 따라 트리거 구성 옵션이 달라집니다.

## Lambda 함수를 간접적으로 간접 호출할 수 있는 서비스
<a name="listing-of-services-and-links-to-more-information"></a>

다음 표에는 Lambda 함수를 간접적으로 간접 호출할 수 있는 서비스가 나와 있습니다.


****  

| 서비스 | 호출 메서드 | 
| --- | --- | 
|  [Amazon Managed Streaming for Apache Kafka](with-msk.md)  |  [이벤트 소스 매핑](invocation-eventsourcemapping.md)  | 
|  [자체 관리형 Apache Kafka](with-kafka.md)  |  [이벤트 소스 매핑](invocation-eventsourcemapping.md)  | 
|  [Amazon API Gateway](services-apigateway.md)  |  이벤트 기반, 동기식 간접 호출  | 
|  [AWS CloudFormation](services-cloudformation.md)  |  이벤트 기반, 비동기식 간접 호출  | 
|  [Amazon CloudWatch Logs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#LambdaFunctionExample)  |  이벤트 기반, 비동기식 간접 호출  | 
|  [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/how-to-notify-lambda-cc.html)  |  이벤트 기반, 비동기식 간접 호출  | 
|  [AWS CodePipeline](https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html)  |  이벤트 기반, 비동기식 간접 호출  | 
|  [Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-events.html)  |  이벤트 기반, 동기식 간접 호출  | 
|  [AWS Config](governance-config.md)  |  이벤트 기반, 비동기식 간접 호출  | 
|  [Amazon Connect](https://docs.aws.amazon.com/connect/latest/adminguide/connect-lambda-functions.html)  |  이벤트 기반, 동기식 간접 호출  | 
|  [Amazon DocumentDB](with-documentdb.md)  |  [이벤트 소스 매핑](invocation-eventsourcemapping.md)  | 
|  [Amazon DynamoDB](with-ddb.md)  |  [이벤트 소스 매핑](invocation-eventsourcemapping.md)  | 
|  [Elastic Load Balancing (Application Load Balancer)](services-alb.md)  |  이벤트 기반, 동기식 간접 호출  | 
|  [Amazon EventBridge(CloudWatch Events)](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html)  |  이벤트 기반, 비동기식 간접 호출(이벤트 버스), 동기 또는 비동기식 간접 호출(파이프 및 스케줄)  | 
|  [AWS IoT](services-iot.md)  |  이벤트 기반, 비동기식 간접 호출  | 
|  [Amazon Kinesis](with-kinesis.md)  |  [이벤트 소스 매핑](invocation-eventsourcemapping.md)  | 
|  [Amazon Data Firehose](https://docs.aws.amazon.com/firehose/latest/dev/data-transformation.html)  |  이벤트 기반, 동기식 간접 호출  | 
|  [Amazon Lex](https://docs.aws.amazon.com/lexv2/latest/dg/lambda.html)  |  이벤트 기반, 동기식 간접 호출  | 
|  [Amazon MQ](with-mq.md)  |  [이벤트 소스 매핑](invocation-eventsourcemapping.md)  | 
|  [Amazon Simple Email Service](https://docs.aws.amazon.com/ses/latest/dg/receiving-email-action-lambda.html)  |  이벤트 기반, 비동기식 간접 호출  | 
|  [ Amazon Simple Notification Service](with-sns.md)  |  이벤트 기반, 비동기식 간접 호출  | 
|  [Amazon Simple Queue Service](with-sqs.md)  |  [이벤트 소스 매핑](invocation-eventsourcemapping.md)  | 
|  [Amazon Simple Storage Service(Amazon S3)](with-s3.md)  |  이벤트 기반, 비동기식 간접 호출  | 
|  [Amazon Simple Storage Service Batch](services-s3-batch.md)  |  이벤트 기반, 동기식 간접 호출  | 
|  [보안 관리자](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotate-secrets_lambda.html)  |  보안 암호 교체  | 
|  [AWS Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/connect-lambda.html)  |  이벤트 기반, 동기식 또는 비동기식 간접 호출  | 
|  [Amazon VPC Lattice](https://docs.aws.amazon.com/vpc-lattice/latest/ug/lambda-functions.html)  |  이벤트 기반, 동기식 간접 호출  | 

# Apache Kafka에서 Lambda 사용
<a name="with-kafka-esm"></a>

Lambda는 [이벤트 소스](invocation-eventsourcemapping.md)로 [Apache Kafka](https://kafka.apache.org/)를 지원합니다. Apache Kafka는 처리량이 많은 실시간 데이터 파이프라인과 스트리밍 애플리케이션을 처리하도록 설계된 오픈 소스 이벤트 스트리밍 플랫폼입니다. Apache Kafka에서 Lambda를 사용하는 방법은 크게 두 가지입니다.
+ [Amazon MSK에서 Lambda 사용](with-msk.md) - Amazon Managed Streaming for Apache Kafka(Amazon MSK)는 AWS의 완전관리형 서비스입니다. Amazon MSK는 프로비저닝, 패치 적용 및 스케일링을 포함하여 Kafka 인프라 관리를 자동화하는 데 도움이 됩니다.
+ [자체 관리형 Apache Kafka에서 Lambda 사용](with-kafka.md) – AWS 용어에서 자체 관리형 클러스터는 AWS가 아닌 다른 서비스에 호스팅된 Kafka 클러스터를 포함합니다. 예를 들어, [ Confluent Cloud](https://www.confluent.io/confluent-cloud/), [Redpanda](https://www.redpanda.com/) 등의 AWS가 아닌 클라우드 제공업체에서 호스팅되는 Kafka 클러스터에서 Lambda를 계속 사용할 수 있습니다.

Amazon MSK와 자체 관리형 Apache Kafka 중에서 결정할 때는 운영 요구 사항과 제어 요구 사항을 고려하세요. 최소한의 운영 오버헤드로 확장 가능하고 프로덕션에 바로 사용할 수 있는 Kafka 설정을 관리하는 데 AWS의 도움을 받으려면 Amazon MSK가 더 나은 선택입니다. 보안, 모니터링, 고가용성이 간소화되어 인프라 관리보다는 애플리케이션 개발에 집중할 수 있습니다. 반면, 자체 관리형 Apache Kafka는 온프레미스 클러스터를 포함하여 AWS 호스팅 환경이 아닌 곳에서 실행되는 사용 사례에 더 적합합니다.

**Topics**
+ [

# Amazon MSK에서 Lambda 사용
](with-msk.md)
+ [

# 자체 관리형 Apache Kafka에서 Lambda 사용
](with-kafka.md)
+ [

# Lambda에서의 Apache Kafka 이벤트 폴러 스케일링 모드
](kafka-scaling-modes.md)
+ [

# Lambda에서의 Apache Kafka 폴링 및 스트림 시작 위치
](kafka-starting-positions.md)
+ [

# Lambda에서 사용자 지정이 가능한 소비자 그룹 ID
](kafka-consumer-group-id.md)
+ [

# Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스에서 이벤트 필터링
](kafka-filtering.md)
+ [

# Lambda에서 Kafka 이벤트 소스와 함께 스키마 레지스트리 사용
](services-consume-kafka-events.md)
+ [

# Kafka 이벤트 소스의 저지연 처리
](with-kafka-low-latency.md)
+ [

# Kafka 이벤트 소스의 오류 처리 제어 구성
](kafka-retry-configurations.md)
+ [

# Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스에 대한 폐기된 배치 캡처
](kafka-on-failure.md)
+ [

# Kafka 주제를 실패 시 대상으로 사용
](kafka-on-failure-destination.md)
+ [

# Kafka 이벤트 소스 매핑 로깅
](esm-logging.md)
+ [

# Kafka 이벤트 소스 매핑 오류 문제 해결
](with-kafka-troubleshoot.md)

# Amazon MSK에서 Lambda 사용
<a name="with-msk"></a>

[Amazon Managed Streaming for Apache Kafka(Amazon MSK)](https://docs.aws.amazon.com/msk/latest/developerguide/what-is-msk.html)는 Apache Kafka를 사용하여 스트리밍 데이터를 처리하는 애플리케이션의 구축 및 실행을 위해 사용할 수 있는 완전관리형 서비스입니다. Amazon MSK는 Kafka 클러스터의 설정, 스케일링, 관리를 간소화합니다. 또한 Amazon MSK는 여러 Availability Zones에 맞게, 그리고 AWS Identity and Access Management(IAM)를 통한 보안을 위해 애플리케이션을 쉽게 구성할 수 있도록 도와줍니다.

이 장에서는 Amazon MSK 클러스터를 Lambda 함수의 이벤트 소스로 사용하는 방법을 설명합니다. Amazon MSK를 Lambda와 통합하는 일반적인 프로세스에는 다음 단계가 포함됩니다.

1. **[클러스터 및 네트워크 설정](with-msk-cluster-network.md)** - 먼저 [Amazon MSK 클러스터](https://docs.aws.amazon.com/msk/latest/developerguide/what-is-msk.html)를 설정합니다. 여기에는 Lambda가 클러스터에 액세스할 수 있도록 올바른 네트워킹 구성이 포함됩니다.

1. **[이벤트 소스 매핑 설정](with-msk-configure.md)** - 그런 다음 Lambda가 Amazon MSK 클러스터를 함수에 안전하게 연결하는 데 필요한 [이벤트 소스 매핑](invocation-eventsourcemapping.md) 리소스를 생성합니다.

1. **[함수 및 권한 설정](with-msk-permissions.md)** - 마지막으로 함수가 올바르게 설정되었고 [실행 역할](lambda-intro-execution-role.md)에 필요한 권한이 있는지 확인합니다.

**참고**  
이제 Lambda 또는 Amazon MSK 콘솔에서 직접 Amazon MSK 이벤트 소스 매핑을 생성 및 관리할 수 있습니다. 두 콘솔 모두 보다 간편한 구성 프로세스를 위해 필요한 Lambda 실행 역할 권한 설정을 자동으로 처리하는 옵션을 제공합니다.

Amazon MSK 클러스터와 Lambda 통합을 설정하는 방법의 예는 [자습서: Amazon MSK 이벤트 소스 매핑을 사용하여 간접적으로 Lambda 함수 간접 호출](services-msk-tutorial.md), AWS Compute Blog의 [Using Amazon MSK as an event source for AWS Lambda](https://aws.amazon.com/blogs/compute/using-amazon-msk-as-an-event-source-for-aws-lambda/) 및 Amazon MSK Labs의 [ Amazon MSK Lambda Integration](https://amazonmsk-labs.workshop.aws/en/msklambda.html)을 참조하세요.

**Topics**
+ [

## 예제 이벤트
](#msk-sample-event)
+ [

# Lambda를 위한 Amazon MSK 클러스터 및 Amazon VPC 네트워크 구성
](with-msk-cluster-network.md)
+ [

# Amazon MSK 이벤트 소스 매핑에 대한 Lambda 권한 구성
](with-msk-permissions.md)
+ [

# Lambda용 Amazon MSK 이벤트 소스 구성
](with-msk-configure.md)
+ [

# 자습서: Amazon MSK 이벤트 소스 매핑을 사용하여 간접적으로 Lambda 함수 간접 호출
](services-msk-tutorial.md)

## 예제 이벤트
<a name="msk-sample-event"></a>

Lambda는 함수를 간접 호출할 때 이벤트 파라미터의 메시지 배치를 보냅니다. 이벤트 페이로드에는 메시지 배열이 포함됩니다. 각 배열 항목에는 Amazon MSK 주제 및 파티션 식별자에 대한 세부 정보와 함께 타임스탬프 및 base64로 인코딩된 메시지가 포함됩니다.

```
{
   "eventSource":"aws:kafka",
   "eventSourceArn":"arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/751d2973-a626-431c-9d4e-d7975eb44dd7-2",
   "bootstrapServers":"b-2.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092,b-1.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092",
   "records":{
      "mytopic-0":[
         {
            "topic":"mytopic",
            "partition":0,
            "offset":15,
            "timestamp":1545084650987,
            "timestampType":"CREATE_TIME",
            "key":"abcDEFghiJKLmnoPQRstuVWXyz1234==",
            "value":"SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
            "headers":[
               {
                  "headerKey":[
                     104,
                     101,
                     97,
                     100,
                     101,
                     114,
                     86,
                     97,
                     108,
                     117,
                     101
                  ]
               }
            ]
         }
      ]
   }
}
```

# Lambda를 위한 Amazon MSK 클러스터 및 Amazon VPC 네트워크 구성
<a name="with-msk-cluster-network"></a>

AWS Lambda 함수를 Amazon MSK 클러스터에 연결하려면 클러스터와 해당 클러스터가 상주하는 [Amazon Virtual Private Cloud(VPC)](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html)를 올바르게 구성해야 합니다. 이 페이지에서는 클러스터와 VPC를 구성하는 방법을 설명합니다. 클러스터와 VPC가 이미 올바르게 구성된 경우 [Lambda용 Amazon MSK 이벤트 소스 구성](with-msk-configure.md) 섹션을 참조하여 이벤트 소스 매핑을 구성합니다.

**Topics**
+ [

## Lambda 및 MSK 통합을 위한 네트워크 구성 요구 사항 개요
](#msk-network-requirements)
+ [

## MSK 이벤트 소스에 대한 NAT 게이트웨이 구성
](#msk-nat-gateway)
+ [

## MSK 이벤트 소스에 대한 AWS PrivateLink 엔드포인트 구성
](#msk-vpc-privatelink)

## Lambda 및 MSK 통합을 위한 네트워크 구성 요구 사항 개요
<a name="msk-network-requirements"></a>

Lambda와 MSK 통합에 필요한 네트워킹 구성은 애플리케이션의 네트워크 아키텍처에 따라 다릅니다. 이 통합에는 Amazon MSK 클러스터, Lambda 함수, Lambda 이벤트 소스 매핑이라는 3개의 주요 리소스가 관련되어 있습니다. 이러한 각 리소스는 서로 다른 VPC에 있습니다.
+ Amazon MSK 클러스터는 일반적으로 사용자가 관리하는 VPC의 프라이빗 서브넷에 상주합니다.
+ Lambda 함수는 Lambda가 소유한 AWS 관리형 VPC에 상주합니다.
+ Lambda 이벤트 소스 매핑은 함수가 포함된 VPC와는 별도로 Lambda가 소유한 다른 AWS 관리형 VPC에 상주합니다.

[이벤트 소스 매핑](invocation-eventsourcemapping.md)은 MSK 클러스터와 Lambda 함수 사이의 중간 리소스입니다. 이벤트 소스 매핑에는 두 가지 기본 작업이 있습니다. 먼저 MSK 클러스터에서 새로운 메시지를 폴링합니다. 그런 다음 해당 메시지와 함께 Lambda 함수를 간접적으로 호출합니다. 이들 3개의 리소스는 서로 다른 VPC에 있으므로 폴링 및 간접 호출 작업 모두 VPC 간 네트워크 직접 호출이 필요합니다.

이벤트 소스 매핑에 대한 네트워크 구성 요구 사항은 다음 다이어그램과 같이 [프로비저닝된 모드](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)와 온디맨드 모드 중 무엇을 사용하는지에 따라 다릅니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/MSK-esm-network-overview.png)


Lambda 이벤트 소스 매핑이 MSK 클러스터에서 새로운 메시지를 폴링하는 방식은 두 모드 모두에서 동일합니다. 이벤트 소스 매핑과 MSK 클러스터 간의 연결을 설정하기 위해 Lambda는 프라이빗 서브넷에 [하이퍼플레인 ENI](configuration-vpc.md#configuration-vpc-enis)를 생성하거나 기존 ENI가 있는 경우 이를 재사용하여 보안 연결을 설정합니다. 다이어그램에 나와 있듯이 이 하이퍼플레인 ENI는 Lambda 함수가 아닌 MSK 클러스터의 서브넷과 보안 그룹 구성을 사용합니다.

클러스터에서 메시지를 폴링한 후 Lambda가 함수를 간접적으로 호출하는 방법은 각 모드에서 다릅니다.
+ 프로비저닝된 모드에서 Lambda는 이벤트 소스 매핑 VPC와 함수 VPC 간의 연결을 자동으로 처리합니다. 따라서 함수를 간접적으로 호출하기 위해 추가적인 네트워킹 구성 요소가 필요하지 않습니다.
+ 온디맨드 모드에서 Lambda 이벤트 소스 매핑은 고객 관리형 VPC를 통한 경로를 통해 함수를 간접적으로 호출합니다. 이러한 이유로 VPC의 퍼블릭 서브넷에 [NAT 게이트웨이](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html)를 구성하거나 Lambda, [AWS Security Token Service(STS)](https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html), [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html)(선택 사항)에 대한 액세스를 제공하는 VPC의 프라이빗 서브넷에 [AWS PrivateLink](https://docs.aws.amazon.com/vpc/latest/privatelink/what-is-privatelink.html) 엔드포인트를 구성해야 합니다. 이러한 옵션 중 하나를 올바르게 구성하면 함수를 간접적으로 호출하는 데 필요한 VPC와 Lambda 관리형 런타임 VPC 간 연결이 허용됩니다.

NAT 게이트웨이를 사용하면 프라이빗 서브넷의 리소스가 퍼블릭 인터넷에 액세스할 수 있습니다. 이 구성을 사용하면 Lambda 함수를 간접적으로 호출하기 전에 트래픽이 인터넷을 통과하게 됩니다. AWS PrivateLink 엔드포인트를 사용하면 프라이빗 서브넷이 퍼블릭 인터넷을 통과하지 않고도 AWS 서비스 또는 기타 프라이빗 VPC 리소스에 안전하게 연결할 수 있습니다. 이러한 리소스를 구성하는 방법에 대한 자세한 내용은 [MSK 이벤트 소스에 대한 NAT 게이트웨이 구성](#msk-nat-gateway) 또는 [MSK 이벤트 소스에 대한 AWS PrivateLink 엔드포인트 구성](#msk-vpc-privatelink) 섹션을 참조하세요.

지금까지는 MSK 클러스터가 VPC 내의 프라이빗 서브넷에 상주한다고 가정했는데, 이는 더 일반적인 경우입니다. 그러나 MSK 클러스터가 VPC 내의 퍼블릭 서브넷에 있더라도 보안 연결을 활성화하도록 AWS PrivateLink 엔드포인트를 구성해야 합니다. 다음 표에는 MSK 클러스터와 Lambda 이벤트 소스 매핑을 구성하는 방법에 따른 네트워킹 구성 요구 사항이 요약되어 있습니다.


| MSK 클러스터 위치(고객 관리형 VPC 내) | Lambda 이벤트 소스 매핑 스케일링 모드 | 필수 네트워킹 구성 | 
| --- | --- | --- | 
|  Private subnet  |  온디맨드 모드  |  Lambda, AWS STS 및 Secrets Manager(선택 사항)에 대한 액세스를 활성화하기 위한 NAT 게이트웨이(VPC의 퍼블릭 서브넷 내) 또는 AWS PrivateLink 엔드포인트(VPC의 프라이빗 서브넷 내)  | 
|  Public subnet  |  온디맨드 모드  |  Lambda, AWS STS 및 Secrets Manager(선택 사항)에 대한 액세스를 활성화하기 위한 AWS PrivateLink 엔드포인트(VPC의 퍼블릭 서브넷 내)  | 
|  Private subnet  |  프로비저닝된 모드  |  없음  | 
|  Public subnet  |  프로비저닝된 모드  |  없음  | 

또한 MSK 클러스터와 연결된 보안 그룹이 올바른 포트를 통해 트래픽을 허용해야 합니다. 다음 보안 그룹 규칙이 구성되어 있는지 확인합니다.
+ **인바운드 규칙** - 기본 브로커 포트의 모든 트래픽을 허용합니다. MSK가 사용하는 포트는 클러스터의 인증 유형에 따라 다릅니다. IAM 인증의 경우 `9098`, SASL/SCRAM의 경우 `9096`, TLS의 경우 `9094`입니다. 또는 자체 참조 보안 그룹 규칙을 사용하여 동일한 보안 그룹 내의 인스턴스에서 액세스를 허용할 수 있습니다.
+ **아웃바운드 규칙** - 함수가 다른 AWS 서비스와 통신해야 하는 경우 외부 대상에 대한 포트 `443`의 모든 트래픽을 허용합니다. 다른 AWS 서비스와 통신할 필요가 없는 경우 자체 참조 보안 그룹 규칙을 사용하여 브로커에 대한 액세스를 제한할 수도 있습니다.
+ **Amazon VPC 엔드포인트 인바운드 규칙** - Amazon VPC 엔드포인트를 사용하는 경우 엔드포인트와 연결된 보안 그룹이 클러스터의 보안 그룹에서 포트 `443`의 인바운드 트래픽을 허용해야 합니다.

## MSK 이벤트 소스에 대한 NAT 게이트웨이 구성
<a name="msk-nat-gateway"></a>

이벤트 소스 매핑이 클러스터에서 메시지를 폴링하도록 허용하도록 NAT 게이트웨이를 구성하고 VPC를 통한 경로를 통해 함수를 간접적으로 호출할 수 있습니다. 이는 이벤트 소스 매핑이 온디맨드 모드를 사용하고 클러스터가 VPC의 프라이빗 서브넷 내에 상주하는 경우에만 필요합니다. 클러스터가 VPC의 퍼블릭 서브넷에 상주하거나 이벤트 소스 매핑이 프로비저닝된 모드를 사용하는 경우 NAT 게이트웨이를 구성할 필요가 없습니다.

[NAT 게이트웨이](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html)를 사용하면 프라이빗 서브넷의 리소스가 퍼블릭 인터넷에 액세스할 수 있습니다. Lambda에 대한 프라이빗 연결이 필요한 경우 [MSK 이벤트 소스에 대한 AWS PrivateLink 엔드포인트 구성](#msk-vpc-privatelink) 섹션을 대신 참조하세요.

NAT 게이트웨이를 구성한 후 적절한 라우팅 테이블을 구성해야 합니다. 이렇게 하면 프라이빗 서브넷의 트래픽이 NAT 게이트웨이를 통해 퍼블릭 인터넷으로 라우팅될 수 있습니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/MSK-NAT-Gateway.png)


다음 단계에서는 콘솔을 사용하여 NAT 게이트웨이를 구성하는 방법을 안내합니다. 각 가용 영역(AZ)에 대해 필요에 따라 이 단계를 반복합니다.

**NAT 게이트웨이와 적절한 라우팅을 구성하려면 다음을 수행하세요(콘솔).**

1. 다음 사항에 유의하여 [NAT 게이트웨이 생성](https://docs.aws.amazon.com/vpc/latest/userguide/nat-gateway-working-with.html)의 단계를 따릅니다.
   + NAT 게이트웨이는 항상 퍼블릭 서브넷에 상주해야 합니다. [퍼블릭 연결](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html)이 있는 NAT 게이트웨이를 생성합니다.
   + MSK 클러스터가 여러 AZ에 복제되는 경우 AZ당 하나의 NAT 게이트웨이를 생성합니다. 예를 들어, 각 AZ에서 클러스터를 포함하는 프라이빗 서브넷 1개와 NAT 게이트웨이를 포함하는 퍼블릭 서브넷 1개가 VPC에 있어야 합니다. 3개의 AZ를 사용하는 설정의 경우 3개의 프라이빗 서브넷, 3개의 퍼블릭 서브넷, 3개의 NAT 게이트웨이를 갖게 됩니다.

1. NAT 게이트웨이를 생성한 후 [Amazon VPC 콘솔](https://console.aws.amazon.com/vpc/)을 열고 왼쪽 메뉴에서 **라우팅 테이블**을 선택합니다.

1. **라우팅 테이블 생성**을 선택합니다.

1. 이 라우팅 테이블을 MSK 클러스터가 포함된 VPC와 연결합니다. 선택 사항으로 라우팅 테이블의 이름을 입력합니다.

1. **라우팅 테이블 생성**을 선택합니다.

1. 방금 생성한 라우팅 테이블을 선택합니다.

1. **서브넷 연결** 탭에서 **서브넷 연결 편집**을 선택합니다.
   + 이 라우팅 테이블을 MSK 클러스터가 포함된 프라이빗 서브넷과 연결합니다.

1. **라우팅 편집(Edit routes)**을 선택합니다.

1. **라우팅 추가**를 선택합니다.

   1. **Destination(대상)**에 `0.0.0.0/0`을 선택합니다.

   1. **대상**에서 **NAT 게이트웨이**를 선택합니다.

   1. 검색 상자에서 1단계에서 생성한 NAT 게이트웨이를 선택합니다. MSK 클러스터가 포함된 프라이빗 서브넷(6단계에서 이 라우팅 테이블과 연결한 프라이빗 서브넷)과 동일한 AZ의 NAT 게이트웨이여야 합니다.

1. **변경 사항 저장**을 선택합니다.

## MSK 이벤트 소스에 대한 AWS PrivateLink 엔드포인트 구성
<a name="msk-vpc-privatelink"></a>

클러스터에서 메시지를 폴링하도록 허용하도록 AWS PrivateLink 엔드포인트를 구성하고 VPC를 통한 경로를 통해 함수를 간접적으로 호출할 수 있습니다. 이러한 엔드포인트는 MSK 클러스터가 다음에 액세스할 수 있도록 허용해야 합니다.
+ Lambda 서비스
+ [AWS Security Token Service(STS)](https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html)
+ [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) 서비스(선택 사항). 클러스터 인증에 필요한 보안 암호가 Secrets Manager에 저장되어 있는 경우 필수입니다.

이벤트 소스 매핑이 온디맨드 모드를 사용하는 경우에만 PrivateLink 엔드포인트 구성이 필요합니다. 이벤트 소스 매핑이 프로비저닝된 모드를 사용하는 경우 Lambda가 필요한 연결을 설정합니다.

PrivateLink 엔드포인트는 AWS PrivateLink를 통해 AWS 서비스에 대한 보안 프라이빗 액세스를 허용합니다. 또는 MSK 클러스터에 퍼블릭 인터넷에 대한 액세스 권한을 부여하도록 NAT 게이트웨이를 구성하려면 [MSK 이벤트 소스에 대한 NAT 게이트웨이 구성](#msk-nat-gateway) 섹션을 참조하세요.

VPC 엔드포인트를 구성한 후 MSK 클러스터에 Lambda, STS 및 Secrets Manager(선택 사항)에 대한 직접 및 프라이빗 액세스 권한이 있어야 합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/MSK-PrivateLink-Endpoints.png)


다음 단계에서는 콘솔을 사용하여 PrivateLink 엔드포인트를 구성하는 방법을 안내합니다. 각 엔드포인트(Lambda, STS, Secrets Manager)에 대해 필요에 따라 다음 단계를 반복합니다.

**VPC PrivateLink 엔드포인트를 구성하려면 다음을 수행하세요(콘솔).**

1. [Amazon VPC 콘솔](https://console.aws.amazon.com/vpc/)을 열고 왼쪽 메뉴에서 **엔드포인트**를 선택합니다.

1. **엔드포인트 생성**을 선택합니다.

1. 선택 사항으로 엔드포인트의 이름을 입력합니다.

1. **유형**에서 **AWS 서비스**를 선택합니다.

1. **서비스**에서 서비스 이름 입력을 시작합니다. 예를 들어 Lambda에 연결할 엔드포인트를 생성하려면 검색 상자에 `lambda`를 입력합니다.

1. 결과에 현재 리전의 서비스 엔드포인트가 표시되어야 합니다. 예를 들어, 미국 동부(버지니아 북부) 리전에서는 `com.amazonaws.us-east-2.lambda`가 표시되어야 합니다. 이 서비스를 선택합니다.

1. **네트워크 설정**에서 MSK 클러스터가 포함된 VPC를 선택합니다.

1. **서브넷**에서 MSK 클러스터가 있는 AZ를 선택합니다.
   + 각 AZ의 **서브넷 ID**에서 MSK 클러스터가 포함된 프라이빗 서브넷을 선택합니다.

1. **보안 그룹**에서 MSK 클러스터와 연결된 보안 그룹을 선택합니다.

1. **엔드포인트 생성**을 선택합니다.

기본적으로 Amazon VPC 엔드포인트에는 리소스에 대한 광범위한 액세스를 허용하는 개방형 IAM 정책이 있습니다. 모범 사례는 해당 엔드포인트를 사용하여 필요한 작업을 수행하도록 이러한 정책을 제한하는 것입니다. 예를 들어 Secrets Manager 엔드포인트의 경우 함수의 실행 역할만 보안 암호에 액세스할 수 있도록 정책을 수정할 수 있습니다.

**Example VPC 엔드포인트 정책 – Secrets Manager 엔드포인트**  

```
{
    "Statement": [
        {
            "Action": "secretsmanager:GetSecretValue",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws::iam::123456789012:role/my-role"
                ]
            },
            "Resource": "arn:aws::secretsmanager:us-west-2:123456789012:secret:my-secret"
        }
    ]
}
```

AWS STS 및 Lambda 엔드포인트의 경우 직접 호출 위탁자를 Lambda 서비스 위탁자로 제한할 수 있습니다. 그러나 이러한 정책에서는 `"Resource": "*"`를 사용해야 합니다.

**Example VPC 엔드포인트 정책 - AWS STS 엔드포인트**  

```
{
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "lambda.amazonaws.com"
                ]
            },
            "Resource": "*"
        }
    ]
}
```

**Example VPC 엔드포인트 정책 - Lambda 엔드포인트**  

```
{
    "Statement": [
        {
            "Action": "lambda:InvokeFunction",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "lambda.amazonaws.com"
                ]
            },
            "Resource": "*"
        }
    ]
}
```

# Amazon MSK 이벤트 소스 매핑에 대한 Lambda 권한 구성
<a name="with-msk-permissions"></a>

Amazon MSK 클러스터에 액세스하려면 함수와 이벤트 소스 매핑에 다양한 Amazon MSK API 작업을 수행할 수 있는 권한이 필요합니다. 함수의 [실행 역할](lambda-intro-execution-role.md)에 이러한 권한을 추가합니다. 사용자에게 액세스 권한이 필요한 경우 사용자 또는 역할에 대한 ID 정책에 필요한 권한을 추가합니다.

[AWSLambdaMSKExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaMSKExecutionRole.html) 관리형 정책에는 Amazon MSK Lambda 이벤트 소스 매핑에 필요한 최소 권한이 포함되어 있습니다. 다음 작업을 통해 권한 프로세스를 간소화할 수 있습니다.
+ [AWSLambdaMSKExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaMSKExecutionRole.html) 관리형 정책을 실행 역할에 연결합니다.
+ Lambda 콘솔에서 권한을 생성하도록 합니다. [콘솔에서 Amazon MSK 이벤트 소스 매핑을 생성](msk-esm-create.md#msk-console)하면 Lambda에서 실행 역할을 평가하고 권한이 누락된 경우 알립니다. **권한 생성**을 선택하여 실행 역할을 자동으로 업데이트합니다. 실행 역할 정책을 수동으로 생성하거나 수정한 경우 또는 정책이 여러 역할에 연결된 경우에는 효과가 없습니다. [실패 시 대상](kafka-on-failure.md) 또는 [AWS Glue Schema Registry](services-consume-kafka-events.md)와 같은 고급 기능을 사용하는 경우에도 실행 역할에 추가 권한이 필요할 수 있습니다.

**Topics**
+ [

## 필수 권한
](#msk-required-permissions)
+ [

## 선택적 권한
](#msk-optional-permissions)

## 필수 권한
<a name="msk-required-permissions"></a>

Amazon MSK 이벤트 소스 매핑에 대한 Lambda 함수 실행 역할에는 다음 권한이 필요합니다. 이러한 권한은 [AWSLambdaMSKExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaMSKExecutionRole.html) 관리형 정책에 포함됩니다.

### CloudWatch Logs 권한
<a name="msk-basic-permissions"></a>

다음 권한을 통해 Lambda는 Amazon CloudWatch Logs에 로그를 생성하고 저장할 수 있습니다.
+ [logs:CreateLogGroup](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html)
+ [logs:CreateLogStream](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogStream.html)
+ [logs:PutLogEvents](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html)

### MSK 클러스터 권한
<a name="msk-cluster-permissions"></a>

다음 권한을 통해 Lambda는 사용자를 대신하여 Amazon MSK 클러스터에 액세스할 수 있습니다.
+ [kafka:DescribeCluster](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn.html)
+ [kafka:DescribeClusterV2](https://docs.aws.amazon.com/MSK/2.0/APIReference/v2-clusters-clusterarn.html)
+ [kafka:GetBootstrapBrokers](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn-bootstrap-brokers.html)

[kafka:DescribeCluster](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn.html) 대신 [kafka:DescribeClusterV2](https://docs.aws.amazon.com/MSK/2.0/APIReference/v2-clusters-clusterarn.html)를 사용하는 것이 좋습니다. v2 권한은 프로비저닝된 Amazon MSK 클러스터와 서버리스 Amazon MSK 클러스터 모두에서 작동합니다. 정책에는 이 권한 중 하나만 필요합니다.

### VPC 권한
<a name="msk-vpc-permissions"></a>

다음 권한을 통해 Lambda는 Amazon MSK 클러스터에 연결할 때 네트워크 인터페이스를 생성 및 관리할 수 있습니다.
+ [ec2:CreateNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html)
+ [ec2:DescribeNetworkInterfaces](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html)
+ [ec2:DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
+ [ec2:DeleteNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkInterface.html)
+ [ec2:DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
+ [ec2:DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)

## 선택적 권한
<a name="msk-optional-permissions"></a>

 Lambda 함수에 또한 다음 권한이 필요할 수 있습니다.
+ 교차 계정 Amazon MSK 클러스터에 액세스합니다. 교차 계정 이벤트 소스 매핑의 경우 실행 역할에 [kafka:DescribeVpcConnection](https://docs.aws.amazon.com/msk/1.0/apireference/vpc-connection-arn.html)이 필요합니다. 교차 계정 이벤트 소스 매핑을 생성하는 IAM 보안 주체에는 [kafka:ListVpcConnections](https://docs.aws.amazon.com/msk/1.0/apireference/vpc-connections.html)가 필요합니다.
+ [SASL/SCRAM 인증](msk-cluster-auth.md#msk-sasl-scram)을 사용하는 경우 SCRAM 보안 암호에 액세스 이렇게 하면 함수가 사용자 이름과 암호를 사용하여 Kafka에 연결할 수 있습니다.
+ SASL/SCRAM 또는 [mTLS 인증을](msk-cluster-auth.md#msk-mtls) 사용하는 경우 Secrets Manager 보안 암호 설명 이렇게 하면 함수가 보안 연결에 필요한 자격 증명이나 인증서를 검색할 수 있습니다.
+ AWS Secrets Manager 보안 암호가 AWS KMS 고객 관리형 키로 암호화된 경우 AWS KMS 고객 관리형 키에 액세스합니다.
+ 인증과 함께 스키마 레지스트리를 사용하는 경우 스키마 레지스트리 시크릿에 액세스합니다.
  + AWS Glue 스키마 레지스트리의 경우: 함수에 `glue:GetRegistry` 및 `glue:GetSchemaVersion` 권한이 필요합니다. 이를 통해 함수가 AWS Glue에 저장된 메시지 형식 규칙을 조회하고 사용할 수 있습니다.
  + `BASIC_AUTH` 또는 `CLIENT_CERTIFICATE_TLS_AUTH`를 사용하는 [Confluent 스키마 레지스트리](https://docs.confluent.io/platform/current/schema-registry/security/index.html)의 경우: 함수에 인증 자격 증명이 포함된 시크릿에 대한 `secretsmanager:GetSecretValue` 권한이 필요합니다. 이렇게 하면 함수가 Confluent 스키마 레지스트리에 액세스하는 데 필요한 사용자 이름/암호 또는 인증서를 검색할 수 있습니다.
  + Private CA Certificate의 경우: 함수에 인증서가 포함된 시크릿에 대한 secretsmanager:GetSecretValue 권한이 필요합니다. 이렇게 하면 함수가 사용자 지정 인증서를 사용하는 스키마 레지스트리의 ID를 확인할 수 있습니다.
+ 이벤트 소스 매핑에 IAM 인증을 사용하는 경우 주제에서 Kafka 클러스터 소비자 그룹에 액세스하고 메시지를 폴링합니다.

 이는 다음과 같은 필수 권한에 해당합니다.
+ [kafka:ListScramSecrets](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn-scram-secrets.html) - Kafka 인증을 위한 SCRAM 시크릿 나열 허용
+ [secretsmanager:GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html) - Secrets Manager에서 시크릿 검색 활성화
+ [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) - AWS KMS를 사용하여 암호화된 데이터의 복호화 허용
+ [glue:GetRegistry](https://docs.aws.amazon.com/glue/latest/webapi/API_GetRegistry.html) - AWS Glue 스키마 레지스트리에 대한 액세스 허용
+ [glue:GetSchemaVersion](https://docs.aws.amazon.com/glue/latest/webapi/API_GetSchemaVersion.html) - AWS Glue 스키마 레지스트리에서 특정 스키마 버전 검색 활성화
+ [kafka-cluster:Connect](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - 클러스터에 연결하고 인증할 수 있는 권한 부여
+ [kafka-cluster:AlterGroup](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - Apache Kafka의 READ GROUP ACL에 해당하는 클러스터에서 그룹에 참여할 수 있는 권한 부여
+ [kafka-cluster:DescribeGroup](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - Apache Kafka의 DESCRIBE GROUP ACL에 해당하는 클러스터에서 그룹을 설명할 수 있는 권한 부여
+ [kafka-cluster:DescribeTopic](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - Apache Kafka의 DESCRIBE TOPIC ACL에 해당하는 클러스터에서 주제를 설명할 수 있는 권한 부여
+ [kafka-cluster:ReadData](https://docs.aws.amazon.com/service-authorization/latest/reference/list_apachekafkaapisforamazonmskclusters.html) - Apache Kafka의 READ TOPIC ACL에 해당하는 클러스터에서 주제의 데이터를 읽을 수 있는 권한 부여

 또한 실패한 간접 호출의 레코드를 장애 시 대상으로 전송하려면 대상 유형에 따라 다음과 같은 권한이 필요합니다: 
+ Amazon SQS 대상의 경우: [sqs:SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) - Amazon SQS 대기열로 메시지 전송 허용
+ Amazon SNS 대상의 경우: [sns:Publish](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html) - Amazon SNS 주제에 메시지 게시 허용
+ Amazon S3 버킷 대상의 경우: [s3:PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 및 [s3:ListBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucket.html) - Amazon S3 버킷에서 객체 쓰기 및 나열 활성화

일반적인 인증 및 권한 부여 오류 문제를 해결할 경우 [Kafka 이벤트 소스 매핑 오류 문제 해결](with-kafka-troubleshoot.md) 섹션을 참조하세요.

# Lambda용 Amazon MSK 이벤트 소스 구성
<a name="with-msk-configure"></a>

Amazon MSK 클러스터를 Lambda 함수의 이벤트 소스로 사용하려면 두 리소스를 연결하는 [이벤트 소스 매핑](invocation-eventsourcemapping.md)을 생성합니다. 이 페이지에서는 Amazon MSK에 대한 이벤트 소스 매핑을 생성하는 방법을 설명합니다.

이 페이지에서는 MSK 클러스터와 해당 클러스터가 있는 [Amazon Virtual Private Cloud(VPC)](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html)를 이미 올바르게 구성했다고 가정합니다. 클러스터나 VPC를 설정해야 하는 경우 [Lambda를 위한 Amazon MSK 클러스터 및 Amazon VPC 네트워크 구성](with-msk-cluster-network.md) 섹션을 참조하세요. 오류 처리를 위한 재시도 동작을 구성하려면 [Kafka 이벤트 소스의 오류 처리 제어 구성](kafka-retry-configurations.md) 항목을 참조하세요.

**Topics**
+ [

## Amazon MSK 클러스터를 이벤트 소스로 사용
](#msk-esm-overview)
+ [

# Lambda에서 Amazon MSK 클러스터 인증 방법 구성
](msk-cluster-auth.md)
+ [

# Amazon MSK 이벤트 소스에 대한 Lambda 이벤트 소스 매핑 생성
](msk-esm-create.md)
+ [

# Lambda에서 교차 계정 이벤트 소스 매핑 생성
](msk-cross-account.md)
+ [

# Lambda에서의 모든 Amazon MSK 이벤트 소스 구성 파라미터
](msk-esm-parameters.md)

## Amazon MSK 클러스터를 이벤트 소스로 사용
<a name="msk-esm-overview"></a>

Apache Kafka 또는 Amazon MSK 클러스터를 Lambda 함수의 트리거로 추가하면 해당 클러스터가 [이벤트 소스](invocation-eventsourcemapping.md)로 사용됩니다.

Lambda는 사용자가 지정한 [시작 위치](kafka-starting-positions.md)를 기반으로 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 요청에서 `Topics`로 지정한 Kafka 주제에서 이벤트 데이터를 읽습니다. 성공적인 처리 후, Kafka 토픽은 Kafka 클러스터에 커밋됩니다.

Lambda는 각 Kafka 주제 파티션에 대해 순차적으로 메시지를 읽습니다. 단일 Lambda 페이로드에는 여러 파티션의 메시지가 포함될 수 있습니다. 사용 가능한 레코드가 더 있는 경우 Lambda는 함수가 주제를 따라잡을 때까지 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 요청에서 지정한 BatchSize 값을 기반으로 배치로 레코드를 계속 처리합니다.

Lambda는 각 배치를 처리한 후 해당 배치에 있는 메시지의 오프셋을 커밋합니다. 함수가 배치의 어떤 메시지에 대해 오류를 반환하면 Lambda는 처리가 성공하거나 메시지가 만료될 때까지 전체 메시지 배치를 다시 시도합니다. 모든 재시도에 실패한 레코드를 실패 시 대상으로 전송하여 나중에 처리하도록 할 수 있습니다.

**참고**  
Lambda 함수의 최대 제한 시간은 일반적으로 15분이지만 Amazon MSK, 자체 관리형 Apache Kafka, Amazon DocumentDB, ActiveMQ 및 RabbitMQ용 Amazon MQ에 대한 이벤트 소스 매핑은 최대 제한 시간이 14분인 함수만 지원합니다.

# Lambda에서 Amazon MSK 클러스터 인증 방법 구성
<a name="msk-cluster-auth"></a>

Lambda는 Amazon MSK 클러스터에 액세스하고 레코드를 검색하고 다른 태스크를 수행할 수 있는 권한이 필요합니다. Amazon MSK는 MSK 클러스터를 통해 인증하는 여러 가지 방법을 지원합니다.

**Topics**
+ [

## 인증되지 않은 액세스
](#msk-unauthenticated)
+ [

## SASL/SCRAM 인증
](#msk-sasl-scram)
+ [

## 상호 TLS 인증
](#msk-mtls)
+ [

## IAM 인증
](#msk-iam-auth)
+ [

## Lambda이 부트스트랩 브로커를 선택하는 방법
](#msk-bootstrap-brokers)

## 인증되지 않은 액세스
<a name="msk-unauthenticated"></a>

인터넷을 통해 클러스터에 액세스하는 클라이언트가 없는 경우 인증되지 않은 액세스를 사용할 수 있습니다.

## SASL/SCRAM 인증
<a name="msk-sasl-scram"></a>

Lambda는 SHA-512 해시 함수와 Transport Layer Security(TLS) 암호화를 통해 [Simple Authentication and Security Layer/Salted Challenge Response Authentication Mechanism(SASL/SCRAM)](https://docs.aws.amazon.com/msk/latest/developerguide/msk-password-tutorial.html) 인증을 지원합니다. Lambda가 클러스터에 연결하려면 인증 자격 증명(사용자 이름 및 암호)을 Secrets Manager 보안 암호에 저장하고 이벤트 소스 매핑을 구성할 때 이 보안 암호를 참조합니다.

Secrets Manager 사용에 대한 자세한 내용은 *Amazon Managed Streaming for Apache Kafka 개발자 안내서*의 [Sign-in credentials authentication with Secrets Manager](https://docs.aws.amazon.com/msk/latest/developerguide/msk-password.html)를 참조하세요.

**참고**  
Amazon MSK는 SASL/PLAIN 인증을 지원하지 않습니다.

## 상호 TLS 인증
<a name="msk-mtls"></a>

상호 TLS(mTLS)는 클라이언트와 서버 간의 양방향 인증을 제공합니다. 클라이언트는 서버가 클라이언트를 확인할 수 있도록 인증서를 서버로 전송합니다. 서버는 또한 클라이언트가 서버를 확인할 수 있도록 클라이언트에 인증서를 전송합니다.

Amazon MSK와 Lambda 통합의 경우 MSK 클러스터는 서버 역할을 하고 Lambda는 클라이언트 역할을 합니다.
+ Lambda가 MSK 클러스터를 확인하려면 Secrets Manager에서 클라이언트 인증서를 보안 암호로 구성하고 이벤트 소스 매핑 구성에서 이 인증서를 참조합니다. 클라이언트 인증서는 서버의 신뢰 저장소에 있는 인증 기관(CA)에서 서명해야 합니다.
+ MSK 클러스터는 서버 인증서도 Lambda로 전송합니다. 서버 인증서는 AWS 트러스트 스토어에 있는 인증 기관(CA)에서 서명해야 합니다.

Amazon MSK는 자체 서명 서버 인증서를 지원하지 않습니다. Amazon MSK의 모든 브로커는 기본적으로 Lambda가 신뢰하는 [Amazon Trust Services CA](https://docs.aws.amazon.com/msk/latest/developerguide/msk-encryption.html)에서 서명한 [퍼블릭 인증서](https://www.amazontrust.com/repository/)를 사용하기 때문입니다.

### mTLS 암호 구성
<a name="mtls-auth-secret"></a>

CLIENT\$1CERTIFICATE\$1TLS\$1AUTH 비밀 정보에 인증서 필드와 프라이빗 키 필드가 필요합니다. 암호화된 프라이빗 키의 경우 비밀 정보에 프라이빗 키 암호가 필요합니다. 인증서와 프라이빗 키는 모두 PEM 형식이어야 합니다.

**참고**  
Lambda는 [PBES1](https://datatracker.ietf.org/doc/html/rfc2898/#section-6.1)(PBES2가 아님) 프라이빗 키 암호화 알고리즘을 지원합니다.

인증서 필드에는 클라이언트 인증서부터 시작하여 중간 인증서가 이어지고 루트 인증서로 끝나는 인증서 목록이 포함되어야 합니다. 각 인증서는 다음 구조의 새 줄에서 시작해야 합니다.

```
-----BEGIN CERTIFICATE-----  
        <certificate contents>
-----END CERTIFICATE-----
```

Secrets Manager는 최대 65,536바이트의 보안 정보를 지원하므로 긴 인증서 체인을 위한 충분한 공간입니다.

프라이빗 키는 다음 구조의 [PKCS \$18](https://datatracker.ietf.org/doc/html/rfc5208) 형식이어야 합니다.

```
-----BEGIN PRIVATE KEY-----  
         <private key contents>
-----END PRIVATE KEY-----
```

암호화된 프라이빗 키의 경우 다음 구조를 사용합니다.

```
-----BEGIN ENCRYPTED PRIVATE KEY-----  
          <private key contents>
-----END ENCRYPTED PRIVATE KEY-----
```

다음 예제에서는 암호화된 프라이빗 키를 사용한 mTLS 인증용 비밀 정보 콘텐츠를 표시합니다. 암호화된 개인 키의 경우 비밀 정보에 프라이빗 키 암호를 포함합니다.

```
{
 "privateKeyPassword": "testpassword",
 "certificate": "-----BEGIN CERTIFICATE-----
MIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw
...
j0Lh4/+1HfgyE2KlmII36dg4IMzNjAFEBZiCRoPimO40s1cRqtFHXoal0QQbIlxk
cmUuiAii9R0=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb
...
rQoiowbbk5wXCheYSANQIfTZ6weQTgiCHCCbuuMKNVS95FkXm0vqVD/YpXKwA/no
c8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==
-----END CERTIFICATE-----",
 "privateKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFKzBVBgkqhkiG9w0BBQ0wSDAnBgkqhkiG9w0BBQwwGgQUiAFcK5hT/X7Kjmgp
...
QrSekqF+kWzmB6nAfSzgO9IaoAaytLvNgGTckWeUkWn/V0Ck+LdGUXzAC4RxZnoQ
zp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==
-----END ENCRYPTED PRIVATE KEY-----"
}
```

mTLS for Amazon MSK에 대한 자세한 내용과 클라이언트 인증서 생성 방법에 대한 지침은 *Amazon Managed Streaming for Apache Kafka Developer Guide*의 [Mutual TLS client authentication for Amazon MSK](https://docs.aws.amazon.com/msk/latest/developerguide/msk-authentication.html)를 참조하세요.

## IAM 인증
<a name="msk-iam-auth"></a>

AWS Identity and Access Management(IAM)를 사용하여 MSK 클러스터에 연결하는 클라이언트의 ID를 인증할 수 있습니다. IAM 인증을 사용하면 Lambda는 함수 [실행 역할](lambda-intro-execution-role.md)의 권한에 따라 클러스터에 연결하고, 레코드를 검색하고, 기타 필요한 작업을 수행합니다. 필요한 권한이 포함된 샘플 정책은 *Amazon Managed Streaming for Apache Kafka 개발자 안내서*의 [IAM 역할을 위한 권한 부여 정책 생성](https://docs.aws.amazon.com/msk/latest/developerguide/create-iam-access-control-policies.html)을 참조하세요.

IAM 인증이 MSK 클러스터에서 활성 상태이고 보안 암호를 제공하지 않으면 Lambda는 자동으로 IAM 인증을 사용하도록 기본 설정됩니다.

Amazon MSK의 IAM 인증에 대한 자세한 내용은 [IAM access control](https://docs.aws.amazon.com/msk/latest/developerguide/iam-access-control.html)을 참조하세요.

## Lambda이 부트스트랩 브로커를 선택하는 방법
<a name="msk-bootstrap-brokers"></a>

Lambda는 클러스터에서 사용할 수 있는 인증 방법 및 인증을 위한 암호 제공 여부를 기반으로 [부트스트랩 브로커](https://docs.aws.amazon.com/msk/latest/developerguide/msk-get-bootstrap-brokers.html)를 선택합니다. mTLS 또는 SASL/SCRAM에 대한 암호를 제공하면 Lambda가 자동으로 해당 인증 방법을 선택합니다. 암호를 제공하지 않으면 Lambda가 클러스터에서 활성화된 가장 강력한 인증 방법을 선택합니다. 다음은 Lambda가 가장 강력한 인증부터 가장 약한 인증까지 브로커를 선택하는 우선 순위입니다.
+ mTLS(MTL에 제공되는 암호)
+ SASL/SCRAM(SASL/SCRAM에 대해 제공되는 암호)
+ SASL IAM(암호가 제공되지 않았으며 IAM 인증이 활성화됨)
+ 인증되지 않은 TLS(암호가 제공되지 않고 IAM 인증이 활성화되지 않음)
+ 일반 텍스트(암호가 제공되지 않고 IAM 인증 및 인증되지 않은 TLS가 모두 활성화되지 않음)

**참고**  
Lambda가 가장 안전한 브로커 유형에 연결할 수 없는 경우 Lambda는 다른 (약한) 브로커 유형에 연결을 시도하지 않습니다. Lambda가 더 약한 브로커 유형을 선택하게 하려면 클러스터에서 더 강력한 인증 방법을 모두 비활성화하십시오.

# Amazon MSK 이벤트 소스에 대한 Lambda 이벤트 소스 매핑 생성
<a name="msk-esm-create"></a>

이벤트 소스 매핑을 생성하려면 Lambda 콘솔, [AWS Command Line Interface(CLI)](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 또는 [AWS SDK](https://aws.amazon.com/getting-started/tools-sdks/)를 사용할 수 있습니다.

**참고**  
이벤트 소스 매핑을 생성하면 Lambda는 MSK 클러스터가 포함된 프라이빗 서브넷에 [하이퍼플레인 ENI](configuration-vpc.md#configuration-vpc-enis)를 생성하여 Lambda가 보안 연결을 설정할 수 있도록 합니다. 이 하이퍼플레인 ENI는 Lambda 함수가 아닌 MSK 클러스터의 서브넷과 보안 그룹 구성을 사용합니다.

다음 콘솔 단계에서는 Amazon MSK 클러스터를 Lambda 함수의 트리거로 추가합니다. 그러면 내부적으로 이벤트 소스 매핑 리소스가 생성됩니다.

**Lambda 함수에 Amazon MSK 트리거를 추가하려면(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. Amazon MSK 트리거를 추가할 Lambda 함수의 이름을 선택합니다.

1. **함수 개요(Function overview)**에서 **트리거 추가(Add trigger)**를 선택합니다.

1. **트리거 구성**에서 **MSK**를 선택합니다.

1. Kafka 클러스터 세부 정보를 지정하려면 다음을 수행합니다.

   1. **MSK 클러스터**에 해당 클러스터를 선택합니다.

   1. **주제 이름**에 메시지를 사용할 Kafka 주제의 이름을 입력합니다.

   1. **소비자 그룹 ID**에서 가입할 Kafka 소비자 그룹의 ID(해당되는 경우)를 입력합니다. 자세한 내용은 [Lambda에서 사용자 지정이 가능한 소비자 그룹 ID](kafka-consumer-group-id.md) 섹션을 참조하세요.

1. **클러스터 인증**에 대해 필요에 따라 구성합니다. 클러스터 인증에 대한 자세한 내용은 [Lambda에서 Amazon MSK 클러스터 인증 방법 구성](msk-cluster-auth.md) 섹션을 참조하세요.
   + 연결을 설정할 때 Lambda가 MSK 클러스터로 인증을 수행하도록 하려면 **인증 사용**을 켭니다. 인증이 권장됩니다.
   + 인증을 사용하는 경우 **인증 방법**에서 사용할 인증 방법을 선택합니다.
   + 인증을 사용하는 경우 **Secrets Manager 키**에서 클러스터에 액세스하는 데 필요한 인증 자격 증명이 포함된 Secrets Manager 키를 선택합니다.

1. **이벤트 폴러 구성**에서 필요에 따라 구성합니다.
   + 생성 직후 트리거를 활성화하려면 **트리거 활성화**를 선택합니다.
   + 이벤트 소스 매핑에 대해 **프로비저닝된 모드를 구성**할지 여부를 선택합니다. 자세한 내용은 [Lambda에서의 Apache Kafka 이벤트 폴러 스케일링 모드](kafka-scaling-modes.md) 섹션을 참조하세요.
     + 프로비저닝 모드를 구성하는 경우 **최소 이벤트 폴러**의 값, **최대 이벤트 폴러**의 값, PollerGroupName 값(선택 사항)을 입력하여 동일한 이벤트 소스 VPC 내에서 여러 ESM의 그룹화를 지정합니다.
   + **시작 위치**에서 Lambda가 스트림에서 읽기를 시작하는 방법을 선택합니다. 자세한 내용은 [Lambda에서의 Apache Kafka 폴링 및 스트림 시작 위치](kafka-starting-positions.md) 섹션을 참조하세요.

1. **배치 처리**에서 필요에 따라 구성합니다. 일괄 처리에 대한 자세한 내용은 [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching) 섹션을 참조하세요.

   1. **배치 크기(Batch size)**에 단일 배치에서 검색할 최대 메시지 수를 입력합니다.

   1. **배치 창**에서 Lambda가 함수를 간접적으로 호출하기 전에 레코드를 수집하는 데 걸리는 최대 시간(초)을 입력합니다.

1. **필터링**에서 필요에 따라 구성합니다. 필터링에 대한 자세한 내용은 [Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스에서 이벤트 필터링](kafka-filtering.md) 섹션을 참조하세요.
   + **필터 기준**에서 필터 기준 정의를 추가하여 이벤트를 처리할지 여부를 결정합니다.

1. **장애 처리**에서 필요에 따라 구성합니다. 장애 처리에 대한 자세한 내용은 [Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스에 대한 폐기된 배치 캡처](kafka-on-failure.md) 섹션을 참조하세요.
   + **장애 시 대상**에서 장애 시 대상의 ARN을 지정합니다.

1. **태그**에 이 이벤트 소스 매핑과 연결할 태그를 입력합니다.

1. 트리거를 생성하려면 **추가**를 선택합니다.

[create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 명령과 함께 AWS CLI를 사용하여 이벤트 소스 매핑을 생성할 수도 있습니다. 다음 예시에서는 `LATEST` 메시지부터 시작하여 Lambda 함수 `my-msk-function`을 `AWSKafkaTopic` 주제에 매핑하는 이벤트 소스 매핑을 생성합니다. 또한 이 명령은 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 객체를 사용하여 클러스터에 연결할 때 [SASL/SCRAM](msk-cluster-auth.md#msk-sasl-scram) 인증을 사용하도록 Lambda에 지시합니다.

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:cluster/my-cluster/fc2f5bdf-fd1b-45ad-85dd-15b4a5a6247e-2 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function
  --source-access-configurations '[{"Type": "SASL_SCRAM_512_AUTH","URI": "arn:aws:secretsmanager:us-east-1:111122223333:secret:my-secret"}]'
```

클러스터가 [mTLS authentication](msk-cluster-auth.md#msk-mtls)을 사용하는 경우 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 객체를 포함하며 이는 `CLIENT_CERTIFICATE_TLS_AUTH` 및 Secrets Manager 키 ARN을 지정합니다. 다음 명령을 참조하세요.

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:cluster/my-cluster/fc2f5bdf-fd1b-45ad-85dd-15b4a5a6247e-2 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function
  --source-access-configurations '[{"Type": "CLIENT_CERTIFICATE_TLS_AUTH","URI": "arn:aws:secretsmanager:us-east-1:111122223333:secret:my-secret"}]'
```

클러스터가 [IAM 인증](msk-cluster-auth.md#msk-iam-auth)을 사용하는 경우 [ SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 객체가 필요하지 않습니다. 다음 명령을 참조하세요.

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:cluster/my-cluster/fc2f5bdf-fd1b-45ad-85dd-15b4a5a6247e-2 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function
```

# Lambda에서 교차 계정 이벤트 소스 매핑 생성
<a name="msk-cross-account"></a>

[다중 VPC 프라이빗 연결](https://docs.aws.amazon.com/msk/latest/developerguide/aws-access-mult-vpc.html)을 사용하여 Lambda 함수를 다른 AWS 계정의 클러스터에 프로비저닝된 MSK 클러스터에 연결할 수 있습니다. 다중 VPC 연결은 AWS PrivateLink를 사용하며, 이는 모든 트래픽을 AWS 네트워크 내에 유지합니다.

**참고**  
서버리스 MSK 클러스터에는 계정 간 이벤트 소스 매핑을 생성할 수 없습니다.

계정 간 이벤트 소스 매핑을 생성하려면 먼저 [MSK 클러스터의 다중 VPC 연결을 구성](https://docs.aws.amazon.com/msk/latest/developerguide/aws-access-mult-vpc.html#mvpc-cluster-owner-action-turn-on)해야 합니다. 이벤트 소스 매핑을 생성할 때는 다음 예에서 표시된 것처럼 클러스터 ARN 대신 관리형 VPC 연결 ARN을 사용합니다. [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 작업도 MSK 클러스터가 사용하는 인증 유형에 따라 달라집니다.

**Example — IAM 인증을 사용하는 클러스터의 계정 간 이벤트 소스 매핑 생성**  
클러스터가 [IAM 역할 기반 인증](msk-cluster-auth.md#msk-iam-auth)을 사용하는 경우 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 객체가 필요하지 않습니다. 예제:  

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:vpc-connection/444455556666/my-cluster-name/51jn98b4-0a61-46cc-b0a6-61g9a3d797d5-7 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function
```

**Example — SASL/SCRAM 인증을 사용하는 클러스터의 계정 간 이벤트 소스 매핑 생성**  
클러스터가 [SASL/SCRAM 인증](msk-cluster-auth.md#msk-sasl-scram)을 사용하는 경우 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 객체를 포함하며 이는 `SASL_SCRAM_512_AUTH` 및 Secrets Manager 비밀 ARN을 지정합니다.  
SASL/SCRAM 인증을 통한 계정 간 Amazon MSK 이벤트 소스 매핑에 암호를 사용하는 방법에는 두 가지가 있습니다.  
+ Lambda 함수 계정에서 시크릿을 생성하고 클러스터 암호와 동기화합니다. [로테이션을 생성](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html)하여 두 암호가 동기화된 상태를 유지합니다. 이 옵션을 사용하면 함수 계정에서 시크릿을 제어할 수 있습니다.
+ MSK 클러스터와 연결된 암호를 사용합니다. 이 암호는 Lambda 함수 계정에 대한 교차 계정 액세스를 허용해야 합니다. 자세한 내용은 [다른 계정에 있는 사용자의 AWS Secrets Manager 암호에 대한 권한](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_examples_cross.html)을 참조하세요.

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:vpc-connection/444455556666/my-cluster-name/51jn98b4-0a61-46cc-b0a6-61g9a3d797d5-7 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function \
  --source-access-configurations '[{"Type": "SASL_SCRAM_512_AUTH","URI": "arn:aws:secretsmanager:us-east-1:444455556666:secret:my-secret"}]'
```

**Example — mTLS 인증을 사용하는 클러스터의 계정 간 이벤트 소스 매핑 생성**  
클러스터가 [mTLS](msk-cluster-auth.md#msk-mtls)을 사용하는 경우 [SourceAccessConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_SourceAccessConfiguration.html) 객체를 포함하며 이는 `CLIENT_CERTIFICATE_TLS_AUTH` 및 Secrets Manager 비밀 ARN을 지정합니다. 암호는 클러스터 계정 또는 Lambda 함수 계정에 저장할 수 있습니다.  

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:vpc-connection/444455556666/my-cluster-name/51jn98b4-0a61-46cc-b0a6-61g9a3d797d5-7 \
  --topics AWSKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function \
  --source-access-configurations '[{"Type": "CLIENT_CERTIFICATE_TLS_AUTH","URI": "arn:aws:secretsmanager:us-east-1:444455556666:secret:my-secret"}]'
```

# Lambda에서의 모든 Amazon MSK 이벤트 소스 구성 파라미터
<a name="msk-esm-parameters"></a>

모든 Lambda 이벤트 소스 유형은 동일한 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 및 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 작업을 공유합니다. 그러나 다음 표와 같이 일부 파라미터만 Amazon MSK에 적용됩니다.


| 파라미터 | 필수 | 기본값 | 참고 | 
| --- | --- | --- | --- | 
|  AmazonManagedKafkaEventSourceConfig  |  N  |  기본적으로 고유한 값으로 설정되는 소비자 그룹 ID 필드를 포함합니다.  |  생성 시에만 설정할 수 있음  | 
|  BatchSize  |  N  |  100  |  최대값: 10,000  | 
|  DestinationConfig  |  N  |  해당 사항 없음  |  [Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스에 대한 폐기된 배치 캡처](kafka-on-failure.md)  | 
|  활성  |  N  |  True  |    | 
|  BisectBatchOnFunctionError  |  N  |  False  |  [Kafka 이벤트 소스의 오류 처리 제어 구성](kafka-retry-configurations.md)  | 
|  FunctionResponseTypes  |  N  |  해당 사항 없음  |  [Kafka 이벤트 소스의 오류 처리 제어 구성](kafka-retry-configurations.md)  | 
|  MaximumRecordAgeInSeconds  |  N  |  -1(무제한)  |  [Kafka 이벤트 소스의 오류 처리 제어 구성](kafka-retry-configurations.md)  | 
|  MaximumRetryAttempts  |  N  |  -1(무제한)  |  [Kafka 이벤트 소스의 오류 처리 제어 구성](kafka-retry-configurations.md)  | 
|  EventSourceArn  |  Y  | 해당 사항 없음 |  생성 시에만 설정할 수 있음  | 
|  FilterCriteria  |  N  |  해당 사항 없음  |  [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)  | 
|  FunctionName  |  Y  |  해당 사항 없음  |    | 
|  KMSKeyArn  |  N  |  해당 사항 없음  |  [필터 기준 암호화](invocation-eventfiltering.md#filter-criteria-encryption)  | 
|  MaximumBatchingWindowInSeconds  |  N  |  500ms  |  [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)  | 
|  ProvisionedPollersConfig  |  N  |  `MinimumPollers`: 지정하지 않은 경우 기본값(1) `MaximumPollers`: 지정하지 않은 경우 기본값(200) `PollerGroupName`: 해당 사항 없음  |  [프로비저닝된 모드](kafka-scaling-modes.md#kafka-provisioned-mode)  | 
|  SourceAccessConfigurations  |  N  |  자격 증명 없음  |  이벤트 소스에 대한 CLIENT\$1CERTIFICATE\$1TLS\$1AUTH(MutualTLS) 또는 SASL/SCRAM  | 
|  StartingPosition  |  Y  | 해당 사항 없음 |  AT\$1TIMESTAMP, TRIM\$1HORIZON, 또는 LATEST 생성 시에만 설정할 수 있음  | 
|  StartingPositionTimestamp  |  N  |  해당 사항 없음  |  StartingPosition이 AT\$1TIMESTAMP로 설정된 경우에만 필요합니다.  | 
|  Tags  |  N  |  해당 사항 없음  |  [이벤트 소스 매핑에 태그 사용](tags-esm.md)  | 
|  주제  |  Y  | 해당 사항 없음 |  Kafka 주제 이름 생성 시에만 설정할 수 있음  | 

**참고**  
`PollerGroupName`을 지정하면 동일한 Amazon VPC 내의 여러 ESM이 이벤트 폴러 단위(EPU) 용량을 공유할 수 있습니다. 이 옵션을 사용하면 ESM의 프로비저닝된 모드 비용을 최적화할 수 있습니다. ESM 그룹화 요구 사항:  
ESM이 동일한 Amazon VPC 내에 위치
폴러 그룹당 최대 100개의 ESM
그룹 내 모든 ESM의 최대 폴러 합계가 2,000을 초과할 수 없음
`PollerGroupName`을 업데이트하여 ESM을 다른 그룹으로 이동하거나 `PollerGroupName`을 빈 문자열("")로 설정하여 그룹에서 ESM을 제거할 수 있습니다.

# 자습서: Amazon MSK 이벤트 소스 매핑을 사용하여 간접적으로 Lambda 함수 간접 호출
<a name="services-msk-tutorial"></a>

이 자습서에서는 다음을 수행합니다.
+ 기존 Amazon MSK 클러스터와 동일한 AWS 계정에서 Lambda 함수를 생성합니다.
+ Lambda가 Amazon MSK와 통신할 수 있도록 네트워킹과 인증을 구성합니다.
+ 주제에 이벤트가 표시될 때 Lambda 함수를 실행하는 Lambda Amazon MSK 이벤트 소스 매핑을 설정합니다.

이 단계를 완료한 후 Amazon MSK로 이벤트가 전송되면 사용자 지정 Lambda 코드를 사용하여 해당 이벤트를 자동으로 처리하도록 Lambda 함수를 설정할 수 있습니다.

 **이 기능으로 무엇을 할 수 있나요?**

**예제 솔루션: MSK 이벤트 소스 매핑을 사용하여 고객에게 실시간 점수를 제공하세요.**

다음 시나리오를 생각해 보세요. 회사에서 고객이 스포츠 경기와 같은 실시간 이벤트에 대한 정보를 볼 수 있는 웹 애플리케이션을 호스팅하고 있습니다. 게임의 정보 업데이트는 Amazon MSK의 Kafka 주제를 통해 팀에 제공됩니다. 개발하는 애플리케이션 내에서 고객에게 라이브 이벤트의 업데이트된 보기를 제공하기 위해 MSK 주제의 업데이트를 사용하는 솔루션을 설계하려고 합니다. 다음과 같은 설계 접근 방식을 결정했습니다. 클라이언트 애플리케이션은 AWS에서 호스팅되는 서버리스 백엔드와 통신합니다. 클라이언트는 Amazon API Gateway WebSocket API를 사용하여 WebSocket 세션을 통해 연결됩니다.

이 솔루션에서는 MSK 이벤트를 읽고 일부 사용자 지정 로직을 수행하여 애플리케이션 계층에 맞게 해당 이벤트를 준비한 다음 해당 정보를 API Gateway API로 전달하는 구성 요소가 필요합니다. Lambda 함수에 사용자 지정 로직을 제공한 다음 AWS Lambda Amazon MSK 이벤트 소스 매핑을 통해 직접적으로 호출하여 AWS Lambda로 이 구성 요소를 구현할 수 있습니다.

Amazon API Gateway WebSocket API를 사용하여 솔루션을 구현하는 방법에 대한 자세한 내용은 API Gateway 설명서의 [WebSocket API 자습서](https://docs.aws.amazon.com/apigateway/latest/developerguide/websocket-api-chat-app.html)를 참조하세요.

## 사전 조건
<a name="w2aad101c23c15c35c19"></a>

다음과 같은 사전 구성된 리소스가 있는 AWS 계정:

**이러한 사전 요구 사항을 충족하려면 Amazon MSK 설명서의 [Getting started using Amazon MSK](https://docs.aws.amazon.com//msk/latest/developerguide/getting-started.html)를 따르는 것이 좋습니다.**
+ Amazon MSK 클러스터. *Getting started using Amazon MSK*의 [Create an Amazon MSK cluster](https://docs.aws.amazon.com//msk/latest/developerguide/create-cluster.html)를 참조하세요.
+ 다음 구성:
  + 클러스터 보안 설정에서 **IAM 역할 기반 인증**이 **활성화됨**인지 확인합니다. 이렇게 하면 필요한 Amazon MSK 리소스에만 액세스하도록 Lambda 함수를 제한하여 보안이 강화됩니다. 이는 새 Amazon MSK 클러스터에서 기본적으로 활성화됩니다.
  + 클러스터 네트워킹 설정에서 **퍼블릭 액세스**가 꺼져 있는지 확인합니다. Amazon MSK 클러스터의 인터넷 액세스를 제한하면 데이터를 처리하는 중개자 수가 제한되어 보안이 강화됩니다. 이는 새 Amazon MSK 클러스터에서 기본적으로 활성화됩니다.
+ 이 솔루션에 사용할 Amazon MSK 클러스터의 Kafka 주제. **Getting started using Amazon MSK의 [Create a topic](https://docs.aws.amazon.com//msk/latest/developerguide/create-topic.html)을 참조하세요.
+ Kafka 클러스터에서 정보를 검색하고 테스트를 위해 Kafka 이벤트를 주제에 전송하도록 설정된 Kafka 관리자 호스트(예: Kafka 관리 CLI와 Amazon MSK IAM 라이브러리가 설치된 Amazon EC2 인스턴스). **Getting started using Amazon MSK의 [Create a client machine](https://docs.aws.amazon.com//msk/latest/developerguide/create-client-machine.html)을 참조하세요.

이러한 리소스를 설정한 후에는 AWS 계정에서 다음 정보를 수집하여 계속할 준비가 되었는지 확인하세요.
+ Amazon MSK 클러스터의 이름. 이 정보는 Amazon MSK 콘솔에서 확인할 수 있습니다.
+ Amazon MSK 클러스터용 ARN의 일부인 클러스터 UUID(Amazon MSK 콘솔에서 찾을 수 있음). 이 정보를 찾으려면 Amazon MSK 설명서의 [Listing clusters](https://docs.aws.amazon.com/msk/latest/developerguide/msk-list-clusters.html)에 나와 있는 절차를 따르세요.
+ Amazon MSK 클러스터와 연결된 보안 그룹. 이 정보는 Amazon MSK 콘솔에서 확인할 수 있습니다. 다음 단계에서는 이를 *clusterSecurityGroups*라고 합니다.
+ Amazon MSK 클러스터를 포함하는 Amazon VPC의 ID. Amazon MSK 콘솔에서 Amazon MSK 클러스터와 연결된 서브넷을 식별한 다음 Amazon VPC 콘솔에서 해당 서브넷과 연결된 Amazon VPC를 식별하여 이 정보를 찾을 수 있습니다.
+ 솔루션에 사용되는 Kafka 주제의 이름. Kafka 관리 호스트에서 Kafka `topics` CLI로 Amazon MSK 클러스터를 직접적으로 호출하여 이 정보를 찾을 수 있습니다. 주제 CLI에 대한 자세한 내용은 Kafka 설명서의 [Adding and removing topics](https://kafka.apache.org/documentation/#basic_ops_add_topic)를 참조하세요.
+ Lambda 함수에서 사용하기에 적합한 Kafka 주제에 대한 소비자 그룹의 이름. 이 그룹은 Lambda에서 자동으로 생성할 수 있으므로 Kafka CLI를 사용하여 생성할 필요가 없습니다. 소비자 그룹을 관리해야 하는 경우 소비자 그룹 CLI에 대한 자세한 내용은 Kafka 설명서의 [Managing Consumer Groups](https://kafka.apache.org/documentation/#basic_ops_consumer_group)를 참조하세요.

AWS 계정의 다음 권한:
+ Lambda 함수를 생성하고 관리할 수 있는 권한
+ IAM 정책을 생성하고 Lambda 함수와 연결할 수 있는 권한
+ Amazon MSK 클러스터를 호스팅하는 Amazon VPC에서 Amazon VPC 엔드포인트를 생성하고 네트워킹 구성을 변경할 수 있는 권한

### AWS Command Line Interface 설치
<a name="install_aws_cli"></a>

아직 AWS Command Line Interface를 설치하지 않은 경우 [AWS CLI의 최신 버전 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)에서 설명하는 단계에 따라 설치하세요.

이 자습서에서는 명령을 실행할 셸 또는 명령줄 터미널이 필요합니다. Linux 및 macOS에서는 선호하는 셸과 패키지 관리자를 사용합니다.

**참고**  
Windows에서는 Lambda와 함께 일반적으로 사용하는 일부 Bash CLI 명령(예:`zip`)은 운영 체제의 기본 제공 터미널에서 지원되지 않습니다. Ubuntu와 Bash의 Windows 통합 버전을 가져오려면 [Linux용 Windows Subsystem을 설치](https://docs.microsoft.com/en-us/windows/wsl/install-win10)합니다.

## Lambda가 Amazon MSK와 통신할 수 있도록 네트워크 연결 구성
<a name="w2aad101c23c15c35c21"></a>

 AWS PrivateLink를 사용하여 Lambda와 Amazon MSK를 연결합니다. 이를 위해 Amazon VPC 콘솔에서 인터페이스 Amazon VPC 엔드포인트를 생성할 수 있습니다. 네트워크 구성에 대한 자세한 내용은 [Lambda를 위한 Amazon MSK 클러스터 및 Amazon VPC 네트워크 구성](with-msk-cluster-network.md) 섹션을 참조하세요.

Amazon MSK 이벤트 소스 매핑이 Lambda 함수를 대신하여 실행되는 경우 Lambda 함수의 실행 역할을 수임합니다. 이 IAM 역할은 Amazon MSK 클러스터와 같이 IAM으로 보호되는 리소스에 액세스할 수 있도록 매핑 권한을 부여합니다. 구성 요소는 실행 역할을 공유하지만 다음 다이어그램과 같이 Amazon MSK 매핑과 Lambda 함수에는 해당 작업에 대한 별도의 연결 요구 사항이 있습니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/msk_tut_network.png)


이벤트 소스 매핑은 Amazon MSK 클러스터 보안 그룹에 속합니다. 이 네트워킹 단계에서는 Amazon MSK 클러스터 VPC에서 Amazon VPC 엔드포인트를 생성하여 Lambda 및 STS 서비스에 이벤트 소스 매핑을 연결합니다. 이러한 엔드포인트를 보호하여 Amazon MSK 클러스터 보안 그룹의 트래픽을 허용하세요. 그런 다음 Amazon MSK 클러스터 보안 그룹을 조정하여 이벤트 소스 매핑이 Amazon MSK 클러스터와 통신할 수 있도록 합니다.

 AWS Management Console을 사용하여 다음 단계를 구성할 수 있습니다.

**Lambda와 Amazon MSK를 연결하도록 인터페이스 Amazon VPC 엔드포인트를 구성하려면 다음을 수행하세요.**

1. 443에서 *clusterSecurityGroups*의 인바운드 TCP 트래픽을 허용하는 인터페이스 Amazon VPC 엔드포인트에 대한 보안 그룹인 *endpointSecurityGroup*을 생성합니다. Amazon EC2 설명서의 [보안 그룹 생성](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/working-with-security-groups.html#creating-security-group)에 나와 있는 절차에 따라 보안 그룹을 생성합니다. 그런 다음 Amazon EC2 설명서의 [보안 그룹에 규칙 추가](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/working-with-security-groups.html#adding-security-group-rule) 절차에 따라 적절한 규칙을 추가합니다.

   **다음 정보로 보안 그룹 생성:**

   인바운드 규칙을 추가할 때 *clusterSecurityGroups*에서 각 보안 그룹에 대한 규칙을 생성합니다. 각 규칙에 대해 다음을 수행합니다.
   + **타입**에 대해 **HTTPS**를 선택합니다.
   + **소스**로 *clusterSecurityGroups* 중 하나를 선택합니다.

1.  Amazon MSK 클러스터가 포함된 Amazon VPC에 Lambda 서비스를 연결하는 엔드포인트를 생성합니다. [인터페이스 엔드포인트 생성](https://docs.aws.amazon.com//vpc/latest/privatelink/create-interface-endpoint.html) 절차를 따릅니다.

   **다음 정보로 인터페이스 엔드포인트 생성:**
   + **서비스 이름**으로 `com.amazonaws.regionName.lambda`를 선택합니다. 여기서 *regionName*은 Lambda 함수를 호스팅합니다.
   + **VPC**로 Amazon MSK 클러스터가 포함된 Amazon VPC를 선택합니다.
   + **보안 그룹**으로 앞에서 생성한 *endpointSecurityGroup*을 선택합니다.
   + **서브넷**으로 Amazon MSK 클러스터를 호스팅하는 서브넷을 선택합니다.
   + **정책**으로 Lambda 서비스 주체가 `lambda:InvokeFunction` 작업에 사용할 엔드포인트를 보호하는 다음 정책 문서를 제공합니다.

     ```
     {
         "Statement": [
             {
                 "Action": "lambda:InvokeFunction",
                 "Effect": "Allow",
                 "Principal": {
                     "Service": [
                         "lambda.amazonaws.com"
                     ]
                 },
                 "Resource": "*"
             }
         ]
     }
     ```
   + **DNS 이름 활성화**가 설정된 상태로 유지되는지 확인합니다.

1.  Amazon MSK 클러스터가 포함된 Amazon VPC에 AWS STS 서비스를 연결하는 엔드포인트를 생성합니다. [인터페이스 엔드포인트 생성](https://docs.aws.amazon.com//vpc/latest/privatelink/create-interface-endpoint.html) 절차를 따릅니다.

   **다음 정보로 인터페이스 엔드포인트 생성:**
   + **서비스 이름**에서 AWS STS를 선택합니다.
   + **VPC**로 Amazon MSK 클러스터가 포함된 Amazon VPC를 선택합니다.
   + **보안 그룹**으로 *endpointSecurityGroup*을 선택합니다.
   + **서브넷**으로 Amazon MSK 클러스터를 호스팅하는 서브넷을 선택합니다.
   + **정책**으로 Lambda 서비스 주체가 `sts:AssumeRole` 작업에 사용할 엔드포인트를 보호하는 다음 정책 문서를 제공합니다.

     ```
     {
         "Statement": [
             {
                 "Action": "sts:AssumeRole",
                 "Effect": "Allow",
                 "Principal": {
                     "Service": [
                         "lambda.amazonaws.com"
                     ]
                 },
                 "Resource": "*"
             }
         ]
     }
     ```
   + **DNS 이름 활성화**가 설정된 상태로 유지되는지 확인합니다.

1. Amazon MSK 클러스터와 연결된 각 보안 그룹, 즉 *clusterSecurityGroups*에 대해 다음을 허용합니다.
   + 9098의 모든 인바운드 및 아웃바운드 TCP 트래픽을 자체 내부를 포함하여 모든 *clusterSecurityGroups*에 허용합니다.
   + 443에서 모든 아웃바운드 TCP 트래픽을 허용합니다.

   이 트래픽 중 일부는 기본 보안 그룹 규칙에 의해 허용되므로 클러스터가 단일 보안 그룹에 연결되어 있고 해당 그룹에 기본 규칙이 있는 경우 추가 규칙이 필요하지 않습니다. 보안 그룹 규칙을 조정하려면 Amazon EC2 설명서의 [보안 그룹에 규칙 추가](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/working-with-security-groups.html#adding-security-group-rule) 절차를 따릅니다.

   **다음 정보로 보안 그룹에 규칙 추가**
   + 포트 9098에 대한 각 인바운드 규칙 또는 아웃바운드 규칙에 대해 다음을 제공합니다.
     + **유형**에서 **Custom TCP(사용자 지정 TCP)**를 선택합니다.
     + **포트 범위**에 9098을 입력합니다.
     + **소스**로 *clusterSecurityGroups* 중 하나를 제공합니다.
   + 포트 443에 대한 각 인바운드 규칙에 대해 **유형**으로 **HTTPS**를 선택합니다.

## Lambda가 Amazon MSK 주제에서 읽을 수 있도록 IAM 역할 생성
<a name="w2aad101c23c15c35c23"></a>

Lambda가 Amazon MSK 주제에서 읽기 위한 인증 요구 사항을 파악한 다음 정책에서 정의합니다. Lambda가 이러한 권한을 사용할 수 있도록 승인하는 역할인 *lambdaAuthRole*을 생성합니다. `kafka-cluster` IAM 작업을 사용하여 Amazon MSK 클러스터에서 작업 권한을 부여합니다. 그런 다음, Lambda가 Amazon MSK 클러스터를 검색하고 연결하는 데 필요한 Amazon MSK `kafka` 및 Amazon EC2 작업을 수행하도록 권한을 부여하고, Lambda가 수행한 작업을 기록할 수 있도록 CloudWatch 작업을 수행하도록 권한을 부여합니다.

**Lambda가 Amazon MSK에서 읽기 위한 인증 요구 사항을 설명하려면 다음을 수행하세요.**

1. Lambda가 Kafka 소비자 그룹을 사용하여 Amazon MSK 클러스터의 Kafka 주제에서 읽을 수 있도록 허용하는 IAM 정책 문서(JSON 문서)인 *clusterAuthPolicy*를 작성합니다. Lambda는 읽을 때 Kafka 소비자 그룹을 설정해야 합니다.

   사전 요구 사항에 맞게 다음 템플릿 변경

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "kafka-cluster:Connect",
                   "kafka-cluster:DescribeGroup",
                   "kafka-cluster:AlterGroup",
                   "kafka-cluster:DescribeTopic",
                   "kafka-cluster:ReadData",
                   "kafka-cluster:DescribeClusterDynamicConfiguration"
               ],
               "Resource": [
                   "arn:aws:kafka:us-east-1:111122223333:cluster/mskClusterName/cluster-uuid",
                   "arn:aws:kafka:us-east-1:111122223333:topic/mskClusterName/cluster-uuid/mskTopicName",
                   "arn:aws:kafka:us-east-1:111122223333:group/mskClusterName/cluster-uuid/mskGroupName"
               ]
           }
       ]
   }
   ```

------

   자세한 내용은 [Amazon MSK 이벤트 소스 매핑에 대한 Lambda 권한 구성](with-msk-permissions.md)을 참조하세요. 정책을 작성할 때
   + *us-east-1* 및 *111122223333*를 Amazon MSK 클러스터의 AWS 리전 및 AWS 계정으로 변경합니다.
   + *mskClusterName*으로 Amazon MSK 클러스터의 이름을 제공합니다.
   + *cluster-uuid*로 Amazon MSK 클러스터의 ARN에 UUID를 제공합니다.
   + *mskTopicName*으로 Kafka 주제의 이름을 제공합니다.
   + *mskGroupName*으로 Kafka 소비자 그룹의 이름을 제공합니다.

1. Lambda가 Amazon MSK 클러스터를 검색 및 연결하고 해당 이벤트를 기록하는 데 필요한 Amazon MSK, Amazon EC2 및 CloudWatch 권한을 식별합니다.

   `AWSLambdaMSKExecutionRole` 관리형 정책은 필요한 권한을 허용적으로 정의합니다. 다음 단계에서 사용합니다.

   프로덕션 환경에서는 `AWSLambdaMSKExecutionRole`을 평가하여 최소 권한 원칙에 따라 실행 역할 정책을 제한한 다음 이 관리형 정책을 대체하는 역할에 대한 정책을 작성합니다.

IAM 정책 언어에 대한 자세한 내용은 [IAM 설명서](https://docs.aws.amazon.com//iam/)를 참조하세요.

정책 문서를 작성했으니 이제 IAM 정책을 생성하여 역할에 연결할 수 있습니다. 다음 절차에 따라 콘솔을 사용하여 이 작업을 수행할 수 있습니다.

**정책 문서에서 IAM 정책을 생성하려면 다음을 수행하세요.**

1. AWS Management Console에 로그인하여 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)에서 IAM 콘솔을 엽니다.

1. 왼쪽의 탐색 창에서 **정책**을 선택합니다.

1. **정책 생성**을 선택합니다.

1. **정책 편집기** 섹션에서 **JSON** 옵션을 선택합니다.

1. *clusterAuthPolicy*를 붙여넣습니다.

1. 정책에 권한 추가를 완료했으면 **다음**을 선택합니다.

1. **검토 및 생성** 페이지에서 생성하는 정책에 대한 **정책 이름**과 **설명**(선택 사항)을 입력합니다. **이 정책에 정의된 권한**을 검토하여 정책이 부여한 권한을 확인합니다.

1. **정책 생성**을 선택하고 새로운 정책을 저장합니다.

자세한 내용은 IAM 설명서의 [IAM 정책 생성](https://docs.aws.amazon.com//IAM/latest/UserGuide/access_policies_create.html)을 참조하세요.

이제 적절한 IAM 정책이 있으므로 역할을 생성하고 이에 IAM 정책을 연결합니다. 다음 절차에 따라 콘솔을 사용하여 이 작업을 수행할 수 있습니다.

**IAM 콘솔에서 실행 역할을 생성하려면**

1. IAM 콘솔에서 [역할(Roles)](https://console.aws.amazon.com/iam/home#/roles) 페이지를 엽니다.

1. **역할 생성**을 선택합니다.

1. **신뢰할 수 있는 엔터티 유형**에서 **AWS 서비스**를 선택합니다.

1. **사용 사례**에서 **Lambda**를 선택합니다.

1. **다음**을 선택합니다.

1. 다음 정책을 선택합니다.
   + *clusterAuthPolicy*
   + `AWSLambdaMSKExecutionRole`

1. **다음**을 선택합니다.

1. **역할 이름**에 *lambdaAuthRole*을 입력한 다음 **역할 생성**을 선택합니다.

자세한 내용은 [실행 역할로 Lambda 함수 권한 정의](lambda-intro-execution-role.md) 섹션을 참조하세요.

## Amazon MSK 주제에서 읽을 Lambda 함수 생성
<a name="w2aad101c23c15c35c25"></a>

IAM 역할을 사용하도록 구성된 Lambda 함수를 생성합니다. 콘솔을 사용하여 Lambda 함수를 생성할 수 있습니다.

**인증 구성을 사용하여 Lambda 함수를 생성하려면 다음을 수행하세요.**

1.  Lambda 콘솔을 열고 헤더에서 **함수 생성**을 선택합니다.

1. **새로 작성**을 선택합니다.

1. **함수 이름**으로 원하는 적절한 이름을 제공합니다.

1. **런타임**으로 이 자습서에 제공된 코드를 사용하려면 **지원되는 최신** 버전의 `Node.js`를 선택합니다.

1. **기본 실행 역할 변경**을 선택합니다.

1. **기존 역할 사용**을 선택합니다.

1. **기존 역할**로 *lambdaAuthRole*을 선택합니다.

프로덕션 환경에서는 일반적으로 Amazon MSK 이벤트를 의미 있게 처리하기 위해 Lambda 함수의 실행 역할에 추가 정책을 추가해야 합니다. 역할에 정책을 추가하는 방법에 대한 자세한 내용은 IAM 설명서의 [ID 권한 추가 또는 제거](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#add-policies-console)를 참조하세요.

## Lambda 함수에 대한 이벤트 소스 매핑 생성
<a name="w2aad101c23c15c35c27"></a>

Amazon MSK 이벤트 소스 매핑은 적절한 Amazon MSK 이벤트가 발생할 때 Lambda를 간접적으로 간접 호출하는 데 필요한 정보를 Lambda 서비스에 제공합니다. 콘솔을 사용하여 Amazon MSK 매핑을 생성할 수 있습니다. Lambda 트리거를 생성하면 이벤트 소스 매핑이 자동으로 설정됩니다.

**Lambda 트리거 및 이벤트 소스 매핑을 생성하려면 다음을 수행하세요.**

1. Lambda 함수의 개요 페이지로 이동합니다.

1. 함수 개요 섹션의 왼쪽 하단에서 **트리거 추가**를 선택합니다.

1. **소스 선택** 드롭다운에서 **Amazon MSK**를 선택합니다.

1. **인증**을 설정하지 마세요.

1. **MSK 클러스터**로 클러스터의 이름을 선택합니다.

1. **배치 크기**로 1을 입력합니다. 이 단계를 수행하면 이 기능을 더 쉽게 테스트할 수 있지만 프로덕션에서는 이상적인 값이 아닙니다.

1. **주제 이름**으로 Kafka 주제의 이름을 입력합니다.

1. **소비자 그룹 ID**로 Kafka 소비자 그룹의 ID를 제공합니다.

## 스트리밍 데이터를 읽도록 Lambda 함수 업데이트
<a name="w2aad101c23c15c35c29"></a>

 Lambda는 이벤트 메서드 파라미터를 통해 Kafka 이벤트에 대한 정보를 제공합니다. Amazon MSK 이벤트의 예제 구조는 [예제 이벤트](with-msk.md#msk-sample-event) 섹션을 참조하세요. Lambda가 전달한 Amazon MSK 이벤트를 해석하는 방법을 이해한 후에는 제공된 정보를 사용하도록 Lambda 함수 코드를 변경할 수 있습니다.

 테스트 목적으로 Lambda Amazon MSK 이벤트의 내용을 기록하려면 Lambda 함수에 다음 코드를 제공하세요.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 Amazon MSK 이벤트 사용  

```
using System.Text;
using Amazon.Lambda.Core;
using Amazon.Lambda.KafkaEvents;


// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace MSKLambda;

public class Function
{
    
    
    /// <param name="input">The event for the Lambda function handler to process.</param>
    /// <param name="context">The ILambdaContext that provides methods for logging and describing the Lambda environment.</param>
    /// <returns></returns>
    public void FunctionHandler(KafkaEvent evnt, ILambdaContext context)
    {

        foreach (var record in evnt.Records)
        {
            Console.WriteLine("Key:" + record.Key); 
            foreach (var eventRecord in record.Value)
            {
                var valueBytes = eventRecord.Value.ToArray();    
                var valueText = Encoding.UTF8.GetString(valueBytes);
                
                Console.WriteLine("Message:" + valueText);
            }
        }
    }
    

}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 Amazon MSK 이벤트 사용  

```
package main

import (
	"encoding/base64"
	"fmt"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(event events.KafkaEvent) {
	for key, records := range event.Records {
		fmt.Println("Key:", key)

		for _, record := range records {
			fmt.Println("Record:", record)

			decodedValue, _ := base64.StdEncoding.DecodeString(record.Value)
			message := string(decodedValue)
			fmt.Println("Message:", message)
		}
	}
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda로 Amazon MSK 이벤트를 사용합니다.  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.KafkaEvent;
import com.amazonaws.services.lambda.runtime.events.KafkaEvent.KafkaEventRecord;

import java.util.Base64;
import java.util.Map;

public class Example implements RequestHandler<KafkaEvent, Void> {

    @Override
    public Void handleRequest(KafkaEvent event, Context context) {
        for (Map.Entry<String, java.util.List<KafkaEventRecord>> entry : event.getRecords().entrySet()) {
            String key = entry.getKey();
            System.out.println("Key: " + key);

            for (KafkaEventRecord record : entry.getValue()) {
                System.out.println("Record: " + record);

                byte[] value = Base64.getDecoder().decode(record.getValue());
                String message = new String(value);
                System.out.println("Message: " + message);
            }
        }

        return null;
    }
}
```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda로 Amazon MSK 이벤트를 사용합니다.  

```
exports.handler = async (event) => {
    // Iterate through keys
    for (let key in event.records) {
      console.log('Key: ', key)
      // Iterate through records
      event.records[key].map((record) => {
        console.log('Record: ', record)
        // Decode base64
        const msg = Buffer.from(record.value, 'base64').toString()
        console.log('Message:', msg)
      }) 
    }
}
```
TypeScript를 사용하여 Lambda로 Amazon MSK 이벤트를 사용합니다.  

```
import { MSKEvent, Context } from "aws-lambda";
import { Buffer } from "buffer";
import { Logger } from "@aws-lambda-powertools/logger";

const logger = new Logger({
  logLevel: "INFO",
  serviceName: "msk-handler-sample",
});

export const handler = async (
  event: MSKEvent,
  context: Context
): Promise<void> => {
  for (const [topic, topicRecords] of Object.entries(event.records)) {
    logger.info(`Processing key: ${topic}`);

    // Process each record in the partition
    for (const record of topicRecords) {
      try {
        // Decode the message value from base64
        const decodedMessage = Buffer.from(record.value, 'base64').toString();

        logger.info({
          message: decodedMessage
        });
      }
      catch (error) {
        logger.error('Error processing event', { error });
        throw error;
      }
    };
  }
}
```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 Amazon MSK 이벤트 사용  

```
<?php
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

// using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\Kafka\KafkaEvent;
use Bref\Event\Handler as StdHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler implements StdHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handle(mixed $event, Context $context): void
    {
        $kafkaEvent = new KafkaEvent($event);
        $this->logger->info("Processing records");
        $records = $kafkaEvent->getRecords();

        foreach ($records as $record) {
            try {
                $key = $record->getKey();
                $this->logger->info("Key: $key");

                $values = $record->getValue();
                $this->logger->info(json_encode($values));

                foreach ($values as $value) {
                    $this->logger->info("Value: $value");
                }
                
            } catch (Exception $e) {
                $this->logger->error($e->getMessage());
            }
        }
        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords records");
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 Amazon MSK 이벤트 사용  

```
import base64

def lambda_handler(event, context):
    # Iterate through keys
    for key in event['records']:
        print('Key:', key)
        # Iterate through records
        for record in event['records'][key]:
            print('Record:', record)
            # Decode base64
            msg = base64.b64decode(record['value']).decode('utf-8')
            print('Message:', msg)
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 Amazon MSK 이벤트 사용  

```
require 'base64'

def lambda_handler(event:, context:)
  # Iterate through keys
  event['records'].each do |key, records|
    puts "Key: #{key}"

    # Iterate through records
    records.each do |record|
      puts "Record: #{record}"

      # Decode base64
      msg = Base64.decode64(record['value'])
      puts "Message: #{msg}"
    end
  end
end
```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-msk-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 Amazon MSK 이벤트 사용  

```
use aws_lambda_events::event::kafka::KafkaEvent;
use lambda_runtime::{run, service_fn, tracing, Error, LambdaEvent};
use base64::prelude::*;
use serde_json::{Value};
use tracing::{info};

/// Pre-Requisites:
/// 1. Install Cargo Lambda - see https://www.cargo-lambda.info/guide/getting-started.html
/// 2. Add packages tracing, tracing-subscriber, serde_json, base64
///
/// This is the main body for the function.
/// Write your code inside it.
/// There are some code example in the following URLs:
/// - https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/examples
/// - https://github.com/aws-samples/serverless-rust-demo/

async fn function_handler(event: LambdaEvent<KafkaEvent>) -> Result<Value, Error> {

    let payload = event.payload.records;

    for (_name, records) in payload.iter() {

        for record in records {

         let record_text = record.value.as_ref().ok_or("Value is None")?;
         info!("Record: {}", &record_text);

         // perform Base64 decoding
         let record_bytes = BASE64_STANDARD.decode(record_text)?;
         let message = std::str::from_utf8(&record_bytes)?;
         
         info!("Message: {}", message);
        }

    }

    Ok(().into())
}

#[tokio::main]
async fn main() -> Result<(), Error> {

    // required to enable CloudWatch error logging by the runtime
    tracing::init_default_subscriber();
    info!("Setup CW subscriber!");

    run(service_fn(function_handler)).await
}
```

------

콘솔을 사용하여 Lambda에 함수 코드를 제공할 수 있습니다.

**콘솔 코드 편집기를 사용하여 함수 코드 업데이트**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 열고 함수를 선택합니다.

1. **코드** 탭을 선택합니다.

1. **코드 소스** 창에서 소스 코드 파일을 선택하고 통합 코드 편집기에서 편집합니다.

1. **배포** 섹션에서 **배포**를 선택하여 함수의 코드를 업데이트하세요.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

## Lambda 함수를 테스트하여 Amazon MSK 주제에 연결되어 있는지 확인합니다.
<a name="w2aad101c23c15c35c31"></a>

이제 CloudWatch 이벤트 로그를 검사하여 Lambda가 이벤트 소스에 의해 간접적으로 간접 호출되고 있는지 여부를 확인할 수 있습니다.

**Lambda 함수가 간접적으로 간접 호출되고 있는지 확인하려면 다음을 수행하세요.**

1. Kafka 관리 호스트를 사용하여 `kafka-console-producer` CLI를 통해 Kafka 이벤트를 생성합니다. 자세한 내용은 Kafka 설명서의 [Write some events into the topic](https://kafka.apache.org/documentation/#quickstart_send)을 참조하세요. 이전 단계에서 정의된 이벤트 소스 매핑에 대해 배치 크기로 정의된 배치를 채우기에 충분한 이벤트를 전송합니다. 그렇지 않으면 Lambda가 추가 정보가 간접적으로 간접 호출될 때까지 기다립니다.

1. 함수가 실행되면 Lambda는 CloudWatch에 발생한 일을 기록합니다. 콘솔에서 Lambda 함수의 세부 정보 페이지로 이동합니다.

1. [**구성(Configuration)**] 탭을 선택합니다.

1. 사이드바에서 **모니터링 및 운영 도구**를 선택합니다.

1. **로깅 구성**에서 **CloudWatch 로그 그룹**을 식별합니다. 로그 그룹은 `/aws/lambda`로 시작해야 합니다. 로그 그룹의 링크를 선택합니다.

1. CloudWatch 콘솔의 **로그 이벤트**에서 Lambda가 로그 스트림으로 전송한 로그 이벤트가 있는지 검사합니다. 다음 이미지와 같이 Kafka 이벤트의 메시지가 포함된 로그 이벤트가 있는지 확인합니다. 로그 이벤트가 있으면 Lambda 이벤트 소스 매핑을 사용하여 Lambda 함수를 Amazon MSK에 성공적으로 연결한 것입니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/msk_tut_log.png)

# 자체 관리형 Apache Kafka에서 Lambda 사용
<a name="with-kafka"></a>

이 주제에서는 자체 관리형 Kafka 클러스터에서 Lambda를 사용하는 방법을 설명합니다. AWS 용어에서 자체 관리형 클러스터는 AWS가 아닌 다른 서비스에 호스팅된 Kafka 클러스터를 포함합니다. 예를 들어, [Confluent Cloud](https://www.confluent.io/confluent-cloud/) 또는 [Redpanda](https://www.redpanda.com/)와 같은 클라우드 공급업체를 통해 Kafka 클러스터를 호스팅할 수 있습니다.

이 장에서는 자체 관리형 Apache Kafka 클러스터를 Lambda 함수의 이벤트 소스로 사용하는 방법을 설명합니다. 자체 관리형 Apache Kafka를 Lambda와 통합하는 일반적인 프로세스에는 다음 단계가 포함됩니다.

1. **[클러스터 및 네트워크 설정](with-kafka-cluster-network.md)** - 우선 Lambda가 클러스터에 액세스할 수 있도록 자체 관리형 Apache Kafka 클러스터를 적합한 네트워킹 구성으로 설정합니다.

1. **[이벤트 소스 매핑 설정](with-kafka-configure.md)** - 그런 다음 Lambda가 Apache Kafka 클러스터를 함수에 안전하게 연결하는 데 필요한 [이벤트 소스 매핑](invocation-eventsourcemapping.md) 리소스를 생성합니다.

1. **[함수 및 권한 설정](with-kafka-permissions.md)** - 마지막으로 함수가 올바르게 설정되었고 [실행 역할](lambda-intro-execution-role.md)에 필요한 권한이 있는지 확인합니다.

이벤트 소스로서 Apache Kafka는 Amazon Simple Queue Service(Amazon SQS) 또는 Amazon Kinesis를 사용하는 것과 유사하게 작동합니다. Lambda는 이벤트 소스의 새 메시지를 내부적으로 폴링한 다음 대상 Lambda 함수를 동기적으로 간접 호출합니다. Lambda는 메시지를 배치 단위로 읽고 이를 함수에 이벤트 페이로드로 제공합니다. 최대 배치 크기를 구성할 수 있습니다. 기본값은 메시지 100건입니다. 자세한 내용은 [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching) 섹션을 참조하세요.

자체 관리형 Apache Kafka 이벤트 소스 매핑의 처리량을 최적화하려면 프로비저닝된 모드를 구성합니다. 프로비저닝된 모드에서는 이벤트 소스 매핑에 할당된 최소 및 최대 이벤트 폴러 수를 정의할 수 있습니다. 그러면 예기치 않은 메시지 급증을 처리하는 이벤트 소스 매핑의 역량이 향상될 수 있습니다. 자세한 내용은 [프로비저닝된 모드](kafka-scaling-modes.md#kafka-provisioned-mode)를 참조하세요.

**주의**  
Lambda 이벤트 소스 매핑은 각 이벤트를 한 번 이상 처리하므로 레코드가 중복될 수 있습니다. 중복 이벤트와 관련된 잠재적 문제를 방지하려면 함수 코드를 멱등성으로 만드는 것이 좋습니다. 자세한 내용은 AWS 지식 센터의 [함수를 멱등성 Lambda 함수로 만들려면 어떻게 해야 하나요?](https://repost.aws/knowledge-center/lambda-function-idempotent)를 참조하세요.

Kafka 기반 이벤트 소스의 경우 Lambda는 일괄 처리 기간 및 배치 크기와 같은 처리 제어 파라미터를 지원합니다. 자세한 정보는 [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching) 섹션을 참조하세요.

자체 관리형 Kafka를 이벤트 소스로 사용하는 방법의 예는 AWS 컴퓨팅 블로그에서 [Using self-hosted Apache Kafka as an event source for AWS Lambda](https://aws.amazon.com/blogs/compute/using-self-hosted-apache-kafka-as-an-event-source-for-aws-lambda/)를 참조하세요.

**Topics**
+ [

## 예제 이벤트
](#smaa-sample-event)
+ [

# Lambda용 자체 관리형 Apache Kafka 클러스터 및 네트워크 구성
](with-kafka-cluster-network.md)
+ [

# Lambda 실행 역할 권한 구성
](with-kafka-permissions.md)
+ [

# Lambda용 자체 관리형 Apache Kafka 이벤트 소스 구성
](with-kafka-configure.md)

## 예제 이벤트
<a name="smaa-sample-event"></a>

Lambda는 Lambda 함수를 간접 호출할 때 이벤트 파라미터의 메시지 배치를 보냅니다. 이벤트 페이로드에는 메시지 배열이 포함됩니다. 각 배열 항목에는 Kafka 주제 및 Kafka 파티션 식별자에 대한 세부 정보와 함께 타임스탬프 및 base64로 인코딩된 메시지가 포함됩니다.

```
{
   "eventSource": "SelfManagedKafka",
   "bootstrapServers":"b-2.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092,b-1.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092",
   "records":{
      "mytopic-0":[
         {
            "topic":"mytopic",
            "partition":0,
            "offset":15,
            "timestamp":1545084650987,
            "timestampType":"CREATE_TIME",
            "key":"abcDEFghiJKLmnoPQRstuVWXyz1234==",
            "value":"SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
            "headers":[
               {
                  "headerKey":[
                     104,
                     101,
                     97,
                     100,
                     101,
                     114,
                     86,
                     97,
                     108,
                     117,
                     101
                  ]
               }
            ]
         }
      ]
   }
}
```

# Lambda용 자체 관리형 Apache Kafka 클러스터 및 네트워크 구성
<a name="with-kafka-cluster-network"></a>

Lambda 함수를 자체 관리형 Apache Kafka 클러스터에 연결하려면 클러스터와 클러스터가 있는 네트워크를 올바르게 구성해야 합니다. 이 페이지에서는 클러스터와 네트워크를 구성하는 방법을 설명합니다. 클러스터와 네트워크가 이미 올바르게 구성된 경우 [Lambda용 자체 관리형 Apache Kafka 이벤트 소스 구성](with-kafka-configure.md) 섹션을 참조하여 이벤트 소스 매핑을 구성합니다.

**Topics**
+ [

## 자체 관리형 Apache Kafka 클러스터 설정
](#kafka-cluster-setup)
+ [

## 네트워크 보안 구성
](#services-kafka-vpc-config)

## 자체 관리형 Apache Kafka 클러스터 설정
<a name="kafka-cluster-setup"></a>

[Confluent Cloud](https://www.confluent.io/confluent-cloud/) 또는 [Redpanda](https://www.redpanda.com/)와 같은 클라우드 공급자를 사용하여 자체 관리형 Apache Kafka 클러스터를 호스팅하거나 자체 인프라에서 실행할 수 있습니다. Lambda 이벤트 소스 매핑이 연결될 네트워크에서 클러스터가 올바르게 구성되고 액세스할 수 있는지 확인합니다.

## 네트워크 보안 구성
<a name="services-kafka-vpc-config"></a>

이벤트 소스 매핑을 통해 Lambda가 자체 관리형 Apache Kafka에 대한 전체 액세스 권한을 부여하려면 클러스터에서 퍼블릭 엔드포인트(퍼블릭 IP 주소)를 사용하거나 클러스터를 생성한 Amazon VPC에 대한 액세스 권한을 제공해야 합니다.

Lambda에서 자체 관리형 Apache Kafka를 사용하는 경우 함수에 Amazon VPC의 리소스에 대한 액세스 권한을 제공하는 [AWS PrivateLink VPC 엔드포인트](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html)를 생성합니다.

**참고**  
이벤트 폴러에 기본(온디맨드) 모드를 사용하는 이벤트 소스 매핑을 포함하는 함수에 대해 AWS PrivateLink VPC 엔드포인트가 필요합니다. 이벤트 소스 매핑에서 [프로비저닝된 모드](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)를 사용하는 경우 AWS PrivateLink VPC 엔드포인트를 구성하지 않아도 됩니다.

다음 리소스에 대한 액세스를 제공하는 엔드포인트를 생성합니다.
+  Lambda - Lambda 서비스 위탁자에 대한 엔드포인트를 생성합니다.
+  AWS STS - 서비스 위탁자가 사용자를 대신하여 역할을 맡을 수 있도록 AWS STS에 대한 엔드포인트를 생성합니다.
+  Secrets Manager - 클러스터에서 Secrets Manager를 사용하여 자격 증명을 저장하는 경우 Secrets Manager를 위한 엔드포인트를 생성합니다.

또는 Amazon VPC의 각 퍼블릭 서브넷에 NAT 게이트웨이를 구성합니다. 자세한 내용은 [VPC 연결 Lambda 함수에 대한 인터넷 액세스 활성화](configuration-vpc-internet.md) 섹션을 참조하세요.

자체 관리형 Apache Kafka에 대한 이벤트 소스 매핑을 생성하면 Lambda는 Amazon VPC에 대해 구성된 서브넷과 보안 그룹을 위한 탄력적 네트워크 인터페이스(ENI)가 이미 존재하는지 확인합니다. Lambda가 기존 ENI를 찾으면 이를 재사용하려고 시도합니다. 그렇지 않으면 Lambda가 이벤트 소스에 연결하고 함수를 간접 호출하기 위해 새 ENI를 생성합니다.

**참고**  
Lambda 함수는 항상 Lambda 서비스가 소유한 VPC 내에서 실행됩니다. 함수의 VPC 구성은 이벤트 소스 매핑에 영향을 미치지 않습니다. 이벤트 소스의 네트워킹 구성에 따라 Lambda가 이벤트 소스에 연결하는 방식이 결정됩니다.

클러스터가 포함된 Amazon VPC에 대한 보안 그룹을 구성합니다. 기본적으로 자체 관리형 Apache Kafka는 `9092` 포트를 사용합니다.
+ 인바운드 규칙 – 이벤트 소스와 연결된 보안 그룹에 대한 기본 브로커 포트의 모든 트래픽을 허용합니다. 또는 자체 참조 보안 그룹 규칙을 사용하여 동일한 보안 그룹 내의 인스턴스에서 액세스를 허용할 수 있습니다.
+ 아웃바운드 규칙 - 함수가 AWS 서비스와 통신해야 하는 경우 외부 대상에 대한 포트 `443`의 모든 트래픽을 허용합니다. 다른 AWS 서비스와 통신할 필요가 없는 경우 자체 참조 보안 그룹 규칙을 사용하여 브로커에 대한 액세스를 제한할 수도 있습니다.
+ Amazon VPC 엔드포인트 인바운드 규칙 - Amazon VPC 엔드포인트를 사용하는 경우 Amazon VPC 엔드포인트와 연결된 보안 그룹이 클러스터 보안 그룹에서 `443` 포트의 인바운드 트래픽을 허용해야 합니다.

클러스터가 인증을 사용하는 경우 Secrets Manager 엔드포인트에 대한 엔드포인트 정책을 제한할 수도 있습니다. Secrets Manager API를 직접 호출하기 위해 Lambda는 Lambda 서비스 위탁자가 아닌 함수 역할을 사용합니다.

**Example VPC 엔드포인트 정책 — Secrets Manager 엔드포인트**  

```
{
      "Statement": [
          {
              "Action": "secretsmanager:GetSecretValue",
              "Effect": "Allow",
              "Principal": {
                  "AWS": [
                      "arn:aws::iam::123456789012:role/my-role"
                  ]
              },
              "Resource": "arn:aws::secretsmanager:us-west-2:123456789012:secret:my-secret"
          }
      ]
  }
```

Amazon VPC 엔드포인트를 사용하는 경우 AWS에서는 엔드포인트의 탄력적 네트워크 인터페이스(ENI)를 사용하여 함수를 간접 호출하도록 API 직접 호출을 라우팅합니다. Lambda 서비스 위탁자는 해당 ENI를 사용하는 모든 역할과 함수에서 `lambda:InvokeFunction`을 직접 호출해야 합니다.

기본적으로 Amazon VPC 엔드포인트에는 리소스에 대한 광범위한 액세스를 허용하는 개방형 IAM 정책이 있습니다. 모범 사례는 해당 엔드포인트를 사용하여 필요한 작업을 수행하도록 이러한 정책을 제한하는 것입니다. 이벤트 소스 매핑이 Lambda 함수를 간접 호출할 수 있도록 하려면 VPC 엔드포인트 정책에서 Lambda 서비스 위탁자가 `sts:AssumeRole` 및 `lambda:InvokeFunction`을 직접 호출할 수 있도록 허용해야 합니다. 조직 내에서 발생하는 API 직접 호출만 허용하도록 VPC 엔드포인트 정책을 제한하면 이벤트 소스 매핑이 제대로 작동하지 않으므로 이 정책에는 `"Resource": "*"`가 필요합니다.

다음 예제 VPC 엔드포인트 정책은 AWS STS 및 Lambda 엔드포인트에 대해 Lambda 서비스 위탁자에 필요한 액세스 권한을 부여하는 방법을 안내합니다.

**Example VPC 엔드포인트 정책 - AWS STS 엔드포인트**  

```
{
      "Statement": [
          {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
    }
```

**Example VPC 엔드포인트 정책 - Lambda 엔드포인트**  

```
{
      "Statement": [
          {
              "Action": "lambda:InvokeFunction",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
  }
```

# Lambda 실행 역할 권한 구성
<a name="with-kafka-permissions"></a>

[자체 관리형 Kafka 클러스터에 액세스하는 것](kafka-cluster-auth.md) 외에도 Lambda 함수에는 다양한 API 작업을 수행할 수 있는 권한이 필요합니다. 함수의 [실행 역할](lambda-intro-execution-role.md)에 이러한 권한을 추가합니다. 사용자가 API 작업에 액세스해야 하는 경우 AWS Identity and Access Management(IAM) 사용자 또는 역할에 자격 증명 정책에 필요한 권한을 추가합니다.

**Topics**
+ [

## 필요한 Lambda 함수 권한
](#smaa-api-actions-required)
+ [

## 선택적 Lambda 함수 권한
](#smaa-api-actions-optional)
+ [

## 실행 역할에 권한 추가
](#smaa-permissions-add-policy)
+ [

## IAM 정책을 사용하여 사용자에게 액세스 권한 부여
](#smaa-permissions-add-users)

## 필요한 Lambda 함수 권한
<a name="smaa-api-actions-required"></a>

Amazon CloudWatch Logs의 로그 그룹에 로그를 생성하고 저장하려면 Lambda 함수의 실행 역할에 다음 권한이 있어야 합니다.
+ [logs:CreateLogGroup](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html)
+ [logs:CreateLogStream](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogStream.html)
+ [logs:PutLogEvents](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html)

## 선택적 Lambda 함수 권한
<a name="smaa-api-actions-optional"></a>

Lambda 함수에 또한 다음 권한이 필요할 수 있습니다.
+ Secrets Manager 비밀 정보를 설명합니다.
+ AWS Key Management Service(AWS KMS) 고객 관리형 키에 액세스합니다.
+ Amazon VPC에 액세스합니다.
+ 실패한 간접 호출 기록을 대상으로 전송합니다.

### Secrets Manager 및 AWS KMS 권한
<a name="smaa-api-actions-secrets"></a>

Kafka 브로커에 대해 구성하는 액세스 제어 유형에 따라 Lambda 함수에는 Secrets Manager 비밀 정보에 액세스하거나 AWS KMS 고객 관리형 키를 복호화할 수 있는 권한이 필요할 수 있습니다. 리소스에 액세스하려면 함수의 실행 역할에 다음 권한이 주어져야 합니다.
+ [ secretsmanager:GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html)
+ [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)

### VPC 권한
<a name="smaa-api-actions-vpc"></a>

VPC 내의 사용자만 자체 관리형 Apache Kafka 클러스터에 액세스할 수 있는 경우 Lambda 함수에 Amazon VPC 리소스에 액세스할 수 있는 권한이 있어야 합니다. 이러한 리소스에는 VPC, 서브넷, 보안 그룹 및 네트워크 인터페이스가 있습니다. 리소스에 액세스하려면 함수의 실행 역할에 다음 권한이 주어져야 합니다.
+ [ec2:CreateNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html)
+ [ec2:DescribeNetworkInterfaces](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html)
+ [ec2:DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
+ [ec2:DeleteNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkInterface.html)
+ [ec2:DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
+ [ec2:DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)

## 실행 역할에 권한 추가
<a name="smaa-permissions-add-policy"></a>

자체 관리형 Apache Kafka 클러스터가 사용하는 다른 AWS 서비스에 액세스하기 위해 Lambda는 함수의 [실행 역할](lambda-intro-execution-role.md)에 정의된 권한 정책을 사용합니다.

기본적으로 Lambda는 자체 관리형 Apache Kafka 클러스터에 대한 필수 또는 선택적 작업을 수행할 수 없습니다. 실행 역할에 대한 [IAM 신뢰 정책](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_update-role-trust-policy.html)에서 이러한 작업을 생성하고 정의해야 합니다. 이 예제에서는 Lambda가 Amazon VPC 리소스에 액세스하도록 허용하는 정책을 생성하는 방법을 보여줍니다.

------
#### [ JSON ]

****  

```
{
        "Version":"2012-10-17",		 	 	 
        "Statement":[
           {
              "Effect":"Allow",
              "Action":[
                 "ec2:CreateNetworkInterface",
                 "ec2:DescribeNetworkInterfaces",
                 "ec2:DescribeVpcs",
                 "ec2:DeleteNetworkInterface",
                 "ec2:DescribeSubnets",
                 "ec2:DescribeSecurityGroups"
              ],
              "Resource":"*"
           }
        ]
     }
```

------

## IAM 정책을 사용하여 사용자에게 액세스 권한 부여
<a name="smaa-permissions-add-users"></a>

기본적으로 사용자 및 역할에는 [이벤트 소스 API 작업](invocation-eventsourcemapping.md#event-source-mapping-api)을 수행할 수 있는 권한이 없습니다. 조직 또는 계정의 사용자에게 액세스 권한을 부여하려면 자격 증명 기반 정책을 생성 혹은 업데이트합니다. 자세한 내용은 **IAM 사용 설명서의 [정책을 사용하여 AWS 리소스에 대한 액세스 제어](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_controlling.html)를 참조하세요.

일반적인 인증 및 권한 부여 오류 문제를 해결할 경우 [Kafka 이벤트 소스 매핑 오류 문제 해결](with-kafka-troubleshoot.md) 섹션을 참조하세요.

# Lambda용 자체 관리형 Apache Kafka 이벤트 소스 구성
<a name="with-kafka-configure"></a>

자체 관리형 Apache Kafka 클러스터를 Lambda 함수의 이벤트 소스로 사용하려면 두 리소스를 연결하는 [이벤트 소스 매핑](invocation-eventsourcemapping.md)을 생성합니다. 이 페이지에서는 자체 관리형 Apache Kafka에 대한 이벤트 소스 매핑을 생성하는 방법을 설명합니다.

이 페이지에서는 Kafka 클러스터와 해당 클러스터가 있는 네트워크를 이미 올바르게 구성했다고 가정합니다. 클러스터나 네트워크를 설정해야 하는 경우 [Lambda용 자체 관리형 Apache Kafka 클러스터 및 네트워크 구성](with-kafka-cluster-network.md) 섹션을 참조하세요.

**Topics**
+ [

## 자체 관리형 Apache Kafka 클러스터를 이벤트 소스로 사용
](#kafka-esm-overview)
+ [

# Lambda에서 클러스터 인증 방법 구성
](kafka-cluster-auth.md)
+ [

# 자체 관리형 Apache Kafka 이벤트 소스에 대한 Lambda 이벤트 소스 매핑 생성
](kafka-esm-create.md)
+ [

# Lambda에서의 모든 자체 관리형 Apache Kafka 이벤트 소스 구성 파라미터
](kafka-esm-parameters.md)

## 자체 관리형 Apache Kafka 클러스터를 이벤트 소스로 사용
<a name="kafka-esm-overview"></a>

Apache Kafka 또는 Amazon MSK 클러스터를 Lambda 함수의 트리거로 추가하면 해당 클러스터가 [이벤트 소스](invocation-eventsourcemapping.md)로 사용됩니다.

Lambda는 사용자가 지정한 [시작 위치](kafka-starting-positions.md)를 기반으로 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 요청에서 `Topics`로 지정한 Kafka 주제에서 이벤트 데이터를 읽습니다. 성공적인 처리 후, Kafka 토픽은 Kafka 클러스터에 커밋됩니다.

Lambda는 각 Kafka 주제 파티션에 대해 순차적으로 메시지를 읽습니다. 단일 Lambda 페이로드에는 여러 파티션의 메시지가 포함될 수 있습니다. 사용 가능한 레코드가 더 있는 경우 Lambda는 함수가 주제를 따라잡을 때까지 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 요청에서 지정한 BatchSize 값을 기반으로 배치로 레코드를 계속 처리합니다.

Lambda는 각 배치를 처리한 후 해당 배치에 있는 메시지의 오프셋을 커밋합니다. 함수가 배치의 어떤 메시지에 대해 오류를 반환하면 Lambda는 처리가 성공하거나 메시지가 만료될 때까지 전체 메시지 배치를 다시 시도합니다. 모든 재시도에 실패한 레코드를 실패 시 대상으로 전송하여 나중에 처리하도록 할 수 있습니다.

**참고**  
Lambda 함수의 최대 제한 시간은 일반적으로 15분이지만 Amazon MSK, 자체 관리형 Apache Kafka, Amazon DocumentDB, ActiveMQ 및 RabbitMQ용 Amazon MQ에 대한 이벤트 소스 매핑은 최대 제한 시간이 14분인 함수만 지원합니다.

# Lambda에서 클러스터 인증 방법 구성
<a name="kafka-cluster-auth"></a>

Lambda는 자체 관리형 Apache Kafka 클러스터를 통해 인증하는 여러 가지 방법을 지원합니다. 지원되는 인증 방법 중 하나를 사용하도록 Kafka 클러스터를 구성해야 합니다. Kafka 보안에 대한 자세한 내용은 Kafka 설명서의 [보안](http://kafka.apache.org/documentation.html#security) 섹션을 참조하세요.

## SASL/SCRAM 인증
<a name="smaa-auth-sasl"></a>

Lambda는 Transport Layer Security(TLS) 암호화(`SASL_SSL`)를 통해 Simple Authentication and Security Layer/Salted Challenge Response Authentication Mechanism(SASL/SCRAM) 인증을 지원합니다. Lambda는 암호화된 자격 증명을 전송하여 클러스터에서 인증합니다. Lambda는 일반 텍스트(`SASL_PLAINTEXT`)가 포함된 SASL/SCRAM을 지원하지 않습니다. SASL/SCRAM 인증에 관한 자세한 내용은 [RFC 5802](https://tools.ietf.org/html/rfc5802)를 참조하세요.

Lambda는 SASL/PLAIN 인증도 지원합니다. 이 메커니즘은 일반 텍스트 보안 인증을 사용하므로, 서버에 연결할 때 TLS 암호화를 사용하여 보안 인증 정보를 보호해야 합니다.

SASL 인증의 경우 로그인 자격 증명을 AWS Secrets Manager에 보안 암호로 저장합니다. Secrets Manager 사용에 대한 자세한 내용은 *AWS Secrets Manager Manager 사용 설명서*의 [AWS Secrets Manager 보안 암호 생성](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)을 참조하세요.

**중요**  
인증에 Secrets Manager를 사용하려면 Lambda 함수와 동일한 AWS 리전에 보안 암호를 저장해야 합니다.

## 상호 TLS 인증
<a name="smaa-auth-mtls"></a>

상호 TLS(mTLS)는 클라이언트와 서버 간의 양방향 인증을 제공합니다. 클라이언트는 서버가 클라이언트를 확인할 수 있도록 서버에 인증서를 보내고, 서버는 클라이언트가 서버를 확인할 수 있도록 클라이언트에 인증서를 보냅니다.

자체 관리형 Apache Kafka에서 Lambda는 클라이언트 역할을 수행합니다. 클라이언트 인증서(Secrets Manager의 비밀 정보)를 구성하여 Kafka 브로커로 Lambda를 인증합니다. 클라이언트 인증서는 서버의 신뢰 저장소에 있는 CA에서 서명해야 합니다.

Kafka 클러스터는 서버 인증서를 Lambda로 전송하여 Lambda로 Kafka 브로커를 인증합니다. 서버 인증서는 퍼블릭 CA 인증서 또는 프라이빗 CA/자체 서명 인증서일 수 있습니다. 퍼블릭 CA 인증서는 Lambda 신뢰 저장소에 있는 인증 기관(CA)에서 서명해야 합니다. 프라이빗 CA/자체 서명 인증서의 경우 서버 루트 CA 인증서(Secrets Manager의 비밀 정보로)를 구성합니다. Lambda는 루트 인증서를 사용하여 Kafka 브로커를 확인합니다.

mTLS에 대한 자세한 내용은 [이벤트 소스로 Amazon MSK에 대한 상호 TLS 인증 도입](https://aws.amazon.com/blogs/compute/introducing-mutual-tls-authentication-for-amazon-msk-as-an-event-source)을 참조하세요.

## 클라이언트 인증서 비밀 정보 구성
<a name="smaa-auth-secret"></a>

CLIENT\$1CERTIFICATE\$1TLS\$1AUTH 비밀 정보에 인증서 필드와 프라이빗 키 필드가 필요합니다. 암호화된 프라이빗 키의 경우 비밀 정보에 프라이빗 키 암호가 필요합니다. 인증서와 프라이빗 키는 모두 PEM 형식이어야 합니다.

**참고**  
Lambda는 [PBES1](https://datatracker.ietf.org/doc/html/rfc2898/#section-6.1)(PBES2가 아님) 프라이빗 키 암호화 알고리즘을 지원합니다.

인증서 필드에는 클라이언트 인증서부터 시작하여 중간 인증서가 이어지고 루트 인증서로 끝나는 인증서 목록이 포함되어야 합니다. 각 인증서는 다음 구조의 새 줄에서 시작해야 합니다.

```
-----BEGIN CERTIFICATE-----  
            <certificate contents>
-----END CERTIFICATE-----
```

Secrets Manager는 최대 65,536바이트의 보안 정보를 지원하므로 긴 인증서 체인을 위한 충분한 공간입니다.

프라이빗 키는 다음 구조의 [PKCS \$18](https://datatracker.ietf.org/doc/html/rfc5208) 형식이어야 합니다.

```
-----BEGIN PRIVATE KEY-----  
             <private key contents>
-----END PRIVATE KEY-----
```

암호화된 프라이빗 키의 경우 다음 구조를 사용합니다.

```
-----BEGIN ENCRYPTED PRIVATE KEY-----  
              <private key contents>
-----END ENCRYPTED PRIVATE KEY-----
```

다음 예제에서는 암호화된 프라이빗 키를 사용한 mTLS 인증용 비밀 정보 콘텐츠를 표시합니다. 암호화된 프라이빗 키의 경우 비밀 정보에 프라이빗 키 암호를 포함합니다.

```
{"privateKeyPassword":"testpassword",
"certificate":"-----BEGIN CERTIFICATE-----
MIIE5DCCAsygAwIBAgIRAPJdwaFaNRrytHBto0j5BA0wDQYJKoZIhvcNAQELBQAw
...
j0Lh4/+1HfgyE2KlmII36dg4IMzNjAFEBZiCRoPimO40s1cRqtFHXoal0QQbIlxk
cmUuiAii9R0=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFgjCCA2qgAwIBAgIQdjNZd6uFf9hbNC5RdfmHrzANBgkqhkiG9w0BAQsFADBb
...
rQoiowbbk5wXCheYSANQIfTZ6weQTgiCHCCbuuMKNVS95FkXm0vqVD/YpXKwA/no
c8PH3PSoAaRwMMgOSA2ALJvbRz8mpg==
-----END CERTIFICATE-----",
"privateKey":"-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFKzBVBgkqhkiG9w0BBQ0wSDAnBgkqhkiG9w0BBQwwGgQUiAFcK5hT/X7Kjmgp
...
QrSekqF+kWzmB6nAfSzgO9IaoAaytLvNgGTckWeUkWn/V0Ck+LdGUXzAC4RxZnoQ
zp2mwJn2NYB7AZ7+imp0azDZb+8YG2aUCiyqb6PnnA==
-----END ENCRYPTED PRIVATE KEY-----"
}
```

## 서버 루트 CA 인증서 비밀 정보 구성
<a name="smaa-auth-ca-cert"></a>

Kafka 브로커가 프라이빗 CA에서 서명한 인증서로 TLS 암호화를 사용하는 경우 이 비밀 정보를 생성합니다. VPC, SASL/SCRAM, SASL/PLAIN 또는 mTLS 인증에 TLS 암호화를 사용할 수 있습니다.

서버 루트 CA 인증서 비밀 정보에는 PEM 형식의 Kafka 브로커의 루트 CA 인증서가 포함된 필드가 필요합니다. 다음 예제는 비밀 정보의 구조를 보여줍니다.

```
{"certificate":"-----BEGIN CERTIFICATE-----
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dG...
-----END CERTIFICATE-----"
}
```

# 자체 관리형 Apache Kafka 이벤트 소스에 대한 Lambda 이벤트 소스 매핑 생성
<a name="kafka-esm-create"></a>

이벤트 소스 매핑을 생성하려면 Lambda 콘솔, [AWS Command Line Interface(CLI)](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 또는 [AWS SDK](https://aws.amazon.com/getting-started/tools-sdks/)를 사용할 수 있습니다.

다음 콘솔 단계에서는 자체 관리형 Apache Kafka 클러스터를 Lambda 함수의 트리거로 추가합니다. 그러면 내부적으로 이벤트 소스 매핑 리소스가 생성됩니다.

## 사전 조건
<a name="kafka-esm-prereqs"></a>
+ 자체 관리형 Apache Kafka 클러스터. Lambda는 Apache Kafka 버전 0.10.1.0 이상을 지원합니다.
+ 자체 관리형 Kafka 클러스터에서 사용하는 AWS 리소스에 액세스할 수 있는 권한이 있는 [실행 역할](lambda-intro-execution-role.md)입니다.

## 자체 관리형 Kafka 클러스터 추가(콘솔)
<a name="kafka-esm-console"></a>

다음 단계에 따라 자체 관리형 Apache Kafka 클러스터 및 Kafka 주제를 Lambda 함수의 트리거로 추가합니다.

**Lambda 함수에 Apache Kafka 트리거를 추가하려면(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

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

1. **함수 개요(Function overview)**에서 **트리거 추가(Add trigger)**를 선택합니다.

1. **트리거 구성**에서 다음을 수행합니다.

   1. **Apache Kafka** 트리거 유형을 선택합니다.

   1. **Bootstrap 서버**에는 클러스터의 Kafka 브로커 호스트 및 포트 페어 주소를 입력한 다음 **추가**를 선택합니다. 클러스터의 각 Kafka 브로커에 대해 이를 반복합니다.

   1. **주제 이름**에는 클러스터에 레코드를 저장하는 데 사용되는 Kafka 주제의 이름을 입력합니다.

   1. 프로비저닝 모드를 구성하는 경우 **최소 이벤트 폴러**의 값, **최대 이벤트 폴러**의 값, PollerGroupName 값(선택 사항)을 입력하여 동일한 이벤트 소스 VPC 내에서 여러 ESM의 그룹화를 지정합니다.

   1. (선택 사항) **배치 크기(Batch size)**에 단일 배치에서 검색할 최대 레코드 수를 입력합니다.

   1. **Batch window**에서 Lambda가 함수를 호출하기 전에 레코드를 수집하는 데 걸리는 최대 시간(초)을 입력합니다.

   1. (선택 사항) **Consumer group ID**에서 가입할 Kafka 소비자 그룹의 ID를 입력합니다.

   1. (선택 사항) **시작 위치**의 경우 최신 레코드에서 스트림 읽기를 시작하려면 **최신**을 선택하고, 사용 가능한 가장 빠른 레코드에서 시작하려면 **수평 트리밍**을 선택하고, 읽기를 시작할 타임스탬프를 지정하려면 **타임스탬프**를 선택합니다.

   1. (선택 사항) **VPC**에서 Kafka 클러스터용 Amazon VPC를 선택합니다. 그런 다음 **VPC 서브넷(VPC subnets)**과 **VPC 보안 그룹(VPC security groups)**을 선택합니다.

      VPC 내의 사용자만 브로커에 액세스하는 경우 이 설정이 필요합니다.

      

   1. (선택 사항) **인증(Authentication)**에서 **추가(Add)**를 선택한 후 다음을 수행합니다.

      1. 클러스터에 있는 Kafka 브로커의 액세스 또는 인증 프로토콜을 선택합니다.
         + Kafka 브로커가 SASL/PLAIN 인증을 사용하는 경우 **BASIC\$1AUTH**를 선택합니다.
         + 브로커가 SASL/SCRAM 인증을 사용하는 경우 **SASL\$1SCRAM** 프로토콜 중 하나를 선택합니다.
         + mTLS 인증을 구성하는 경우 **CLIENT\$1CERTIFICATE\$1TLS\$1AUTH** 프로토콜을 선택합니다.

      1. SASL/SCRAM 또는 mTLS 인증의 경우 Kafka 클러스터에 대한 자격 증명이 포함된 Secrets Manager 비밀 키를 선택합니다.

   1. (선택 사항) **암호화(Encryption)**에서 Kafka 브로커가 프라이빗 CA에서 서명한 인증서를 사용하는 경우 Kafka 브로커가 TLS 암호화에 사용하는 루트 CA 인증서가 포함된 Secrets Manager 암호를 선택합니다.

      이 설정은 SASL/SCRAM 또는 SASL/PLANE에 대한 TLS 암호화 및 mTLS 인증에 적용됩니다.

   1. 테스트를 위해 트리거를 비활성화된 상태에서 생성하려면(권장됨) **트리거 사용**을 선택 해제합니다. 또는 트리거를 즉시 사용하려면 **트리거 사용**을 선택합니다.

1. 트리거를 생성하려면 **추가**를 선택합니다.

## 자체 관리형 Kafka 클러스터 추가(AWS CLI)
<a name="kafka-esm-cli"></a>

다음 예제 AWS CLI 명령을 사용하여 Lambda 함수에 대한 자체 관리형 Apache Kafka 트리거를 생성하고 확인합니다.

### SASL/SCRAM 사용
<a name="kafka-esm-cli-create"></a>

Kafka 사용자가 인터넷을 통해 Kafka 브로커에 액세스한다면 SASL/SCRAM 인증용으로 생성한 Secrets Manager 비밀 정보를 지정합니다. 다음 예제에서는 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) AWS CLI 명령을 사용하여 `my-kafka-function`이라는 Lambda 함수를 `AWSKafkaTopic`이라는 Kafka 주제에 매핑합니다.

```
aws lambda create-event-source-mapping \ 
  --topics AWSKafkaTopic \
  --source-access-configuration Type=SASL_SCRAM_512_AUTH,URI=arn:aws:secretsmanager:us-east-1:111122223333:secret:MyBrokerSecretName \
  --function-name arn:aws:lambda:us-east-1:111122223333:function:my-kafka-function \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc3.xyz.com:9092", "abc2.xyz.com:9092"]}}'
```

### VPC 사용
<a name="kafka-esm-cli-create-vpc"></a>

VPC 내의 Kafka 사용자만 Kafka 브로커에 액세스한다면 VPC, 서브넷 및 VPC 보안 그룹을 지정해야 합니다. 다음 예제에서는 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) AWS CLI 명령을 사용하여 `my-kafka-function`이라는 Lambda 함수를 `AWSKafkaTopic`이라는 Kafka 주제에 매핑합니다.

```
aws lambda create-event-source-mapping \ 
  --topics AWSKafkaTopic \
  --source-access-configuration '[{"Type": "VPC_SUBNET", "URI": "subnet:subnet-0011001100"}, {"Type": "VPC_SUBNET", "URI": "subnet:subnet-0022002200"}, {"Type": "VPC_SECURITY_GROUP", "URI": "security_group:sg-0123456789"}]' \
  --function-name arn:aws:lambda:us-east-1:111122223333:function:my-kafka-function \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc3.xyz.com:9092", "abc2.xyz.com:9092"]}}'
```

### AWS CLI를 사용하여 상태 확인
<a name="kafka-esm-cli-view"></a>

다음 예제에서는 [get-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html) AWS CLI 명령을 사용하여 생성한 이벤트 소스 매핑의 상태를 설명합니다.

```
aws lambda get-event-source-mapping
              --uuid dh38738e-992b-343a-1077-3478934hjkfd7
```

# Lambda에서의 모든 자체 관리형 Apache Kafka 이벤트 소스 구성 파라미터
<a name="kafka-esm-parameters"></a>

모든 Lambda 이벤트 소스 유형은 동일한 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 및 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 작업을 공유합니다. 그러나 다음 표와 같이 일부 파라미터만 자체 관리형 Apache Kafka에 적용됩니다.


| 파라미터 | 필수 | 기본값 | 참고 | 
| --- | --- | --- | --- | 
|  BatchSize  |  N  |  100  |  최대값: 10,000  | 
|  DestinationConfig  |  N  |  해당 사항 없음  |  [Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스에 대한 폐기된 배치 캡처](kafka-on-failure.md)  | 
|  활성  |  N  |  True  |  | 
|  FilterCriteria  |  N  |  해당 사항 없음  |  [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)  | 
|  FunctionName  |  Y  |  해당 사항 없음  |    | 
|  KMSKeyArn  |  N  |  해당 사항 없음  |  [필터 기준 암호화](invocation-eventfiltering.md#filter-criteria-encryption)  | 
|  MaximumBatchingWindowInSeconds  |  N  |  500ms  |  [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)  | 
|  ProvisionedPollersConfig  |  N  |  `MinimumPollers`: 지정하지 않은 경우 기본값(1) `MaximumPollers`: 지정하지 않은 경우 기본값(200) `PollerGroupName`: 해당 사항 없음  |  [프로비저닝된 모드](kafka-scaling-modes.md#kafka-provisioned-mode)  | 
|  SelfManagedEventSource  |  Y  | 해당 사항 없음 |  Kafka 브로커의 목록. 생성 시에만 설정할 수 있음  | 
|  SelfManagedKafkaEventSourceConfig  |  N  |  기본적으로 고유한 값으로 설정되는 소비자 그룹 ID 필드를 포함합니다.  |  생성 시에만 설정할 수 있음  | 
|  SourceAccessConfigurations  |  N  |  자격 증명 없음  |  클러스터에 대한 VPC 정보 또는 인증 자격 증명   SASL\$1PLAIN의 경우 BASIC\$1AUTH로 설정  | 
|  StartingPosition  |  Y  |  해당 사항 없음  |  AT\$1TIMESTAMP, TRIM\$1HORIZON, 또는 LATEST 생성 시에만 설정할 수 있음  | 
|  StartingPositionTimestamp  |  N  |  해당 사항 없음  |  StartingPosition이 AT\$1TIMESTAMP로 설정된 경우에만 필요합니다.  | 
|  Tags  |  N  |  해당 사항 없음  |  [이벤트 소스 매핑에 태그 사용](tags-esm.md)  | 
|  주제  |  Y  |  해당 사항 없음  |  주제 이름 생성 시에만 설정할 수 있음  | 

**참고**  
`PollerGroupName`을 지정하면 동일한 Amazon VPC 내의 여러 ESM이 이벤트 폴러 단위(EPU) 용량을 공유할 수 있습니다. 이 옵션을 사용하면 ESM의 프로비저닝된 모드 비용을 최적화할 수 있습니다. ESM 그룹화 요구 사항:  
ESM이 동일한 Amazon VPC 내에 위치
폴러 그룹당 최대 100개의 ESM
그룹 내 모든 ESM의 최대 폴러 합계가 2,000을 초과할 수 없음
`PollerGroupName`을 업데이트하여 ESM을 다른 그룹으로 이동하거나 `PollerGroupName`을 빈 문자열("")로 설정하여 그룹에서 ESM을 제거할 수 있습니다.

# Lambda에서의 Apache Kafka 이벤트 폴러 스케일링 모드
<a name="kafka-scaling-modes"></a>

Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스 매핑을 위한 두 가지 이벤트 폴러 스케일링 모드 중에서 선택할 수 있습니다.
+ [온디맨드 모드(기본값)](#kafka-default-mode)
+ [프로비저닝된 모드](#kafka-provisioned-mode)

## 온디맨드 모드(기본값)
<a name="kafka-default-mode"></a>

Kafka 이벤트 소스를 처음 생성하는 경우 Lambda는 기본 이벤트 폴러 수를 할당하여 Kafka 주제의 모든 파티션을 처리합니다. Lambda는 메시지 로드에 따라 [이벤트 폴러](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode) 수를 자동으로 스케일 업 또는 스케일 다운합니다.

Lambda는 1분 간격으로 주제의 모든 파티션에 대한 오프셋 지연을 평가합니다. 오프셋 지연이 너무 크면 파티션은 Lambda에서 메시지를 처리할 수 있는 것보다 더 빠르게 메시지를 수신합니다. 필요한 경우 Lambda는 주제에서 이벤트 폴러를 추가하거나 제거합니다. 이벤트 폴러를 추가하거나 제거하는 이 오토 스케일링 프로세스는 평가 후 3분 이내에 수행됩니다.

대상 Lambda 함수가 스로틀링되면 Lambda는 이벤트 폴러 수를 줄입니다. 이 작업은 이벤트 폴러에서 검색하고 함수에 전송할 수 있는 메시지 수를 줄임으로써 함수의 워크로드를 줄입니다.

## 프로비저닝된 모드
<a name="kafka-provisioned-mode"></a>

이벤트 소스 매핑의 처리량을 미세 조정해야 하는 워크로드의 경우 프로비저닝된 모드를 사용할 수 있습니다. 프로비저닝된 모드에서는 프로비저닝된 이벤트 폴러의 양에 대한 최소 및 최대 제한을 정의합니다. 이러한 프로비저닝된 이벤트 폴러는 이벤트 소스 매핑 전용이며 응답형 오토스케일링을 통해 예상치 못한 메시지 급증을 처리할 수 있습니다. 성능 요구 사항이 엄격한 Kafka 워크로드에 대해서는 프로비저닝된 모드를 사용하는 것이 좋습니다.

Lambda에서 이벤트 폴러는 이벤트 소스 유형에 따라 처리량 기능이 다른 컴퓨팅 유닛입니다. Amazon MSK 및 자체 관리형 Apache Kafka의 경우 각 이벤트 폴러는 최대 5MB/s의 처리량 또는 최대 5개의 동시 간접 호출을 처리할 수 있습니다. 예를 들어 이벤트 소스가 1MB의 평균 페이로드를 생성하고 함수의 평균 기간이 1초인 경우 단일 Kafka 이벤트 폴러는 5MB/초 처리량과 5개의 동시 Lambda 간접 호출을 지원할 수 있습니다(페이로드 변환은 없다고 가정). Amazon SQS의 경우 각 이벤트 폴러는 최대 1MB/s의 처리량 또는 최대 10개의 동시 간접 호출을 처리할 수 있습니다. 프로비저닝 모드를 사용하면 이벤트 폴러 사용량에 따라 추가 비용이 발생합니다. 요금에 대한 자세한 내용은 [AWS Lambda 요금](https://aws.amazon.com/lambda/pricing/)을 참조하세요.

**참고**  
프로비저닝된 모드를 사용하는 경우 네트워크 구성의 일부로 AWS PrivateLink VPC 엔드포인트를 생성하거나 연결된 권한을 부여하지 않아도 됩니다.

프로비저닝된 모드에서 최소 이벤트 폴러 수(`MinimumPollers`)에 대해 허용되는 값의 범위는 1\$1200입니다. 최대 이벤트 폴러 수(`MaximumPollers`)에 대해 허용되는 값의 범위는 1\$12,000(경계 포함)입니다. `MaximumPollers`는 `MinimumPollers` 이상이어야 합니다. 또한 파티션 내에서 정렬된 처리를 유지 관리하기 위해 Lambda는 주제에서 파티션 수를 `MaximumPollers`로 제한합니다.

최소 및 최대 이벤트 폴러에 대해 적절한 값을 선택하는 방법에 대한 자세한 내용은 [모범 사례](#kafka-provisioned-mode-bp) 섹션을 참조하세요.

콘솔 또는 Lambda API를 사용하여 Kafka 이벤트 소스 매핑에 대한 프로비저닝된 모드를 구성할 수 있습니다.

**기존 이벤트 소스 매핑에 대해 프로비저닝된 모드를 구성하는 방법(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 프로비저닝된 모드를 구성할 이벤트 소스 매핑을 사용하는 함수를 선택합니다.

1. **구성**을 선택한 다음 **트리거**를 선택합니다.

1. 프로비저닝된 모드를 구성할 이벤트 소스 매핑을 선택하고 **편집**을 선택합니다.

1. **프로비저닝된 모드**에서 **구성**을 선택합니다.
   + **최소 이벤트 폴러**에 1\$1200의 값을 입력하세요. 값을 지정하지 않는 경우 Lambda에서는 기본값(1)을 선택합니다.
   + **최대 이벤트 폴러**에 1\$12,000의 값을 입력하세요 이 값은 **최소 이벤트 폴러**의 값 이상이어야 합니다. 값을 지정하지 않는 경우 Lambda에서는 기본값(200)을 선택합니다.

1. **저장**을 선택합니다.

[EventSourceMappingConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_EventSourceMappingConfiguration.html)의 [ProvisionedPollerConfig](https://docs.aws.amazon.com/lambda/latest/api/API_ProvisionedPollerConfig.html) 객체를 사용하여 프로그래밍 방식으로 프로비저닝된 모드를 구성할 수 있습니다. 예를 들어 다음 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) CLI 명령은 5의 `MinimumPollers` 값과 100의 `MaximumPollers` 값을 구성합니다.

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --provisioned-poller-config '{"MinimumPollers": 5, "MaximumPollers": 100}'
```

프로비저닝된 모드를 구성한 후 `ProvisionedPollers` 지표를 모니터링하여 워크로드에 대한 이벤트 폴러 사용량을 관찰할 수 있습니다. 자세한 내용은 [이벤트 소스 매핑 지표](monitoring-metrics-types.md#event-source-mapping-metrics) 섹션을 참조하세요.

프로비저닝 모드를 비활성화하고 기본(온디맨드) 모드로 돌아가기 위해 다음 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) CLI 명령을 사용할 수 있습니다.

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --provisioned-poller-config '{}'
```

## 고급 오류 처리 및 성능 기능
<a name="services-kafka-advanced-features"></a>

프로비저닝 모드가 활성화된 Kafka 이벤트 소스 매핑의 경우 오류 처리 및 성능을 개선하기 위해 추가 기능을 구성할 수 있습니다.
+ [재시도 구성](kafka-retry-configurations.md) - Lambda가 최대 재시도 횟수, 레코드 기간 제한, 배치 분할 및 부분 배치 응답으로 실패한 레코드를 처리하는 방법을 제어합니다.
+ [Kafka 실패 시 대상](kafka-on-failure-destination.md) - 후속 처리 또는 분석을 위해 실패한 레코드를 Kafka 주제로 보냅니다.

## 프로비저닝된 모드 사용 시 모범 사례 및 고려 사항
<a name="kafka-provisioned-mode-bp"></a>

이벤트 소스 매핑에 대한 최소 및 최대 이벤트 폴러의 최적 구성은 애플리케이션의 성능 요구 사항에 따라 달라집니다. 기본 최소 이벤트 폴러로 시작하여 성능 프로파일을 기준선으로 설정하는 것이 좋습니다. 관찰된 메시지 처리 패턴 및 원하는 성능 프로파일에 따라 구성을 조정합니다.

트래픽이 급증하고 성능 요구가 엄격한 워크로드의 경우 메시지의 갑작스러운 급증을 처리하도록 최소 이벤트 폴러를 늘립니다. 필요한 최소 이벤트 폴러를 확인하려면 초당 워크로드의 메시지 수와 평균 페이로드 크기를 고려하고 단일 이벤트 폴러의 처리량 용량(최대 5MBps)을 참조로 사용합니다.

파티션 내에서 정렬된 처리를 유지 관리하기 위해 Lambda는 최대 이벤트 폴러를 주제의 파티션 수로 제한합니다. 또한 이벤트 소스 매핑에서 조정할 수 있는 최대 이벤트 폴러는 함수의 동시성 설정에 따라 달라집니다.

프로비저닝된 모드를 활성화하는 경우 AWS PrivateLink VPC 엔드포인트 및 연결된 권한을 제거하도록 네트워크 설정을 업데이트합니다.

## 프로비저닝 모드의 비용 최적화
<a name="kafka-cost-optimization"></a>

### 프로비저닝 모드 요금
<a name="kafka-provisioned-pricing"></a>

프로비저닝 모드는 프로비저닝된 최소 이벤트 폴러와 오토 스케일링 중에 사용된 이벤트 폴러를 기준으로 요금이 부과됩니다. 요금은 이벤트 폴러 단위(EPU)라는 결제 단위를 사용하여 계산됩니다. Event-Poller-Unit-hours로 측정되는 사용한 EPU의 수와 기간에 대해 비용을 지불합니다. 성능에 민감한 애플리케이션에 대해 단일 ESM과 함께 프로비저닝 모드를 사용하거나 동일한 VPC 내에서 여러 ESM을 그룹화하여 EPU 용량과 비용을 공유할 수 있습니다. 프로비저닝 모드 비용을 최적화하는 데 도움이 되는 2가지 기능을 자세히 살펴보겠습니다. 요금에 대한 자세한 내용은 [AWS Lambda 요금](https://aws.amazon.com/lambda/pricing/)을 참조하세요.

### 향상된 EPU 사용률
<a name="kafka-enhanced-epu-utilization"></a>

각 EPU는 이벤트 폴링에 대해 최대 20MB/s의 처리량 용량을 지원하며 기본적으로 이벤트 폴러 10개를 지원합니다. 최소 및 최대 폴러를 설정하여 Kafka ESM에 대한 프로비저닝 모드를 생성하면 최소 폴러 수를 사용하여 EPU당 10개의 기본 이벤트 폴러를 EPU를 프로비저닝합니다. 하지만 각 이벤트 폴러는 최대 5MB/s의 처리량 용량을 지원하도록 독립적으로 규모를 조정할 수 있으며, 이로 인해 특정 EPU에서 밀도가 낮은 이벤트 폴러가 필요하게 되고 EPU 규모 조정이 트리거될 수 있습니다. EPU에 할당된 이벤트 폴러 수는 각 이벤트 폴러에서 사용하는 컴퓨팅 용량에 따라 달라집니다. 향상된 EPU 사용률 접근 방식을 사용하면 처리량 요구 사항이 다양한 이벤트 폴러가 EPU 용량을 효과적으로 활용하여 모든 ESM의 비용이 감소합니다.

### ESM 그룹화
<a name="kafka-esm-grouping-cost"></a>

프로비저닝 모드 비용을 추가로 최적화하려면 여러 Kafka ESM을 그룹화하여 EPU 용량을 공유할 수 있습니다. ESM 그룹화 및 향상된 EPU 사용률을 사용하면 단일 ESM 모드에서 실행하는 것에 비해 처리량이 적은 워크로드에 대해 프로비저닝 모드 비용을 최대 90% 줄일 수 있습니다. 1 EPU 용량 미만을 필요로 하는 모든 ESM은 ESM 그룹화의 이점을 누릴 수 있습니다. 이러한 ESM은 대체로 처리량 요구 사항을 지원하기 위해 최소 이벤트 폴러가 거의 필요하지 않습니다. 이 기능을 사용하면 모든 Kafka 워크로드에 프로비저닝 모드를 채택하고 스키마 검증, Avro/Protobuf 이벤트 필터링, 지연 시간이 짧은 간접 호출, 프로비저닝 모드에서만 사용할 수 있는 향상된 오류 처리 등의 기능을 활용할 수 있습니다.

동일한 Amazon VPC 내의 여러 ESM에 대해 동일한 값으로 `PollerGroupName` 파라미터를 구성하면 해당 ESM은 각각 전용 EPU 용량을 필요로 하는 대신 EPU 리소스를 공유합니다. 폴러 그룹당 최대 100개의 ESM을 그룹화할 수 있으며 그룹 내 모든 ESM의 최대 총 폴러 수는 2000개를 초과할 수 없습니다.

#### ESM 그룹화 구성(콘솔)
<a name="kafka-esm-grouping-console-cost"></a>

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 함수를 선택합니다.

1. **구성**을 선택하고 **트리거**를 선택합니다.

1. 새 Kafka 이벤트 소스 매핑을 생성하거나 기존 Kafka 이벤트 소스 매핑을 편집할 때 **프로비저닝 모드**에서 **구성**을 선택합니다.

1. **최소 이벤트 폴러**에 1\$1200의 값을 입력하세요.

1. **최대 이벤트 폴러**에 1\$12,000의 값을 입력하세요

1. **폴러 그룹 이름**에 그룹의 식별자를 입력합니다. 그룹화하려는 다른 ESM에도 동일한 이름을 사용합니다.

1. **저장**을 선택합니다.

#### ESM 그룹화 구성(AWS CLI)
<a name="kafka-esm-grouping-cli-cost"></a>

다음 예제에서는 이름이 `production-app-group`인 폴러 그룹을 사용하여 ESM을 생성합니다.

```
aws lambda create-event-source-mapping \
  --function-name myFunction1 \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/MyCluster/abcd1234 \
  --topics topic1 \
  --starting-position LATEST \
  --provisioned-poller-config '{
    "MinimumPollers": 1, 
    "MaximumPollers": 10, 
    "PollerGroupName": "production-app-group"
  }'
```

(EPU 용량을 공유하는) 동일한 그룹에 다른 ESM을 추가하려면 동일한 PollerGroupName을 사용합니다.

```
aws lambda create-event-source-mapping \
  --function-name myFunction2 \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/MyCluster/abcd1234 \
  --topics topic2 \
  --starting-position LATEST \
  --provisioned-poller-config '{
    "MinimumPollers": 1, 
    "MaximumPollers": 10, 
    "PollerGroupName": "production-app-group"
  }'
```

**참고**  
`PollerGroupName`을 업데이트하여 ESM을 다른 그룹으로 이동하거나 `PollerGroupName`에 대해 빈 문자열("")을 전달하여 그룹에서 ESM을 제거할 수 있습니다.

```
# Move ESM to a different group
aws lambda update-event-source-mapping \
  --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
  --provisioned-poller-config '{
    "MinimumPollers": 1, 
    "MaximumPollers": 10, 
    "PollerGroupName": "new-group-name"
  }'

# Remove ESM from group (use dedicated resources)
aws lambda update-event-source-mapping \
  --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
  --provisioned-poller-config '{
    "MinimumPollers": 1, 
    "MaximumPollers": 10, 
    "PollerGroupName": ""
  }'
```

#### 그룹화 전략 고려 사항
<a name="kafka-grouping-strategy-considerations"></a>
+ **애플리케이션 경계** - 더욱 효과적인 비용 할당 및 관리를 위해 동일한 애플리케이션 또는 서비스에 속하는 ESM을 그룹화합니다. `app-name-environment` 같은 명명 규칙을 사용하는 것이 좋습니다(예: `order-processor-prod`).
+ **트래픽 패턴** - 리소스 경합으로 이어질 수 있으므로 처리량이 높고 트래픽 패턴이 급증하는 ESM을 그룹화하지 않습니다.
+ **영향 범위** - 공유 인프라에 문제가 발생할 경우의 영향을 고려합니다. 동일한 그룹의 모든 ESM은 공유 리소스 제한의 영향을 받습니다. 미션 크리티컬 워크로드의 경우 별도의 그룹 또는 전용 ESM을 사용하는 것이 좋습니다.

#### 비용 최적화 예제
<a name="kafka-cost-optimization-example"></a>

각각 1개의 이벤트 폴러와 2MB/s 미만의 처리량으로 구성된 10개의 ESM이 있는 시나리오를 생각해 보겠습니다.

**그룹화 미사용:**
+ 각 ESM에는 자체 EPU가 필요합니다.
+ 필요한 총 EPU: 10
+ EPU당 비용: 미국 동부(버지니아 북부)에서 시간당 0.185 USD
+ 월별 EPU 비용(720시간): 10 × 720 × 0.185 USD = 1,332 USD

**그룹화 사용:**
+ 10개의 ESM 모두 EPU 용량 공유
+ 1개의 EPU에 10개의 이벤트 폴러(EPU 지원당 10개의 새 폴러 사용)
+ 필요한 총 EPU: 1
+ 월별 EPU 비용(720시간): 1 × 720 × 0.185 USD = 133.20 USD
+ **비용 절감: 90%**(월간 1,198.80 USD 절감)

# Lambda에서의 Apache Kafka 폴링 및 스트림 시작 위치
<a name="kafka-starting-positions"></a>

[StartingPosition 파라미터](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-StartingPosition)는 Lambda에게 Amazon MSK 또는 자체 관리형 Apache Kafka 스트림에서 메시지 읽기를 시작할 시기를 알려줍니다. 3가지 옵션 중에서 선택할 수 있습니다.
+ **최신** - Lambda가 Kafka 주제의 최신 레코드 직후 읽기 시작합니다.
+ **한계 자르기** - Lambda는 Kafka 주제에서 트리밍되지 않은 마지막 레코드부터 읽기 시작합니다. 이는 또한 해당 주제에서 가장 오래된 레코드입니다.
+ **타임스탬프** - Lambda가 타임스탬프로 정의된 위치에서 Unix 시간 초 단위로 읽기 시작합니다. [StartingPositionTimestamp 파라미터](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-StartingPositionTimestamp)를 사용하여 타임스탬프를 지정합니다.

이벤트 소스 매핑 생성 또는 업데이트 중 스트림 폴링은 결국 일관성을 유지합니다.
+ 이벤트 소스 매핑 생성 중 스트림에서 이벤트 폴링을 시작하는 데 몇 분 정도 걸릴 수 있습니다.
+ 이벤트 소스 매핑 업데이트 중에는 스트림에서 이벤트 폴링을 중지했다가 다시 시작하는 데 최대 90초가 걸릴 수 있습니다.

이 동작은 스트림의 시작 위치로 `LATEST`를 지정하면 이벤트 소스 매핑이 생성 또는 업데이트 중 이벤트를 놓칠 수 있음을 의미합니다. 누락된 이벤트가 없도록 하려면 `TRIM_HORIZON` 또는 `AT_TIMESTAMP`를 지정합니다.

# Lambda에서 사용자 지정이 가능한 소비자 그룹 ID
<a name="kafka-consumer-group-id"></a>

Amazon MSK 및 자체 관리형 Apache Kafka를 이벤트 소스로 설정할 때 [소비자 그룹](https://developer.confluent.io/learn-more/kafka-on-the-go/consumer-groups/) ID를 지정할 수 있습니다. 이 소비자 그룹 ID는 Lambda 함수에 가입하려는 Kafka 소비자 그룹의 기존 식별자입니다. 이 기능을 사용하여 진행 중인 모든 Kafka 레코드 처리 설정을 다른 소비자에서 Lambda로 원활하게 마이그레이션할 수 있습니다.

Kafka는 소비자 그룹에 속한 모든 소비자에게 메시지를 배포합니다. 다른 활성 소비자가 있는 소비자 그룹 ID를 지정하면 Lambda는 Kafka 주제에서 메시지의 일부만 수신합니다. Lambda가 주제에 있는 모든 메시지를 처리하도록 하려면 해당 소비자 그룹의 다른 모든 소비자를 끄세요.

또한 소비자 그룹 ID를 지정했는데 Kafka가 동일한 ID를 가진 유효한 기존 소비자 그룹을 찾으면 Lambda는 이벤트 소스 매핑을 위한 [StartingPosition](kafka-starting-positions.md)을 무시합니다. 대신 Lambda는 소비자 그룹의 커밋된 오프셋에 따라 레코드 처리를 시작합니다. 소비자 그룹 ID를 지정했는데 Kafka가 기존 소비자 그룹을 찾을 수 없는 경우, Lambda는 `StartingPosition`에서 지정된 대로 이벤트 소스를 구성합니다.

지정하는 소비자 그룹 ID는 모든 Kafka 이벤트 소스 중에서 고유해야 합니다. 지정된 소비자 그룹 ID로 Kafka 이벤트 소스 매핑을 생성한 후에는 이 값을 업데이트할 수 없습니다.

# Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스에서 이벤트 필터링
<a name="kafka-filtering"></a>

이벤트 필터링을 사용하여 Lambda가 함수로 전송하는 스트림 또는 대기열의 레코드를 제어할 수 있습니다. 이벤트 필터링의 작동 방식에 대한 일반적인 내용은 [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)을 참조하세요.

**참고**  
Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스 매핑은 `value` 키에 대한 필터링만 지원합니다.

**Topics**
+ [

## Kafka 이벤트 필터링 기본 사항
](#filtering-kafka)

## Kafka 이벤트 필터링 기본 사항
<a name="filtering-kafka"></a>

생산자가 Kafka 클러스터의 주제에 유효한 JSON 형식 또는 일반 문자열로 메시지를 작성한다고 가정해 보겠습니다. 예제 레코드는 다음과 같으며, 메시지는 `value` 필드에서 Base64로 인코딩된 문자열로 변환됩니다.

```
{
    "mytopic-0":[
        {
            "topic":"mytopic",
            "partition":0,
            "offset":15,
            "timestamp":1545084650987,
            "timestampType":"CREATE_TIME",
            "value":"SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
            "headers":[]
        }
    ]
}
```

Apache Kafka 생산자가 다음 JSON 형식으로 주제에 메시지를 작성하고 있다고 가정해 보겠습니다.

```
{
    "device_ID": "AB1234",
    "session":{
        "start_time": "yyyy-mm-ddThh:mm:ss",
        "duration": 162
    }
}
```

`value` 키를 사용하여 레코드를 필터링할 수 있습니다. `device_ID`가 문자 AB로 시작하는 레코드만 필터링하려고 한다고 가정해 보겠습니다. `FilterCriteria` 객체는 다음과 같습니다.

```
{
    "Filters": [
        {
            "Pattern": "{ \"value\" : { \"device_ID\" : [ { \"prefix\": \"AB\" } ] } }"
        }
    ]
}
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{
    "value": {
        "device_ID": [ { "prefix": "AB" } ]
      }
}
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "value" : { "device_ID" : [ { "prefix":  "AB" } ] } }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:kafka:us-east-2:123456789012:cluster/my-cluster/b-8ac7cc01-5898-482d-be2f-a6b596050ea8 \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"value\" : { \"device_ID\" : [ { \"prefix\":  \"AB\" } ] } }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"value\" : { \"device_ID\" : [ { \"prefix\":  \"AB\" } ] } }"}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
  Filters:
    - Pattern: '{ "value" : { "device_ID" : [ { "prefix":  "AB" } ] } }'
```

------

Kafka를 사용하면 메시지가 일반 문자열인 레코드를 필터링할 수도 있습니다. 문자열이 'error'인 메시지를 무시하려고 한다고 가정해 보겠습니다. `FilterCriteria` 객체는 다음과 같습니다.

```
{
    "Filters": [
        {
            "Pattern": "{ \"value\" : [ { \"anything-but\": [ \"error\" ] } ] }"
        }
    ]
}
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{
    "value": [
        {
        "anything-but": [ "error" ]
        }
    ]
}
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "value" : [ { "anything-but": [ "error" ] } ] }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:kafka:us-east-2:123456789012:cluster/my-cluster/b-8ac7cc01-5898-482d-be2f-a6b596050ea8 \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"value\" : [ { \"anything-but\": [ \"error\" ] } ] }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"value\" : [ { \"anything-but\": [ \"error\" ] } ] }"}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
  Filters:
    - Pattern: '{ "value" : [ { "anything-but": [ "error" ] } ] }'
```

------

Kafka 메시지는 UTF-8 인코딩 문자열이어야 하며, 일반 문자열이거나 JSON 형식이어야 합니다. 이는 Lambda가 필터 기준을 적용하기 전에 Kafka 바이트 배열을 UTF-8로 디코딩하기 때문입니다. 메시지가 UTF-16 또는 ASCII와 같은 다른 인코딩을 사용하거나 메시지 형식이 `FilterCriteria` 형식과 일치하지 않는 경우 Lambda는 메타데이터 필터만 처리합니다. 다음 표에는 특정 동작이 요약되어 있습니다.


| 수신 메시지 형식 | 메시지 속성에 대한 필터 패턴 형식 | 결과적 작업 | 
| --- | --- | --- | 
|  일반 문자열  |  일반 문자열  |  Lambda는 필터 기준에 따라 필터링합니다.  | 
|  일반 문자열  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  일반 문자열  |  유효한 JSON  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  유효한 JSON  |  일반 문자열  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  유효한 JSON  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  유효한 JSON  |  유효한 JSON  |  Lambda는 필터 기준에 따라 필터링합니다.  | 
|  UTF-8이 아닌 인코딩 문자열  |  JSON, 일반 문자열 또는 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 

# Lambda에서 Kafka 이벤트 소스와 함께 스키마 레지스트리 사용
<a name="services-consume-kafka-events"></a>

 스키마 레지스트리는 데이터 스트림 스키마를 정의하고 관리하는 데 도움이 됩니다. 스키마는 데이터 레코드의 구조와 포맷을 정의합니다. Kafka 이벤트 소스 매핑의 컨텍스트에서 Kafka 메시지가 Lambda 함수에 도달하기 전에 사전 정의된 스키마와 비교하여 Kafka 메시지의 구조와 형식을 검증하도록 스키마 레지스트리를 구성할 수 있습니다. 이렇게 하면 애플리케이션에 데이터 거버넌스 계층이 추가되고 데이터 형식을 효율적으로 관리하고, 스키마 규정 준수를 보장하고, 이벤트 필터링을 통해 비용을 최적화할 수 있습니다.

 이 기능은 모든 프로그래밍 언어와 호환되지만 다음과 같은 중요한 사항을 고려해야 합니다.
+ Powertools for Lambda는 Java, Python 및 TypeScript에 대한 특정 지원을 제공하여 기존 Kafka 개발 패턴과의 일관성을 유지하고 사용자 지정 역직렬화 코드 없이 비즈니스 객체에 직접 액세스할 수 있도록 합니다.
+ 이 기능은 프로비저닝된 모드를 사용하는 이벤트 소스 매핑에만 사용 가능합니다. 스키마 레지스트리는 온디맨드 모드에서 이벤트 소스 매핑을 지원하지 않습니다. 프로비저닝된 모드를 사용하고 있고 스키마 레지스트리가 구성된 경우 스키마 레지스트리 구성을 제거해야 온디맨드 모드로 변경할 수 있습니다. 자세한 내용은 [프로비저닝된 모드](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode) 섹션을 참조하세요.
+ 이벤트 소스 매핑(ESM)당 하나의 스키마 레지스트리만 구성할 수 있습니다. Kafka 이벤트 소스와 함께 스키마 레지스트리를 사용하면 프로비저닝된 모드의 요금 차원인 Lambda EPU(Event Poller Unit) 사용량이 증가할 수 있습니다.

**Topics**
+ [

## 스키마 레지스트리 옵션
](#services-consume-kafka-events-options)
+ [

## Lambda가 Kafka 메시지에 대한 스키마 검증을 수행하는 방법
](#services-consume-kafka-events-how)
+ [

## Kafka 스키마 레지스트리 구성
](#services-consume-kafka-events-config)
+ [

## Avro 및 Protobuf 필터링
](#services-consume-kafka-events-filtering)
+ [

## 페이로드 형식 및 역직렬화 동작
](#services-consume-kafka-events-payload)
+ [

## Lambda 함수에서 역직렬화된 데이터 작업
](#services-consume-kafka-events-payload-examples)
+ [

## 스키마 레지스트리의 인증 방법
](#services-consume-kafka-events-auth)
+ [

## 스키마 레지스트리 문제에 대한 오류 처리 및 문제 해결
](#services-consume-kafka-events-troubleshooting)

## 스키마 레지스트리 옵션
<a name="services-consume-kafka-events-options"></a>

 Lambda는 다음과 같은 스키마 레지스트리 옵션을 지원합니다.
+ [AWS Glue Schema Registry](https://docs.aws.amazon.com/glue/latest/dg/schema-registry.html)
+ [Confluent 클라우드 스키마 레지스트리](https://docs.confluent.io/platform/current/schema-registry/index.html)
+ [자체 관리형 Confluent 스키마 레지스트리](https://docs.confluent.io/platform/current/schema-registry/index.html)

 스키마 레지스트리는 다음 데이터 형식의 메시지 검증을 지원합니다.
+ Apache Avro
+ 프로토콜 버퍼(Protobuf)
+ JSON 스키마(JSON-SE)

 스키마 레지스트리를 사용하려면 먼저 이벤트 소스 매핑이 프로비저닝된 모드인지 확인합니다. 스키마 레지스트리를 사용하면 Lambda가 페이로드에 스키마에 대한 메타데이터를 추가합니다. 자세한 내용은 [페이로드 형식 및 역직렬화 동작](#services-consume-kafka-events-payload)을 참조하세요.

## Lambda가 Kafka 메시지에 대한 스키마 검증을 수행하는 방법
<a name="services-consume-kafka-events-how"></a>

 스키마 레지스트리를 구성하면 Lambda가 각 Kafka 메시지에 대해 다음 단계를 수행합니다.

1. Lambda가 클러스터에서 Kafka 레코드를 폴링합니다.

1. Lambda가 스키마 레지스트리의 특정 스키마에 대해 레코드에서 선택된 메시지 속성을 검증합니다.
   + 메시지와 연관된 스키마를 레지스트리에서 찾을 수 없는 경우 Lambda가 `SCHEMA_NOT_FOUND`라는 이유 코드와 함께 메시지를 DLQ로 전송합니다.

1. Lambda가 스키마 레지스트리 구성에 따라 메시지를 역직렬화하여 메시지를 검증합니다. 이벤트 필터링이 구성된 경우 Lambda가 구성된 필터 기준을 기반으로 필터링을 수행합니다.
   + 역직렬화에 실패하는 경우 Lambda가 `DESERIALIZATION_ERROR`라는 이유 코드와 함께 메시지를 DLQ로 전송합니다. DLQ가 구성되지 않은 경우 Lambda가 메시지를 삭제합니다.

1. 메시지가 스키마 레지스트리에 의해 검증되고 필터 기준에 의해 필터링되지 않는 경우 Lambda가 메시지와 함께 함수를 간접적으로 호출합니다.

 이 기능은 스키마 레지스트리와 통합된 Kafka 클라이언트를 사용하여 이미 생성된 메시지를 검증하기 위한 것입니다. 스키마 레지스트리로 작업하여 올바른 형식의 메시지를 생성하도록 Kafka 생산자를 구성하는 것이 좋습니다.

## Kafka 스키마 레지스트리 구성
<a name="services-consume-kafka-events-config"></a>

 다음 콘솔 단계에서는 이벤트 소스 매핑에 Kafka 스키마 레지스트리 구성을 추가합니다.

**이벤트 소스 매핑에 Kafka 스키마 레지스트리 구성을 추가하려면 다음을 수행하세요(콘솔).**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. **구성**을 선택합니다.

1. **트리거**를 선택합니다.

1. 스키마 레지스트리를 구성하려는 Kafka 이벤트 소스 매핑을 선택한 다음 **편집**을 선택합니다.

1. **이벤트 폴러 구성**에서 **스키마 레지스트리 구성**을 선택합니다. 이 옵션을 보려면 이벤트 소스 매핑이 프로비저닝된 모드에 있어야 합니다.

1. **스키마 레지스트리 URI**에 AWS Glue 스키마 레지스트리의 ARN 또는 Confluent 클라우드 스키마 레지스트리나 자체 관리형 Confluent 스키마 레지스트리의 HTTPS URL을 입력합니다.

1. 다음은 Lambda가 스키마 레지스트리에 액세스하는 방법을 지정하는 구성 단계입니다. 자세한 내용은 [스키마 레지스트리의 인증 방법](#services-consume-kafka-events-auth) 섹션을 참조하세요.
   + **액세스 구성 유형**에서 Lambda가 스키마 레지스트리에 액세스하는 데 사용하는 인증 유형을 선택합니다.
   + **액세스 구성 URI**에 스키마 레지스트리로 인증할 Secrets Manager 시크릿의 ARN을 입력합니다(해당하는 경우). 함수의 [실행 역할](with-msk-permissions.md)에 올바른 권한이 있는지 확인합니다.

1. 스키마 레지스트리가 Private Certificate Authority(CA) 또는 Lambda 트러스트 스토어에 없는 인증 기관(CA)에 의해 서명된 경우에만 **암호화** 필드가 적용됩니다. 해당하는 경우 TLS 암호화를 위해 스키마 레지스트리에서 사용하는 Private CA Certificate가 포함된 시크릿 키를 제공합니다.

1. **이벤트 레코드 형식**에서 스키마 검증 후 Lambda가 함수에 레코드를 전달하는 방법을 선택합니다. 자세한 내용은 [페이로드 형식 예제](#services-consume-kafka-events-payload)를 참조하세요.
   + **JSON**을 선택하는 경우 Lambda가 아래 스키마 검증 속성에서 선택한 속성을 표준 JSON 형식으로 전달합니다. 선택하지 않은 속성의 경우 Lambda가 해당 속성을 그대로 전달합니다.
   + **소스**를 선택하는 경우 Lambda가 아래 스키마 검증 속성에서 선택한 속성을 원본 소스 형식으로 전달합니다.

1. **스키마 검증 속성**에서 Lambda가 스키마 레지스트리를 사용하여 검증하고 역직렬화할 메시지 속성을 선택합니다. **KEY** 또는 **VALUE** 중 하나 이상을 선택해야 합니다. 이벤트 레코드 형식으로 JSON을 선택한 경우 Lambda가 선택한 메시지 속성을 함수로 전송하기 전에 역직렬화합니다. 자세한 내용은 [페이로드 형식 및 역직렬화 동작](#services-consume-kafka-events-payload)을 참조하세요.

1. **저장**을 선택합니다.

 Lambda API를 사용하여 스키마 레지스트리 구성으로 이벤트 소스 매핑을 생성하거나 업데이트할 수도 있습니다. 다음 예제에서는 *AWS Lambda API 참조*의 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) 및 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) API 작업에 해당하는 AWS CLI를 사용하여 AWS Glue 또는 Confluent 스키마 레지스트리를 구성하는 방법을 보여줍니다.

**중요**  
AWS CLI 또는 `update-event-source-mapping` API를 사용하여 스키마 레지스트리 구성 필드를 업데이트하는 경우 스키마 레지스트리 구성의 모든 필드를 업데이트해야 합니다.

------
#### [ Create Event Source Mapping ]

```
aws lambda create-event-source-mapping \
  --function-name my-schema-validator-function \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/a1b2c3d4-5678-90ab-cdef-11111EXAMPLE \
  --topics my-kafka-topic \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=1 \
  --amazon-managed-kafka-event-source-mapping '{
      "SchemaRegistryConfig" : {
          "SchemaRegistryURI": "https://abcd-ef123.us-west-2.aws.confluent.cloud",
          "AccessConfigs": [{
              "Type": "BASIC_AUTH", 
              "URI": "arn:aws:secretsmanager:us-east-1:123456789012:secret:secretName"
          }],
          "EventRecordFormat": "JSON",
          "SchemaValidationConfigs": [
          { 
              "Attribute": "KEY" 
          },
          { 
              "Attribute": "VALUE" 
          }]
      }
  }'
```

------
#### [ Update AWS Glue Schema Registry ]

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --amazon-managed-kafka-event-source-mapping '{
        "SchemaRegistryConfig" : {
            "SchemaRegistryURI": "arn:aws:glue:us-east-1:123456789012:registry/registryName",
            "EventRecordFormat": "JSON",
            "SchemaValidationConfigs": [
            { 
                "Attribute": "KEY" 
            },
            { 
                "Attribute": "VALUE" 
            }]
        }
    }'
```

------
#### [ Update Confluent Schema Registry with Authentication ]

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --amazon-managed-kafka-event-source-mapping '{
        "SchemaRegistryConfig" : {
            "SchemaRegistryURI": "https://abcd-ef123.us-west-2.aws.confluent.cloud",
            "AccessConfigs": [{
                "Type": "BASIC_AUTH", 
                "URI": "arn:aws:secretsmanager:us-east-1:123456789012:secret:secretName"
            }],
            "EventRecordFormat": "JSON",
            "SchemaValidationConfigs": [
            { 
                "Attribute": "KEY" 
            },
            { 
                "Attribute": "VALUE" 
            }]
        }
    }'
```

------
#### [ Update Confluent Schema Registry without Authentication ]

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --amazon-managed-kafka-event-source-mapping '{
        "SchemaRegistryConfig" : {
            "SchemaRegistryURI": "https://abcd-ef123.us-west-2.aws.confluent.cloud",
            "EventRecordFormat": "JSON",
            "SchemaValidationConfigs": [
            { 
                "Attribute": "KEY" 
            },
            { 
                "Attribute": "VALUE" 
            }]
        }
    }'
```

------
#### [ Remove Schema Registry Configuration ]

이벤트 소스 매핑에서 스키마 레지스트리 구성을 제거하려면 *AWS Lambda API 참조*의 CLI 명령 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html)을 사용합니다.

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --amazon-managed-kafka-event-source-mapping '{
        "SchemaRegistryConfig" : {}
    }'
```

------

## Avro 및 Protobuf 필터링
<a name="services-consume-kafka-events-filtering"></a>

 스키마 레지스트리와 함께 Avro 또는 Protobuf 형식을 사용하면 Lambda 함수에 이벤트 필터링을 적용할 수 있습니다. 필터 패턴은 스키마 검증 후 데이터의 역직렬화된 클래식 JSON 표현에 적용됩니다. 예를 들어 가격을 포함한 제품 세부 정보를 정의하는 Avro 스키마를 사용하면 가격 값을 기준으로 메시지를 필터링할 수 있습니다.

**참고**  
 역직렬화될 때 Avro는 표준 JSON으로 변환되므로 Avro 객체로 직접 다시 변환할 수 없습니다. Avro 객체로 변환해야 하는 경우 SOURCE 형식을 대신 사용합니다.  
 Protobuf의 역직렬화 시 결과 JSON의 필드 이름은 Protobuf가 일반적으로 수행하는 것처럼 낙타 대문자로 변환되지 않고 스키마에 정의된 필드 이름과 일치합니다. 필터링 패턴을 생성할 때 이 점에 유의하세요.

```
aws lambda create-event-source-mapping \
    --function-name myAvroFunction \
    --topics myAvroTopic \
    --starting-position TRIM_HORIZON \
    --kafka-bootstrap-servers '["broker1:9092", "broker2:9092"]' \
    --schema-registry-config '{
        "SchemaRegistryURI": "arn:aws:glue:us-east-1:123456789012:registry/myAvroRegistry",
        "EventRecordFormat": "JSON",
        "SchemaValidationConfigs": [
            { 
                "Attribute": "VALUE" 
            }
        ]
    }' \
    --filter-criteria '{
        "Filters": [
            {
                "Pattern": "{ \"value\" : { \"field_1\" : [\"value1\"], \"field_2\" : [\"value2\"] } }"
            }
        ]
    }'
```

 이 예제에서 필터 패턴은 `value` 객체를 분석하여 `field_1`의 메시지를 `"value1"`과 일치시키고 `field_2`의 메시지를 `"value2"`와 일치시킵니다. Lambda가 Avro 형식에서 JSON으로 메시지를 변환한 후 역직렬화된 데이터에 대해 필터 기준이 평가됩니다.

 이벤트 필터링에 대한 자세한 내용은 [Lambda 이벤트 필터링](invocation-eventfiltering.md)을 참조하세요.

## 페이로드 형식 및 역직렬화 동작
<a name="services-consume-kafka-events-payload"></a>

 스키마 레지스트리를 사용할 때 Lambda는 [일반 이벤트 페이로드](with-msk.md#msk-sample-event)와 비슷한 형식으로 최종 페이로드를 함수에 전달하며, 여기에는 몇 가지 추가 필드가 포함됩니다. 추가 필드는 `SchemaValidationConfigs` 파라미터에 따라 달라집니다. 검증을 위해 선택하는 각 속성(키 또는 값)에 대해 Lambda는 페이로드에 해당 스키마 메타데이터를 추가합니다.

**참고**  
스키마 메타데이터 필드를 사용하려면 [aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-events)를 버전 3.16.0 이상으로 업데이트해야 합니다.

 예를 들어 `value` 필드를 검증하면 Lambda는 페이로드에 `valueSchemaMetadata`라는 필드를 추가합니다. 마찬가지로 `key` 필드에 대해 Lambda는 `keySchemaMetadata`라는 필드를 추가합니다. 이 메타데이터에는 데이터 형식과 검증에 사용된 스키마 ID에 대한 정보가 포함되어 있습니다.

```
"valueSchemaMetadata": {
    "dataFormat": "AVRO",
    "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
```

 `EventRecordFormat` 파라미터는 `JSON` 또는 `SOURCE`로 설정할 수 있으며, 이에 따라 Lambda가 스키마 검증된 데이터를 함수에 전달하기 전에 처리하는 방법이 결정됩니다. 각 옵션은 다양한 처리 기능을 제공합니다.
+ `JSON` - Lambda는 검증된 속성을 표준 JSON 형식으로 역직렬화하여 JSON을 기본적으로 지원하는 언어에서 직접 사용할 수 있도록 데이터를 준비합니다. 이 형식은 원본 바이너리 형식을 보존하거나 생성된 클래스로 작업할 필요가 없는 경우에 가장 적합합니다.
+ `SOURCE` - Lambda는 데이터의 원본 바이너리 형식을 Base64로 인코딩된 문자열로 유지하여 Avro 또는 Protobuf 객체로 직접 변환할 수 있도록 합니다. 이 형식은 강력한 형식의 언어로 작업하거나 Avro 또는 Protobuf 스키마의 전체 기능을 유지해야 할 때 필수적입니다.

이러한 형식 특성과 언어별 고려 사항을 바탕으로 다음 형식이 권장됩니다.


**프로그래밍 언어에 따른 권장 형식**  

| 언어 | Avro | Protobuf | JSON | 
| --- | --- | --- | --- | 
| Java | 소스 | 소스 | 소스 | 
| Python | JSON | JSON | JSON | 
| NodeJS | JSON | JSON | JSON | 
| .NET | 소스 | 소스 | 소스 | 
| 기타 | JSON | JSON | JSON | 

다음 섹션에서는 이러한 형식을 자세히 설명하고 각 형식에 대한 예제 페이로드를 제공합니다.

### JSON 형식
<a name="services-consume-kafka-events-payload-json"></a>

 `EventRecordFormat`으로 `JSON`을 선택하면 Lambda는 `SchemaValidationConfigs` 필드에서 선택한 메시지 속성(`key` 및/또는 `value` 속성)을 검증하고 역직렬화합니다. Lambda는 선택된 속성을 함수에서 표준 JSON 표현의 base64로 인코딩된 문자열로 전달합니다.

**참고**  
 역직렬화될 때 Avro는 표준 JSON으로 변환되므로 Avro 객체로 직접 다시 변환할 수 없습니다. Avro 객체로 변환해야 하는 경우 SOURCE 형식을 대신 사용합니다.  
 Protobuf의 역직렬화 시 결과 JSON의 필드 이름은 Protobuf가 일반적으로 수행하는 것처럼 낙타 대문자로 변환되지 않고 스키마에 정의된 필드 이름과 일치합니다. 필터링 패턴을 생성할 때 이 점에 유의하세요.

 다음은 `EventRecordFormat`으로 `JSON`을 선택하고, `key` 및 `value` 속성을 모두 `SchemaValidationConfigs`로 선택하는 경우의 예제 페이로드입니다.

```
{
   "eventSource":"aws:kafka",
   "eventSourceArn":"arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111-1",
   "bootstrapServers":"b-2.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092,b-1.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092",
   "records":{
      "mytopic-0":[
         {
            "topic":"mytopic",
            "partition":0,
            "offset":15,
            "timestamp":1545084650987,
            "timestampType":"CREATE_TIME",
            "key":"abcDEFghiJKLmnoPQRstuVWXyz1234==", //Base64 encoded string of JSON
            "keySchemaMetadata": {
                "dataFormat": "AVRO",
                "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
            },
            "value":"abcDEFghiJKLmnoPQRstuVWXyz1234", //Base64 encoded string of JSON
            "valueSchemaMetadata": {
                "dataFormat": "AVRO",
                "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
            },
            "headers":[
               {
                  "headerKey":[
                     104,
                     101,
                     97,
                     100,
                     101,
                     114,
                     86,
                     97,
                     108,
                     117,
                     101
                  ]
               }
            ]
         }
      ]
   }
}
```

 이 예시는 다음과 같이 설정되어 있습니다.
+ `key`와 `value` 모두 JSON 표현을 역직렬화한 후 base64로 인코딩된 문자열입니다.
+ Lambda에는 `keySchemaMetadata`와 `valueSchemaMetadata`의 두 속성에 대한 스키마 메타데이터가 포함됩니다.
+ 함수는 `key` 및 `value` 문자열을 디코딩하여 역직렬화된 JSON 데이터에 액세스할 수 있습니다.

 JSON 형식은 Python이나 Node.js와 같이 강력한 형식이 아닌 언어에 권장됩니다. 이러한 언어는 JSON을 객체로 변환하는 기능을 기본적으로 지원합니다.

### 소스 형식
<a name="services-consume-kafka-events-payload-source"></a>

 `EventRecordFormat`으로 `SOURCE`를 선택하면 Lambda는 스키마 레지스트리에 대해 레코드를 검증하지만 역직렬화 없이 원본 바이너리 데이터를 함수에 전달합니다. 이 바이너리 데이터는 원본 바이트 데이터의 Base64로 인코딩된 문자열로 전달되며, 생산자가 추가한 메타데이터는 제거됩니다. 따라서 함수 코드 내에서 원시 바이너리 데이터를 Avro 및 Protobuf 객체로 직접 변환할 수 있습니다. Powertools for AWS Lambda를 사용하는 것이 좋습니다. 이 도구는 원시 바이너리 데이터를 역직렬화하여 Avro 및 Protobuf 객체를 직접 제공합니다.

 예를 들어 `key` 및 `value` 속성을 모두 검증하도록 Lambda를 구성하지만 `SOURCE` 형식을 사용하는 경우 함수는 다음과 같은 페이로드를 수신합니다.

```
{
    "eventSource": "aws:kafka",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111-1",
    "bootstrapServers": "b-2.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092,b-1.demo-cluster-1.a1bcde.c1.kafka.us-east-1.amazonaws.com:9092",
    "records": {
        "mytopic-0": [
            {
                "topic": "mytopic",
                "partition": 0,
                "offset": 15,
                "timestamp": 1545084650987,
                "timestampType": "CREATE_TIME",
                "key": "abcDEFghiJKLmnoPQRstuVWXyz1234==", // Base64 encoded string of Original byte data, producer-appended metadata removed
                "keySchemaMetadata": {
                    "dataFormat": "AVRO",
                    "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
                },
                "value": "abcDEFghiJKLmnoPQRstuVWXyz1234==", // Base64 encoded string of Original byte data, producer-appended metadata removed
                "valueSchemaMetadata": {
                    "dataFormat": "AVRO",
                    "schemaId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
                },
                "headers": [
                    {
                        "headerKey": [
                            104,
                            101,
                            97,
                            100,
                            101,
                            114,
                            86,
                            97,
                            108,
                            117,
                            101
                        ]
                    }
                ]
            }
        ]
    }
}
```

 이 예시는 다음과 같이 설정되어 있습니다.
+ `key`와 `value` 모두 원본 바이너리 데이터를 Base64로 인코딩 문자열로 포함합니다.
+ 함수는 적절한 라이브러리를 사용하여 역직렬화를 처리해야 합니다.

 Avro에서 생성한 객체나 Protobuf에서 생성한 객체를 사용하는 경우, 특히 Java 함수와 함께 사용하는 경우 `EventRecordFormat`에 대해 `SOURCE`를 선택하는 것이 좋습니다. 이는 Java가 강력한 형식이고 Avro 및 Protobuf 형식에 특정 역직렬화기가 필요하기 때문입니다. 함수 코드에서 선호하는 Avro 또는 Protobuf 라이브러리를 사용하여 데이터를 역직렬화할 수 있습니다.

## Lambda 함수에서 역직렬화된 데이터 작업
<a name="services-consume-kafka-events-payload-examples"></a>

AWS Lambda는 사용하는 형식에 따라 함수 코드에서 Kafka 레코드를 역직렬화하는 데 도움이 됩니다. 이 유틸리티는 데이터 변환을 처리하고 바로 사용할 수 있는 객체를 제공함으로써 Kafka 레코드 작업을 간소화합니다.

 함수에서 Powertools for AWS Lambda를 사용하려면 Lambda 함수를 빌드할 때 Powertools for AWS Lambda를 계층으로 추가하거나 종속성으로 포함해야 합니다. 설정 방법과 자세한 내용은 선호하는 언어에 대한 Powertools for AWS Lambda 설명서를 참조하세요.
+ [Powertools for AWS Lambda(Java)](https://docs.powertools.aws.dev/lambda/java/latest/utilities/kafka/)
+ [Powertools for AWS Lambda(Python)](https://docs.powertools.aws.dev/lambda/python/latest/utilities/kafka/)
+ [Powertools for AWS Lambda(TypeScript)](https://docs.powertools.aws.dev/lambda/typescript/latest/features/kafka/)
+ [Powertools for AWS Lambda(.NET)](https://docs.powertools.aws.dev/lambda/dotnet/utilities/kafka/)

**참고**  
스키마 레지스트리 통합 작업 시 `SOURCE` 또는 `JSON` 형식을 선택할 수 있습니다. 각 옵션은 아래와 같이 다양한 직렬화 형식을 지원합니다.  


| 형식 | 지원 | 
| --- | --- | 
|  소스  |  Avro 및 Protobuf(Lambda 스키마 레지스트리 통합 사용)  | 
|  JSON  |  JSON 데이터  | 

 `SOURCE` 또는 `JSON` 형식을 사용할 때 Powertools for AWS를 사용하여 함수 코드의 데이터를 역직렬화할 수 있습니다. 다음은 다양한 데이터 형식을 처리하는 방법의 예입니다.

------
#### [ AVRO ]

Java 예제:

```
package org.demo.kafka;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.demo.kafka.avro.AvroProduct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.lambda.powertools.kafka.Deserialization;
import software.amazon.lambda.powertools.kafka.DeserializationType;
import software.amazon.lambda.powertools.logging.Logging;

public class AvroDeserializationFunction implements RequestHandler<ConsumerRecords<String, AvroProduct>, String> {

    private static final Logger LOGGER = LoggerFactory.getLogger(AvroDeserializationFunction.class);

    @Override
    @Logging
    @Deserialization(type = DeserializationType.KAFKA_AVRO)
    public String handleRequest(ConsumerRecords<String, AvroProduct> records, Context context) {
        for (ConsumerRecord<String, AvroProduct> consumerRecord : records) {
            LOGGER.info("ConsumerRecord: {}", consumerRecord);

            AvroProduct product = consumerRecord.value();
            LOGGER.info("AvroProduct: {}", product);

            String key = consumerRecord.key();
            LOGGER.info("Key: {}", key);
        }

        return "OK";
    }

}
```

Python 예제:

```
from aws_lambda_powertools.utilities.kafka_consumer.kafka_consumer import kafka_consumer
from aws_lambda_powertools.utilities.kafka_consumer.schema_config import SchemaConfig
from aws_lambda_powertools.utilities.kafka_consumer.consumer_records import ConsumerRecords

from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools import Logger

logger = Logger(service="kafkaConsumerPowertools")

value_schema_str = open("customer_profile.avsc", "r").read()

schema_config = SchemaConfig(
value_schema_type="AVRO",
value_schema=value_schema_str)

@kafka_consumer(schema_config=schema_config)
def lambda_handler(event: ConsumerRecords, context:LambdaContext):

  for record in event.records:
      value = record.value
      logger.info(f"Received value: {value}")
```

TypeScript 예제:

```
import { kafkaConsumer } from '@aws-lambda-powertools/kafka';

import type { ConsumerRecords } from '@aws-lambda-powertools/kafka/types';
import { Logger } from '@aws-lambda-powertools/logger';
import type { Context } from 'aws-lambda';

const logger = new Logger();

type Value = {
    id: number;
    name: string;
    price: number;
};

const schema = '{   
    "type": "record",   
    "name": "Product",   
    "fields": [     
        { "name": "id", "type": "int" },     
        { "name": "name", "type": "string" },     
        { "name": "price", "type": "double" }   
    ] 
}';

export const handler = kafkaConsumer<string, Value>(
    (event: ConsumerRecords<string, Value>, _context: Context) => {
        for (const record of event.records) {
            logger.info(Processing record with key: ${record.key});
            logger.info(Record value: ${JSON.stringify(record.value)});
            // You can add more processing logic here
        }
    },
    {
        value: {
            type: 'avro',
            schema: schema,
        },
    }
);
```

.NET 예제:

```
using Amazon.Lambda.Core;
using AWS.Lambda.Powertools.Kafka;
using AWS.Lambda.Powertools.Kafka.Avro;
using AWS.Lambda.Powertools.Logging;
using Com.Example;

// Assembly attribute to enable the Lambda function's Kafka event to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(PowertoolsKafkaAvroSerializer))]

namespace ProtoBufClassLibrary;

public class Function
{
    public string FunctionHandler(ConsumerRecords<string, CustomerProfile> records, ILambdaContext context)
    {
        foreach (var record in records)
        {
            Logger.LogInformation("Processing messagem from topic: {topic}", record.Topic);
            Logger.LogInformation("Partition: {partition}, Offset: {offset}", record.Partition, record.Offset);
            Logger.LogInformation("Produced at: {timestamp}", record.Timestamp);
            
            foreach (var header in record.Headers.DecodedValues())
            {
                Logger.LogInformation($"{header.Key}: {header.Value}");
            }
            
            Logger.LogInformation("Processing order for: {fullName}", record.Value.FullName);
        }
    
        return "Processed " + records.Count() + " records";
    }
}
```

------
#### [ PROTOBUF ]

Java 예제:

```
package org.demo.kafka;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.demo.kafka.protobuf.ProtobufProduct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.lambda.powertools.kafka.Deserialization;
import software.amazon.lambda.powertools.kafka.DeserializationType;
import software.amazon.lambda.powertools.logging.Logging;

public class ProtobufDeserializationFunction
        implements RequestHandler<ConsumerRecords<String, ProtobufProduct>, String> {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProtobufDeserializationFunction.class);

    @Override
    @Logging
    @Deserialization(type = DeserializationType.KAFKA_PROTOBUF)
    public String handleRequest(ConsumerRecords<String, ProtobufProduct> records, Context context) {
        for (ConsumerRecord<String, ProtobufProduct> consumerRecord : records) {
            LOGGER.info("ConsumerRecord: {}", consumerRecord);

            ProtobufProduct product = consumerRecord.value();
            LOGGER.info("ProtobufProduct: {}", product);

            String key = consumerRecord.key();
            LOGGER.info("Key: {}", key);
        }

        return "OK";
    }

}
```

Python 예제:

```
from aws_lambda_powertools.utilities.kafka_consumer.kafka_consumer import kafka_consumer

from aws_lambda_powertools.utilities.kafka_consumer.schema_config import SchemaConfig
from aws_lambda_powertools.utilities.kafka_consumer.consumer_records import ConsumerRecords

from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools import Logger

from user_pb2 import User # protobuf generated class

logger = Logger(service="kafkaConsumerPowertools")

schema_config = SchemaConfig(
value_schema_type="PROTOBUF",
value_schema=User)

@kafka_consumer(schema_config=schema_config)
def lambda_handler(event: ConsumerRecords, context:LambdaContext):

  for record in event.records:
      value = record.value
      logger.info(f"Received value: {value}")
```

TypeScript 예제:

```
import { kafkaConsumer } from '@aws-lambda-powertools/kafka';
import type { ConsumerRecords } from '@aws-lambda-powertools/kafka/types';
import { Logger } from '@aws-lambda-powertools/logger';
import type { Context } from 'aws-lambda';
import { Product } from './product.generated.js';

const logger = new Logger();

type Value = {
    id: number;
    name: string;
    price: number;
};

export const handler = kafkaConsumer<string, Value>(
    (event: ConsumerRecords<string, Value>, _context: Context) => {
        for (const record of event.records) {
            logger.info(Processing record with key: ${record.key});
            logger.info(Record value: ${JSON.stringify(record.value)});
        }
    },
    {
        value: {
            type: 'protobuf',
            schema: Product,
        },
    }
);
```

.NET 예제:

```
using Amazon.Lambda.Core;
using AWS.Lambda.Powertools.Kafka;
using AWS.Lambda.Powertools.Kafka.Protobuf;
using AWS.Lambda.Powertools.Logging;
using Com.Example;

// Assembly attribute to enable the Lambda function's Kafka event to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(PowertoolsKafkaProtobufSerializer))]

namespace ProtoBufClassLibrary;

public class Function
{
    public string FunctionHandler(ConsumerRecords<string, CustomerProfile> records, ILambdaContext context)
    {
        foreach (var record in records)
        {
            Logger.LogInformation("Processing messagem from topic: {topic}", record.Topic);
            Logger.LogInformation("Partition: {partition}, Offset: {offset}", record.Partition, record.Offset);
            Logger.LogInformation("Produced at: {timestamp}", record.Timestamp);
            
            foreach (var header in record.Headers.DecodedValues())
            {
                Logger.LogInformation($"{header.Key}: {header.Value}");
            }
            
            Logger.LogInformation("Processing order for: {fullName}", record.Value.FullName);
        }
    
        return "Processed " + records.Count() + " records";
    }
}
```

------
#### [ JSON ]

Java 예제:

```
package org.demo.kafka;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.lambda.powertools.kafka.Deserialization;
import software.amazon.lambda.powertools.kafka.DeserializationType;
import software.amazon.lambda.powertools.logging.Logging;

public class JsonDeserializationFunction implements RequestHandler<ConsumerRecords<String, Product>, String> {

    private static final Logger LOGGER = LoggerFactory.getLogger(JsonDeserializationFunction.class);

    @Override
    @Logging
    @Deserialization(type = DeserializationType.KAFKA_JSON)
    public String handleRequest(ConsumerRecords<String, Product> consumerRecords, Context context) {
        for (ConsumerRecord<String, Product> consumerRecord : consumerRecords) {
            LOGGER.info("ConsumerRecord: {}", consumerRecord);

            Product product = consumerRecord.value();
            LOGGER.info("Product: {}", product);

            String key = consumerRecord.key();
            LOGGER.info("Key: {}", key);
        }

        return "OK";
    }
}
```

Python 예제:

```
from aws_lambda_powertools.utilities.kafka_consumer.kafka_consumer import kafka_consumer

from aws_lambda_powertools.utilities.kafka_consumer.schema_config import SchemaConfig
from aws_lambda_powertools.utilities.kafka_consumer.consumer_records import ConsumerRecords

from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools import Logger

logger = Logger(service="kafkaConsumerPowertools")

schema_config = SchemaConfig(value_schema_type="JSON")

@kafka_consumer(schema_config=schema_config)
def lambda_handler(event: ConsumerRecords, context:LambdaContext):

  for record in event.records:
      value = record.value
      logger.info(f"Received value: {value}")
```

TypeScript 예제:

```
import { kafkaConsumer } from '@aws-lambda-powertools/kafka';
import type { ConsumerRecords } from '@aws-lambda-powertools/kafka/types';
import { Logger } from '@aws-lambda-powertools/logger';
import type { Context } from 'aws-lambda';

const logger = new Logger();

type Value = {
    id: number;
    name: string;
    price: number;
};

export const handler = kafkaConsumer<string, Value>(
    (event: ConsumerRecords<string, Value>, _context: Context) => {
        for (const record of event.records) {
            logger.info(Processing record with key: ${record.key});
            logger.info(Record value: ${JSON.stringify(record.value)});
            // You can add more processing logic here
        }
    },
    {
        value: {
            type: 'json',
        },
    }
);
```

.NET 예제:

```
using Amazon.Lambda.Core;
using AWS.Lambda.Powertools.Kafka;
using AWS.Lambda.Powertools.Kafka.Json;
using AWS.Lambda.Powertools.Logging;
using Com.Example;

// Assembly attribute to enable the Lambda function's Kafka event to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(PowertoolsKafkaJsonSerializer))]

namespace JsonClassLibrary;

public class Function
{
    public string FunctionHandler(ConsumerRecords<string, CustomerProfile> records, ILambdaContext context)
    {
        foreach (var record in records)
        {
            Logger.LogInformation("Processing messagem from topic: {topic}", record.Topic);
            Logger.LogInformation("Partition: {partition}, Offset: {offset}", record.Partition, record.Offset);
            Logger.LogInformation("Produced at: {timestamp}", record.Timestamp);
            
            foreach (var header in record.Headers.DecodedValues())
            {
                Logger.LogInformation($"{header.Key}: {header.Value}");
            }
            
            Logger.LogInformation("Processing order for: {fullName}", record.Value.FullName);
        }
    
        return "Processed " + records.Count() + " records";
    }
}
```

------

## 스키마 레지스트리의 인증 방법
<a name="services-consume-kafka-events-auth"></a>

 스키마 레지스트리를 사용하려면 Lambda가 스키마 레지스트리에 안전하게 액세스할 수 있어야 합니다. AWS Glue 스키마 레지스트리로 작업하는 경우 Lambda는 IAM 인증을 사용합니다. 즉, AWS Glue 레지스트리에 액세스하려면 함수의 [실행 역할](lambda-intro-execution-role.md)에 다음 권한이 있어야 합니다.
+ *AWS Glue 웹 API 참조*의 [GetRegistry](https://docs.aws.amazon.com/glue/latest/webapi/API_GetRegistry.html)
+ *AWS Glue 웹 API 참조*의 [GetSchemaVersion](https://docs.aws.amazon.com/glue/latest/webapi/API_GetSchemaVersion.html)

필요한 IAM 정책의 예: 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "glue:GetRegistry",
                "glue:GetSchemaVersion"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

------

**참고**  
 AWS Glue 스키마 레지스트리의 경우 AWS Glue 레지스트리에 `AccessConfigs`를 제공하면 Lambda가 검증 예외를 반환합니다.

Confluent 스키마 레지스트리로 작업하는 경우 [KafkaSchemaRegistryAccessConfig](https://docs.aws.amazon.com/lambda/latest/api/API_KafkaSchemaRegistryAccessConfig) 객체의 `Type` 파라미터에 대해 지원되는 세 가지 인증 방법 중 하나를 선택할 수 있습니다.
+ **BASIC\$1AUTH** - Lambda가 사용자 이름과 암호 또는 API 키 및 API 시크릿 인증을 사용하여 레지스트리에 액세스합니다. 이 옵션을 선택하는 경우 URI 필드에 자격 증명이 포함된 Secrets Manager ARN을 제공합니다.
+ **CLIENT\$1CERTIFICATE\$1TLS\$1AUTH** - Lambda가 클라이언트 인증서와 상호 TLS 인증을 사용합니다. 이 옵션을 사용하려면 Lambda가 인증서와 프라이빗 키 모두에 액세스할 수 있어야 합니다. URI 필드에 이러한 자격 증명이 포함된 Secrets Manager ARN을 제공합니다.
+ **NO\$1AUTH** - 퍼블릭 CA 인증서는 Lambda 신뢰 저장소에 있는 인증 기관(CA)에서 서명해야 합니다. 프라이빗 CA/자체 서명 인증서의 경우 서버 루트 CA 인증서를 구성합니다. 이 옵션을 사용하려면 `AccessConfigs` 파라미터를 생략합니다.

 또한 Lambda가 스키마 레지스트리의 TLS 인증서를 확인하기 위해 Private CA Certificate에 액세스해야 하는 경우 `Type`으로 `SERVER_ROOT_CA_CERT`를 선택하고 URI 필드에 인증서에 대한 Secrets Manager ARN을 입력합니다.

**참고**  
 콘솔에서 `SERVER_ROOT_CA_CERT` 옵션을 구성하려면 **암호화** 필드에 인증서가 포함된 시크릿 ARN을 입력합니다.

 스키마 레지스트리의 인증 구성은 Kafka 클러스터에 대해 구성한 인증과 별개입니다. 유사한 인증 방법을 사용하더라도 둘 다 별도로 구성해야 합니다.

## 스키마 레지스트리 문제에 대한 오류 처리 및 문제 해결
<a name="services-consume-kafka-events-troubleshooting"></a>

Amazon MSK 이벤트 소스와 함께 스키마 레지스트리를 사용하는 경우 다양한 오류가 발생할 수 있습니다. 이 섹션에서는 일반적인 문제와 해결 방법에 대한 지침을 제공합니다.

### 구성 오류
<a name="consume-kafka-events-troubleshooting-configuration-errors"></a>

이러한 오류는 스키마 레지스트리 구성을 설정할 때 발생합니다.

프로비저닝된 모드 필요  
**오류 메시지**: `SchemaRegistryConfig is only available for Provisioned Mode. To configure Schema Registry, please enable Provisioned Mode by specifying MinimumPollers in ProvisionedPollerConfig.`  
**해결 방법:** `ProvisionedPollerConfig`에서 `MinimumPollers` 파라미터를 구성하여 이벤트 소스 매핑에 대해 프로비저닝된 모드를 활성화합니다.

잘못된 스키마 레지스트리 URL  
**오류 메시지**: `Malformed SchemaRegistryURI provided. Please provide a valid URI or ARN. For example, https://schema-registry.example.com:8081 or arn:aws:glue:us-east-1:123456789012:registry/ExampleRegistry.`  
**해결 방법:** Confluent 스키마 레지스트리에 유효한 HTTPS URL이나 AWS Glue 스키마 레지스트리에 유효한 ARN을 제공합니다.

잘못되었거나 누락된 이벤트 레코드 형식  
**오류 메시지**: `EventRecordFormat is a required field for SchemaRegistryConfig. Please provide one of supported format types: SOURCE, JSON.`  
**해결 방법:** 스키마 레지스트리 구성에서 EventRecordFormat으로 SOURCE나 JSON을 지정합니다.

중복 검증 속성  
**오류 메시지**: `Duplicate KEY/VALUE Attribute in SchemaValidationConfigs. SchemaValidationConfigs must contain at most one KEY/VALUE Attribute.`  
**해결 방법:** SchemaValidationConfigs에서 중복된 KEY 또는 VALUE 속성을 제거합니다. 각 속성 유형은 한 번만 나타날 수 있습니다.

누락된 검증 구성  
**오류 메시지**: `SchemaValidationConfigs is a required field for SchemaRegistryConfig.`  
**해결 방법:** 하나 이상의 검증 속성(KEY 또는 VALUE)을 지정하여 구성에 SchemaValidationConfigs를 추가합니다.

### 액세스 및 권한 오류
<a name="consume-kafka-events-troubleshooting-access-errors"></a>

이러한 오류는 Lambda가 권한 또는 인증 문제로 인해 스키마 레지스트리에 액세스할 수 없을 때 발생합니다.

AWS Glue 스키마 레지스트리 액세스 거부됨  
**오류 메시지**: `Cannot access Glue Schema with provided role. Please ensure the provided role can perform the GetRegistry and GetSchemaVersion Actions on your schema.`  
**해결 방법:** 함수의 실행 역할에 필요한 권한(`glue:GetRegistry` 및 `glue:GetSchemaVersion`)을 추가합니다.

Confluent 스키마 레지스트리 액세스 거부됨  
**오류 메시지**: `Cannot access Confluent Schema with the provided access configuration.`  
**해결 방법:** Secrets Manager에 저장된 인증 자격 증명이 올바르고 스키마 레지스트리에 액세스하는 데 필요한 권한이 있는지 확인합니다.

교차 계정 AWS Glue 스키마 레지스트리  
**오류 메시지**: `Cross-account Glue Schema Registry ARN not supported.`  
**해결 방법:** Lambda 함수와 동일한 AWS 계정에 있는 AWS Glue 스키마 레지스트리를 사용합니다.

교차 리전 AWS Glue 스키마 레지스트리  
**오류 메시지**: `Cross-region Glue Schema Registry ARN not supported.`  
**해결 방법:** Lambda 함수와 동일한 리전에 있는 AWS Glue 스키마 레지스트리를 사용합니다.

시크릿 액세스 문제  
**오류 메시지**: `Lambda received InvalidRequestException from Secrets Manager.`  
**해결 방법:** 함수의 실행 역할에 시크릿에 액세스할 수 있는 권한이 있고 다른 계정에서 액세스하는 경우 시크릿이 기본 AWS KMS 키로 암호화되지 않았는지 확인합니다.

### 연결 오류
<a name="consume-kafka-events-troubleshooting-connection-errors"></a>

이러한 오류는 Lambda가 스키마 레지스트리에 대한 연결을 설정할 수 없을 때 발생합니다.

VPC 연결 문제  
**오류 메시지**: `Cannot connect to your Schema Registry. Your Kafka cluster's VPC must be able to connect to the schema registry. You can provide access by configuring AWS PrivateLink or a NAT Gateway or VPC Peering between Kafka Cluster VPC and the schema registry VPC.`  
**해결 방법:** AWS PrivateLink, NAT 게이트웨이 또는 VPC 피어링을 사용하여 스키마 레지스트리에 대한 연결을 허용하도록 VPC 네트워킹을 구성합니다.

TLS 핸드셰이크 실패  
**오류 메시지**: `Unable to establish TLS handshake with the schema registry. Please provide correct CA-certificate or client certificate using Secrets Manager to access your schema registry.`  
**해결 방법:** Secrets Manager에서 CA 인증서와 클라이언트 인증서(mTLS용)가 올바르고 적절하게 구성되었는지 확인합니다.

Throttling  
**오류 메시지**: `Receiving throttling errors when accessing the schema registry. Please increase API TPS limits for your schema registry.`  
**해결 방법:** 스키마 레지스트리의 API 속도 제한을 늘리거나 애플리케이션의 요청 속도를 줄입니다.

자체 관리형 스키마 레지스트리 오류  
**오류 메시지**: `Lambda received an internal server an unexpected error from the provided self-managed schema registry.`  
**해결 방법:** 자체 관리형 스키마 레지스트리 서버의 상태와 구성을 확인합니다.

# Kafka 이벤트 소스의 저지연 처리
<a name="with-kafka-low-latency"></a>

AWS Lambda는 100밀리초 미만의 일관된 종단 간 지연 시간이 요구되는 애플리케이션에 대해 저지연 이벤트 처리를 기본적으로 지원합니다. 이 페이지에서는 지연 시간이 짧은 워크플로를 활성화하기 위한 구성 세부 정보와 권장 사항을 제공합니다.

## 저지연 처리 활성화
<a name="enable-low-latency"></a>

Kafka 이벤트 소스 매핑에서 저지연 처리를 활성화하려면 다음과 같은 기본 구성이 필요합니다.
+ 프로비저닝된 모드를 활성화합니다. 자세한 내용은 [프로비저닝된 모드](kafka-scaling-modes.md#kafka-provisioned-mode) 섹션을 참조하세요.
+ 이벤트 소스 매핑의 `MaximumBatchingWindowInSeconds` 파라미터를 0으로 설정합니다. 자세한 내용은 [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching) 섹션을 참조하세요.

## 지연 시간이 짧은 Kafka ESM 미세 조정
<a name="recommendations-low-latency"></a>

짧은 지연 시간을 위해 Kafka 이벤트 소스 매핑을 최적화하려면 다음 권장 사항을 고려하세요.

### 프로비저닝 모드 구성
<a name="recommendations-pollers"></a>

Kafka 이벤트 소스 매핑을 위해 프로비저닝 모드에서 Lambda를 사용하면 **이벤트 폴러**라는 리소스의 최소 및 최대 개수를 구성하여 이벤트 소스 매핑의 처리량을 미세 조정할 수 있습니다. 이벤트 폴러(또는 **폴러**)는 프로비저닝 모드에서 이벤트 소스 매핑을 뒷받침하고 최대 5MB/s의 처리량을 할당하는 컴퓨팅 리소스를 의미합니다. 각 이벤트 폴러는 최대 5개의 동시 Lambda 간접 호출을 지원합니다.

애플리케이션에 대한 최적의 폴러 구성을 결정할 때 최대 수집 속도와 처리 요구 사항을 고려하세요. 간소화된 예시를 살펴보겠습니다.

배치 크기가 레코드 20개이고 대상 함수의 평균 시간이 50ms인 경우 각 폴러는 5MB/s 제한에 따라 초당 2,000개의 레코드를 처리할 수 있습니다. 이는 (레코드 20개 × 1,000ms/50ms) × 동시 Lambda 간접 호출 5개로 계산됩니다. 따라서 원하는 최대 수집 속도가 초당 20,000개의 레코드인 경우 최소 10개의 이벤트 폴러가 필요합니다.

**참고**  
지속적으로 최대 용량으로 작동하지 않도록 버퍼용 이벤트 폴러를 추가로 프로비저닝하는 것이 좋습니다.

프로비저닝된 모드는 구성된 최소 및 최대 **이벤트 폴러** 내에서 트래픽 패턴에 따라 이벤트 폴러를 자동으로 조정하므로 리밸런싱을 트리거할 수 있으며 이에 따라 추가 지연 시간이 발생할 수 있습니다. 최소 및 최대 **이벤트 폴러**에 대해 동일한 값을 구성하여 오토 스케일링을 비활성화할 수 있습니다.

### 추가 고려 사항
<a name="additional-considerations-low-latency"></a>

몇 가지 추가 고려 사항은 다음과 같습니다.
+ Lambda 대상 함수를 간접 호출하여 콜드 스타트를 수행하면 종단 간 지연 시간이 늘어날 수 있습니다. 이 위험을 줄이려면 이벤트 소스 매핑의 대상 함수에서 [프로비저닝된 동시성](provisioned-concurrency.md) 또는 [SnapStart](snapstart.md)를 활성화하는 것이 좋습니다. 또한 함수의 메모리 할당을 최적화하여 일관된 최적의 실행을 보장합니다.
+ `MaximumBatchingWindowInSeconds`가 0으로 설정되면 Lambda가 전체 배치 크기를 채울 때까지 기다리지 않고 사용 가능한 레코드를 즉시 처리합니다. 예를 들어 배치 크기가 레코드 1,000개로 설정되었지만 레코드 100개만 사용할 수 있는 경우 Lambda는 전체 1,000개의 레코드가 누적될 때까지 기다리지 않고 해당 레코드 100개를 즉시 처리합니다.

**중요**  
저지연 처리를 위한 최적의 구성은 특정 워크로드에 따라 크게 달라집니다. 실제 워크로드로 다양한 구성을 테스트하여 사용 사례에 가장 적합한 설정을 결정하는 것이 좋습니다.

# Kafka 이벤트 소스의 오류 처리 제어 구성
<a name="kafka-retry-configurations"></a>

Lambda가 오류를 처리하고 Kafka 이벤트 소스 매핑을 재시도하는 방법을 구성할 수 있습니다. 이러한 구성을 통해 Lambda가 실패한 레코드를 처리하고 재시도 동작을 관리하는 방식을 제어할 수 있습니다.

## 사용 가능한 재시도 구성
<a name="kafka-retry-options"></a>

Amazon MSK 및 자체 관리형 Kafka 이벤트 소스 모두에 다음 재시도 구성을 사용할 수 있습니다.
+ **최대 재시도 횟수** - 함수가 오류를 반환할 때 Lambda에서 재시도하는 최대 횟수입니다. 최초 간접 호출 시도는 포함되지 않습니다. 기본값은 -1(무제한)입니다. 무한 재시도와 [실패 시 대상](kafka-on-failure-destination.md)을 모두 구성하면 Lambda에서는 자동으로 최대 10회의 재시도를 적용합니다.
+ **최대 레코드 사용 기간** – Lambda에서 함수로 보내는 최대 레코드 사용 기간입니다. 기본값은 -1(무제한)입니다.
+ **오류 시 배치 분할** - 함수에서 오류가 반환되면 배치를 두 개의 작은 배치로 분할하고 각각을 개별적으로 다시 시도합니다. 문제가 있는 레코드를 격리하는 데 도움이 됩니다.
+ **부분 배치 응답** - Lambda가 실패한 레코드만 재시도할 수 있도록 함수에서 배치 처리 실패 레코드 관련 정보 반환을 허용합니다.

## 오류 처리 제어 구성(콘솔)
<a name="kafka-retry-console"></a>

Lambda 콘솔에서 Kafka 이벤트 소스 매핑을 생성하거나 업데이트할 때 재시도 동작을 구성할 수 있습니다.

**Kafka 이벤트 소스의 재시도 동작 구성(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 함수 이름을 선택합니다.

1. 다음 중 하나를 수행하세요.
   + 새 Kafka 트리거를 추가하려면 **함수 개요**에서 **트리거 추가**를 선택합니다.
   + 기존 Kafka 트리거를 수정하려면 트리거를 선택하고 **편집**을 선택합니다.

1. **이벤트 폴러 구성**에서 프로비저닝 모드를 선택하여 오류 처리 제어를 구성합니다.

   1. **재시도 시도 횟수**에 최대 재시도 횟수(0\$110,000 또는 무제한으로 시도하려면 -1)를 입력합니다.

   1. **최대 레코드 사용 기간**에 최대 사용 기간을 초 단위로 입력합니다(60\$1604,800 또는 무제한의 경우 -1).

   1. 오류가 발생할 때 배치 분할을 활성화하려면 **오류 시 배치 분할**을 선택합니다.

   1. 부분 배치 응답을 활성화하려면 **ReportBatchItemFailures**를 선택합니다.

1. **추가** 또는 **저장**을 선택합니다.

## 재시도 동작 구성(AWS CLI)
<a name="kafka-retry-cli"></a>

다음 AWS CLI 명령을 사용하여 Kafka 이벤트 소스 매핑의 재시도 동작을 구성합니다.

### 재시도 구성 포함 이벤트 소스 매핑 생성
<a name="kafka-retry-cli-create"></a>

다음 예시에서는 오류 처리 제어가 포함된 자체 관리형 Kafka 이벤트 소스 매핑을 생성합니다.

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics my-kafka-topic \
  --source-access-configuration Type=SASL_SCRAM_512_AUTH,URI=arn:aws:secretsmanager:us-east-1:111122223333:secret:MyBrokerSecretName \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc.xyz.com:9092"]}}' \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=1 \
  --maximum-retry-attempts 3 \
  --maximum-record-age-in-seconds 3600 \
  --bisect-batch-on-function-error \
  --function-response-types "ReportBatchItemFailures"
```

Amazon MSK 이벤트 소스의 경우는 다음과 같습니다.

```
aws lambda create-event-source-mapping \
  --event-source-arn arn:aws:kafka:us-east-1:111122223333:cluster/my-cluster/fc2f5bdf-fd1b-45ad-85dd-15b4a5a6247e-2 \
  --topics AWSMSKKafkaTopic \
  --starting-position LATEST \
  --function-name my-kafka-function \
  --source-access-configurations '[{"Type": "SASL_SCRAM_512_AUTH","URI": "arn:aws:secretsmanager:us-east-1:111122223333:secret:my-secret"}]' \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=1 \
  --maximum-retry-attempts 3 \
  --maximum-record-age-in-seconds 3600 \
  --bisect-batch-on-function-error \
  --function-response-types "ReportBatchItemFailures"
```

### 재시도 구성 업데이트
<a name="kafka-retry-cli-update"></a>

`update-event-source-mapping` 명령을 사용하여 기존 이벤트 소스 매핑의 재시도 구성을 수정합니다.

```
aws lambda update-event-source-mapping \
  --uuid 12345678-1234-1234-1234-123456789012 \
  --maximum-retry-attempts 5 \
  --maximum-record-age-in-seconds 7200 \
  --bisect-batch-on-function-error \
  --function-response-types "ReportBatchItemFailures"
```

## PartialBatchResponse
<a name="kafka-partial-batch-response"></a>

ReportBatchItemFailures라고도 하는 부분 배치 응답은 Lambda와 Kafka 소스의 통합에서 오류를 처리하는 주요 기능입니다. 이 기능이 없으면 배치의 항목 중 하나에서 오류가 발생할 때 해당 배치의 모든 메시지가 재처리됩니다. 부분 배치 응답이 활성화 및 구현된 경우 핸들러는 실패한 메시지의 식별자만 반환하므로 Lambda는 해당되는 특정 메시지만 재시도할 수 있습니다. 이를 통해 실패한 메시지가 포함된 배치가 처리되는 방식을 더 효과적으로 제어할 수 있습니다.

배치 오류를 보고하려면 다음 JSON 스키마를 사용합니다.

```
{
  "batchItemFailures": [
    {
      "itemIdentifier": {
        "partition": "topic-partition_number",
        "offset": 100
      }
    },
    ...
  ]
}
```

**중요**  
유효한 빈 JSON 또는 null을 반환하면 이벤트 소스 매핑은 배치가 성공적으로 처리되었다고 간주합니다. 간접 호출된 이벤트에 존재하지 않은 잘못된 topic-partition\$1number 또는 offset이 반환되면 실패로 처리되고 전체 배치를 재시도합니다.

다음 코드 예제에서는 Kafka 소스에서 이벤트를 수신하는 Lambda 함수에 대한 부분 배치 응답을 구현하는 방법을 보여줍니다. 이 함수는 응답으로 배치 항목 실패를 보고하고 나중에 해당 메시지를 다시 시도하도록 Lambda에 신호를 보냅니다.

다음은 이 접근 방식을 보여주는 Python Lambda 핸들러 구현입니다.

```
import base64
from typing import Any, Dict, List

def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, List[Dict[str, Dict[str, Any]]]]:
    failures: List[Dict[str, Dict[str, Any]]] = []
    records_dict = event.get("records", {})
    
    for topic_partition, records_list in records_dict.items():
        for record in records_list:
            topic = record.get("topic")
            partition = record.get("partition")
            offset = record.get("offset")
            value_b64 = record.get("value")
            
            try:
                data = base64.b64decode(value_b64).decode("utf-8")
                process_message(data)
            except Exception as exc:
                print(f"Failed to process record topic={topic} partition={partition} offset={offset}: {exc}")
                item_identifier: Dict[str, Any] = {
                    "partition": f"{topic}-{partition}",
                    "offset": int(offset) if offset is not None else None,
                }
                failures.append({"itemIdentifier": item_identifier})
    
    return {"batchItemFailures": failures}

def process_message(data: str) -> None:
    # Your business logic for a single message
    pass
```

다음은 Node.js 버전입니다.

```
const { Buffer } = require("buffer");

const handler = async (event) => {
  const failures = [];
  
  for (let topicPartition in event.records) {
    const records = event.records[topicPartition];
    
    for (const record of records) {
      const topic = record.topic;
      const partition = record.partition;
      const offset = record.offset;
      const valueBase64 = record.value;
      const data = Buffer.from(valueBase64, "base64").toString("utf8");
      
      try {
        await processMessage(data);
      } catch (error) {
        console.error("Failed to process record", { topic, partition, offset, error });
        const itemIdentifier = {
          "partition": `${topic}-${partition}`,
          "offset": Number(offset),
        };
        failures.push({ itemIdentifier });
      }
    }
  }
  
  return { batchItemFailures: failures };
};

async function processMessage(payload) {
  // Your business logic for a single message
}

module.exports = { handler };
```

# Amazon MSK 및 자체 관리형 Apache Kafka 이벤트 소스에 대한 폐기된 배치 캡처
<a name="kafka-on-failure"></a>

실패한 이벤트 소스 매핑 간접 호출 기록을 보관하려면 함수의 이벤트 소스 매핑에 대상을 추가합니다. 대상으로 전송된 각 레코드는 실패한 간접 호출에 대한 메타데이터를 포함하는 JSON 문서입니다. Amazon S3 대상의 경우 Lambda는 메타데이터와 함께 전체 간접 호출 레코드를 전송합니다. 모든 Amazon SNS 주제, Amazon SQS 대기열, Amazon S3 버킷 또는 Kafka를 대상으로 구성할 수 있습니다.

Amazon S3 대상을 사용하면 [Amazon S3 이벤트 알림](https://docs.aws.amazon.com/) 기능을 통해 객체를 대상 S3 버킷에 업로드할 때 알림을 받을 수 있습니다. 실패한 배치에서 자동 처리를 수행하기 위해 다른 Lambda 함수를 간접 호출하도록 S3 이벤트 알림을 구성할 수도 있습니다.

실행 역할에 대상에 대한 권한이 있어야 합니다.
+ **SQS 대상:** [sqs:SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)
+ **SNS 대상:** [sns:Publish](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html)
+ **S3 대상:** [s3:PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 및 [s3:ListBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/ListObjectsV2.html)
+ **Kafka 대상:** [kafka-cluster:WriteData](https://docs.aws.amazon.com/msk/latest/developerguide/kafka-actions.html)

Kafka 주제를 Kafka 이벤트 소스 매핑의 실패 시 대상으로 구성할 수 있습니다. Lambda가 재시도 횟수를 소진한 후 레코드를 처리할 수 없거나 레코드가 최대 수명을 초과하는 경우 Lambda는 나중에 처리할 수 있도록 실패한 레코드를 지정된 Kafka 주제로 보냅니다. 자세한 내용은 [Kafka 주제를 실패 시 대상으로 사용](kafka-on-failure-destination.md) 항목을 참조하세요.

장애 시 대상 서비스를 위한 VPC 엔드포인트를 Kafka 클러스터 VPC 내에 배포해야 합니다.

또한 대상에 KMS 키를 구성한 경우 대상 유형에 따라 Lambda에는 다음과 같은 권한이 필요합니다.
+ S3 대상에 대해 자체 KMS 키를 사용하여 암호화를 활성화한 경우 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)가 필요합니다. KMS 키와 S3 버킷 대상이 Lambda 함수 및 실행 역할과 다른 계정에 있는 경우 실행 역할을 신뢰하도록 KMS 키를 구성하여 kms:GenerateDataKey를 허용합니다.
+ SQS 대상에 대해 자체 KMS 키를 사용하여 암호화를 활성화한 경우 [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) 및 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)가 필요합니다. KMS 키와 SQS 대기열 대상이 Lambda 함수 및 실행 역할과 다른 계정에 있는 경우 실행 역할을 신뢰하도록 KMS 키를 구성하여 [kms:DescribeKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_DescribeKey.html) 및 [kms:ReEncrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html)를 허용합니다.
+ SNS 대상에 대해 자체 KMS 키를 사용하여 암호화를 활성화한 경우 [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) 및 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)가 필요합니다. KMS 키와 SNS 주제 대상이 Lambda 함수 및 실행 역할과 다른 계정에 있는 경우 실행 역할을 신뢰하도록 KMS 키를 구성하여 [kms:DescribeKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_DescribeKey.html) 및 [kms:ReEncrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html)를 허용합니다.

## MSK 이벤트 소스 매핑에 대한 장애 시 대상 구성
<a name="kafka-onfailure-destination"></a>

이 콘솔을 사용하여 장애 시 대상을 구성하려면 다음 단계를 따르세요.

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 함수를 선택합니다.

1. **함수 개요(Function overview)**에서 **대상 추가(Add destination)**를 선택합니다.

1. **소스**의 경우 **이벤트 소스 매핑 간접 호출**을 선택합니다.

1. **이벤트 소스 매핑**의 경우 이 함수에 대해 구성된 이벤트 소스를 선택합니다.

1. **조건**의 경우 **실패 시**를 선택합니다. 이벤트 소스 매핑 간접 호출의 경우 이 조건만 수락됩니다.

1. **대상 유형**의 경우 Lambda가 간접 호출 레코드를 전송할 대상 유형을 선택합니다.

1. **Destination(대상)**에서 리소스를 선택합니다.

1. **저장**을 선택합니다.

AWS CLI를 사용하여 장애 시 대상을 구성할 수도 있습니다. 예를 들어, 다음 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 명령은 SQS 장애 시 대상이 있는 이벤트 소스 매핑을 `MyFunction`에 추가합니다.

```
aws lambda create-event-source-mapping \
--function-name "MyFunction" \
--event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/751d2973-a626-431c-9d4e-d7975eb44dd7-2 \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sqs:us-east-1:123456789012:dest-queue"}}'
```

다음 [update-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 명령은 `uuid` 입력과 연결된 이벤트 소스에 S3 장애 시 대상을 추가합니다.

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--destination-config '{"OnFailure": {"Destination": "arn:aws:s3:::dest-bucket"}}'
```

대상을 제거하려면 `destination-config` 파라미터의 인수로 빈 문자열을 제공합니다.

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--destination-config '{"OnFailure": {"Destination": ""}}'
```

### Amazon S3에 대한 보안 모범 사례
<a name="kafka-s3-destination-security"></a>

함수 구성에서 대상을 제거하지 않고 대상으로 구성된 S3 버킷을 삭제하면 보안 위험이 초래될 수 있습니다. 사용자의 대상 버킷 이름을 다른 사용자가 알고 있는 경우 AWS 계정에서 버킷을 다시 생성할 수 있습니다. 실패한 간접 호출에 대한 레코드가 해당 버킷으로 전송되어 함수의 데이터가 공개될 수 있습니다.

**주의**  
함수의 간접 호출 레코드를 다른 AWS 계정의 S3 버킷으로 전송할 수 없도록 하려면 계정의 버킷에 대한 `s3:PutObject` 권한을 제한하는 조건을 함수의 실행 역할에 추가합니다.

다음 예제에서는 함수의 `s3:PutObject` 권한을 계정의 버킷으로 제한하는 IAM 정책을 보여줍니다. 또한 이 정책에서는 Lambda가 S3 버킷을 대상으로 사용하는 데 필요한 `s3:ListBucket` 권한도 부여합니다.

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "S3BucketResourceAccountWrite",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::*/*",
                "arn:aws:s3:::*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:ResourceAccount": "111122223333"
                }
            }
        }
    ]
}
```

AWS Management Console 또는 AWS CLI를 사용하여 함수의 실행 역할에 권한 정책을 추가하려면 다음 절차의 지침을 참조하세요.

------
#### [ Console ]

**함수의 실행 역할에 권한 정책을 추가하는 방법(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 실행 역할을 수정하려는 Lambda 함수를 선택하세요.

1. **구성** 탭을 선택한 다음 **사용 권한**을 선택합니다.

1. **실행 역할** 탭에서 함수의 **역할 이름**을 선택하여 역할의 IAM 콘솔 페이지를 여세요.

1. 다음을 수행하여 역할에 기본 권한 정책을 추가하세요.

   1. **권한** 창에서 **권한 추가**를 선택하고 **인라인 정책 생성**을 선택하세요.

   1. **정책 편집기**에서 **JSON**을 선택하세요.

   1. 추가하려는 정책을 편집기에 붙여넣고(이때 기존 JSON 대체) **다음**을 선택하세요.

   1. **정책 세부 정보** 아래에 **정책 이름**을 입력하세요.

   1. **정책 생성**을 선택합니다.

------
#### [ AWS CLI ]

**함수의 실행 역할에 권한 정책을 추가하는 방법(CLI)**

1. 필요한 권한이 있는 JSON 정책 문서를 생성하고 로컬 디렉터리에 저장하세요.

1. IAM `put-role-policy` CLI 명령을 사용하여 함수의 실행 역할에 권한을 추가하세요. JSON 정책 문서를 저장한 디렉터리에서 다음 명령을 실행하고 역할 이름, 정책 이름 및 정책 문서를 고유한 값으로 바꾸세요.

   ```
   aws iam put-role-policy \
   --role-name my_lambda_role \
   --policy-name LambdaS3DestinationPolicy \
   --policy-document file://my_policy.json
   ```

------

### SNS 및 SQS 예제 간접 호출 레코드
<a name="kafka-sns-sqs-destinations"></a>

다음 예는 실패한 Kafka 이벤트 소스 간접 호출에 대해 Lambda가 SNS 주제 또는 SQS 대기열 대상으로 전송하는 내용을 보여줍니다. `recordsInfo` 아래의 각 키에는 하이픈으로 구분된 Kafka 주제와 파티션이 모두 포함되어 있습니다. 예를 들어, `"Topic-0"` 키의 경우 `Topic`은 Kafka 주제이고 `0`은 파티션입니다. 각 주제 및 파티션에 대해 오프셋과 타임스탬프 데이터를 사용하여 원래의 간접 호출 레코드를 찾을 수 있습니다.

```
{
    "requestContext": {
        "requestId": "316aa6d0-8154-xmpl-9af7-85d5f4a6bc81",
        "functionArn": "arn:aws:lambda:us-east-1:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted" | "MaximumPayloadSizeExceeded",
        "approximateInvokeCount": 1
    },
    "responseContext": { // null if record is MaximumPayloadSizeExceeded
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:38:06.021Z",
    "KafkaBatchInfo": {
        "batchSize": 500,
        "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/751d2973-a626-431c-9d4e-d7975eb44dd7-2",
        "bootstrapServers": "...",
        "payloadSize": 2039086, // In bytes
        "recordsInfo": {
            "Topic-0": {
                "firstRecordOffset": "49601189658422359378836298521827638475320189012309704722",
                "lastRecordOffset": "49601189658422359378836298522902373528957594348623495186",
                "firstRecordTimestamp": "2019-11-14T00:38:04.835Z",
                "lastRecordTimestamp": "2019-11-14T00:38:05.580Z",
            },
            "Topic-1": {
                "firstRecordOffset": "49601189658422359378836298521827638475320189012309704722",
                "lastRecordOffset": "49601189658422359378836298522902373528957594348623495186",
                "firstRecordTimestamp": "2019-11-14T00:38:04.835Z",
                "lastRecordTimestamp": "2019-11-14T00:38:05.580Z",
            }
        }
    }
}
```

### S3 대상 예제 간접 호출 레코드
<a name="kafka-s3-destinations"></a>

S3 대상의 경우, Lambda는 메타데이터와 함께 전체 간접 호출 레코드를 대상으로 전송합니다. 다음 예는 실패한 Kafka 이벤트 소스 간접 호출에 대해 Lambda가 SNS 주제 또는 S3 버킷 대상으로 전송하는 것을 보여줍니다. SQS 및 SNS 대상에 대한 이전 예제의 모든 필드 외에도 `payload` 필드에는 원래 간접 호출 레코드가 이스케이프된 JSON 문자열로 포함되어 있습니다.

```
{
    "requestContext": {
        "requestId": "316aa6d0-8154-xmpl-9af7-85d5f4a6bc81",
        "functionArn": "arn:aws:lambda:us-east-1:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted" | "MaximumPayloadSizeExceeded",
        "approximateInvokeCount": 1
    },
    "responseContext": { // null if record is MaximumPayloadSizeExceeded
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:38:06.021Z",
    "KafkaBatchInfo": {
        "batchSize": 500,
        "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/vpc-2priv-2pub/751d2973-a626-431c-9d4e-d7975eb44dd7-2",
        "bootstrapServers": "...",
        "payloadSize": 2039086, // In bytes
        "recordsInfo": {
            "Topic-0": {
                "firstRecordOffset": "49601189658422359378836298521827638475320189012309704722",
                "lastRecordOffset": "49601189658422359378836298522902373528957594348623495186",
                "firstRecordTimestamp": "2019-11-14T00:38:04.835Z",
                "lastRecordTimestamp": "2019-11-14T00:38:05.580Z",
            },
            "Topic-1": {
                "firstRecordOffset": "49601189658422359378836298521827638475320189012309704722",
                "lastRecordOffset": "49601189658422359378836298522902373528957594348623495186",
                "firstRecordTimestamp": "2019-11-14T00:38:04.835Z",
                "lastRecordTimestamp": "2019-11-14T00:38:05.580Z",
            }
        }
    },
    "payload": "<Whole Event>" // Only available in S3
}
```

**작은 정보**  
대상 버킷에서 S3 버전 관리를 활성화하는 것이 좋습니다.

# Kafka 주제를 실패 시 대상으로 사용
<a name="kafka-on-failure-destination"></a>

Kafka 주제를 Kafka 이벤트 소스 매핑의 실패 시 대상으로 구성할 수 있습니다. Lambda가 재시도 횟수를 소진한 후 레코드를 처리할 수 없거나 레코드가 최대 수명을 초과하는 경우 Lambda는 나중에 처리할 수 있도록 실패한 레코드를 지정된 Kafka 주제로 보냅니다. [무한 재시도](kafka-retry-configurations.md)와 실패 시 대상을 모두 구성하면 Lambda에서는 자동으로 최대 10회의 재시도를 적용합니다.

## Kafka 실패 시 대상 작동 방식
<a name="kafka-ofd-overview"></a>

Kafka 주제를 실패 시 대상으로 구성하면 Lambda는 Kafka 생산자 역할을 하고 실패한 레코드를 대상 주제에 기록합니다. 그러면 Kafka 인프라 내에 배달 못한 편지 주제(DLT) 패턴이 생성됩니다.
+ **동일한 클러스터 요구 사항** - 대상 주제는 소스 주제와 동일한 Kafka 클러스터에 있어야 합니다.
+ **실제 레코드 콘텐츠** - Kafka 대상은 실패 메타데이터와 함께 실제로 실패한 레코드를 수신합니다.
+ **재귀 방지** - Lambda는 소스 및 대상 주제가 동일한 구성을 차단하여 무한 루프를 방지합니다.

## Kafka 실패 시 대상 구성
<a name="kafka-ofd-configure"></a>

Kafka 이벤트 소스 매핑을 생성하거나 업데이트할 때 Kafka 주제를 실패 시 대상으로 구성할 수 있습니다.

### Kafka 대상 구성(콘솔)
<a name="kafka-ofd-console"></a>

**Kafka 주제를 실패 시 대상으로 구성(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 함수 이름을 선택합니다.

1. 다음 중 하나를 수행하세요.
   + 새 Kafka 트리거를 추가하려면 **함수 개요**에서 **트리거 추가**를 선택합니다.
   + 기존 Kafka 트리거를 수정하려면 트리거를 선택하고 **편집**을 선택합니다.

1. **추가 설정**의 **실패 시 대상**에서 **Kafka 주제**를 선택합니다.

1. **주제 이름**에 실패한 레코드를 전송할 Kafka 주제의 이름을 입력합니다.

1. **추가** 또는 **저장**을 선택합니다.

### Kafka 대상 구성(AWS CLI)
<a name="kafka-ofd-cli"></a>

`kafka://` 접두사를 사용하여 Kafka 주제를 실패 시 대상으로 지정합니다.

#### Kafka 대상을 사용하여 이벤트 소스 매핑 생성
<a name="kafka-ofd-cli-create"></a>

다음 예제에서는 Kafka 주제를 실패 시 대상으로 사용하여 Amazon MSK 이벤트 소스 매핑을 생성합니다.

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics AWSKafkaTopic \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/abc123 \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=3 \
  --destination-config '{"OnFailure":{"Destination":"kafka://failed-records-topic"}}'
```

자체 관리형 Kafka의 경우 동일한 구문을 사용합니다.

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics AWSKafkaTopic \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc.xyz.com:9092"]}}' \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=3 \
  --destination-config '{"OnFailure":{"Destination":"kafka://failed-records-topic"}}'
```

#### Kafka 대상 업데이트
<a name="kafka-ofd-cli-update"></a>

`update-event-source-mapping` 명령을 사용하여 Kafka 대상을 추가 또는 수정합니다.

```
aws lambda update-event-source-mapping \
  --uuid 12345678-1234-1234-1234-123456789012 \
  --destination-config '{"OnFailure":{"Destination":"kafka://failed-records-topic"}}'
```

## Kafka 대상의 레코드 형식
<a name="kafka-ofd-record-format"></a>

Lambda가 실패한 레코드를 Kafka 주제로 전송할 때 각 메시지에는 실패에 대한 메타데이터와 실제 레코드 콘텐츠가 모두 포함됩니다.

### 실패 메타데이터
<a name="kafka-ofd-metadata"></a>

메타데이터에는 레코드가 실패한 이유에 대한 정보와 원본 배치에 대한 세부 정보가 포함됩니다.

```
{
  "requestContext": {
    "requestId": "e4b46cbf-b738-xmpl-8880-a18cdf61200e",
    "functionArn": "arn:aws:lambda:us-east-1:123456789012:function:my-function:$LATEST",
    "condition": "RetriesExhausted",
    "approximateInvokeCount": 3
  },
  "responseContext": {
    "statusCode": 200,
    "executedVersion": "$LATEST",
    "functionError": "Unhandled"
  },
  "version": "1.0",
  "timestamp": "2019-11-14T18:16:05.568Z",
  "KafkaBatchInfo": {
    "batchSize": 1,
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/abc123",
    "bootstrapServers": "b-1.mycluster.abc123.kafka.us-east-1.amazonaws.com:9098",
    "payloadSize": 1162,
    "recordInfo": {
      "offset": "49601189658422359378836298521827638475320189012309704722",
      "timestamp": "2019-11-14T18:16:04.835Z"
    }
  },
  "payload": {
    "bootstrapServers": "b-1.mycluster.abc123.kafka.us-east-1.amazonaws.com:9098",
    "eventSource": "aws:kafka",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/abc123",
    "records": {
      "my-topic-0": [
        {
          "headers": [],
          "key": "dGVzdC1rZXk=",
          "offset": 100,
          "partition": 0,
          "timestamp": 1749116692330,
          "timestampType": "CREATE_TIME",
          "topic": "my-topic",
          "value": "dGVzdC12YWx1ZQ=="
        }
      ]
    }
  }
}
```

### 파티션 키 동작
<a name="kafka-ofd-partitioning"></a>

Lambda는 대상 주제에 생성할 때 원본 레코드와 동일한 파티션 키를 사용합니다. 원본 레코드에 키가 없는 경우 Lambda는 대상 주제에서 사용 가능한 모든 파티션에 대해 Kafka의 기본 라운드 로빈 파티셔닝을 사용합니다.

## 요구 사항 및 제한 사항
<a name="kafka-ofd-requirements"></a>
+ **프로비저닝 모드 필요** - Kafka 실패 시 대상은 프로비저닝 모드가 활성화된 이벤트 소스 매핑에만 사용할 수 있습니다.
+ **동일한 클러스터만** - 대상 주제는 소스 주제와 동일한 Kafka 클러스터에 있어야 합니다.
+ **주제 권한** - 이벤트 소스 매핑에는 대상 주제에 대한 쓰기 권한이 있어야 합니다. 예제:

  ```
  {
      "Version": "2012-10-17",		 	 	 
      "Statement": [
          {
              "Sid": "ClusterPermissions",
              "Effect": "Allow",
              "Action": [
                  "kafka-cluster:Connect",
                  "kafka-cluster:DescribeCluster",
                  "kafka-cluster:DescribeTopic",
                  "kafka-cluster:WriteData",
                  "kafka-cluster:ReadData"
              ],
              "Resource": [
                  "arn:aws:kafka:*:*:cluster/*"
              ]
          },
          {
              "Sid": "TopicPermissions",
              "Effect": "Allow",
              "Action": [
                  "kafka-cluster:DescribeTopic",
                  "kafka-cluster:WriteData",
                  "kafka-cluster:ReadData"
              ],
              "Resource": [
                  "arn:aws:kafka:*:*:topic/*/*"
              ]
          },
          {
              "Effect": "Allow",
              "Action": [
                  "kafka:DescribeCluster",
                  "kafka:GetBootstrapBrokers",
                  "kafka:Produce"
              ],
              "Resource": "arn:aws:kafka:*:*:cluster/*"
          },
          {
              "Effect": "Allow",
              "Action": [
                  "ec2:CreateNetworkInterface",
                  "ec2:DescribeNetworkInterfaces",
                  "ec2:DeleteNetworkInterface",
                  "ec2:DescribeSubnets",
                  "ec2:DescribeSecurityGroups"
              ],
              "Resource": "*"
          }
      ]
  }
  ```
+ **재귀 없음** - 대상 주제 이름은 소스 주제 이름과 같을 수 없습니다.

# Kafka 이벤트 소스 매핑 로깅
<a name="esm-logging"></a>

Lambda 이벤트 폴러가 CloudWatch로 전송하는 시스템 로그를 활성화하고 필터링하도록 Kafka 이벤트 소스 매핑에 대한 시스템 수준 로깅을 구성할 수 있습니다.

이 기능은 [프로비저닝된 모드](https://docs.aws.amazon.com/lambda/latest/dg/kafka-scaling-modes.html#kafka-provisioned-mode)를 사용하는 Kafka 이벤트 소스 매핑에만 사용 가능합니다.

로깅 구성을 사용한 이벤트 소스 매핑의 경우, 지금 콘솔 **Lambda** > **추가 리소스** > **이벤트 소스 매핑** 페이지의 **모니터** 탭에서 사전 구축된 로그 쿼리의 시스템 로그를 확인할 수도 있습니다.

## 로깅 작동 방식
<a name="esm-logging-overview"></a>

이벤트 소스 매핑에서 로그 수준으로 로깅 구성을 설정하면 Lambda 이벤트 폴러가 해당 로그(이벤트 소스 매핑 시스템 로그)를 전송합니다.

이벤트 소스 매핑은 Lambda 함수와 동일한 [로그 대상](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-logs.html#configuring-log-destinations)을 재사용합니다. Lambda 함수의 실행 역할에 필요한 로깅 권한이 있어야 합니다.

이벤트 소스 매핑에는 `2020/01/01/12345678-1234-1234-1234-12345678901`과 같은 로그 스트림 이름으로 날짜 및 이벤트 소스 매핑 UUID가 포함된 자체 로그 스트림이 있습니다.

이벤트 소스 매핑 시스템 로그의 경우 다음 로그 수준 중에서 선택할 수 있습니다.


| 로그 수준 | 사용법 | 
| --- | --- | 
| DEBUG(최대 세부 정보) | 이벤트 소스 처리 진행 상황에 대한 세부 정보 | 
| INFO | 이벤트 소스 매핑 정상 작동에 대한 메시지 | 
| WARN(최소 세부 정보) | 예기치 않은 동작으로 이어질 수 있는 잠재적 오류에 대한 메시지 | 

로그 수준을 선택하면 Lambda 이벤트 폴러는 해당 수준 이하의 로그를 전송합니다. 예를 들어, 이벤트 소스 매핑 시스템 로그 수준을 INFO로 설정하면 이벤트 폴러는 DEBUG 수준에서 로그 출력을 전송하지 않습니다.

## 로깅 구성
<a name="esm-logging-configure"></a>

Kafka 이벤트 소스 매핑을 생성 또는 업데이트할 때 로깅 구성을 설정할 수 있습니다.

### 로깅 구성(콘솔)
<a name="esm-logging-console"></a>

**로깅을 구성하려면(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 함수 이름을 선택합니다.

1. 다음 중 하나를 수행하세요.
   + 새 Kafka 트리거를 추가하려면 **함수 개요**에서 **트리거 추가**를 선택합니다.
   + 기존 Kafka 트리거를 수정하려면 트리거를 선택하고 **편집**을 선택합니다.

1. **이벤트 폴러 구성**의 **프로비저닝된 모드**에서 **구성** 확인란을 선택합니다. 그러면 **로그 수준** 설정이 나타납니다.

1.  **로그 수준** 드롭다운 목록을 클릭하고 이벤트 소스 매핑의 수준을 선택합니다.

1. 맨 아래에서 **추가** 또는 **저장**을 선택하여 이벤트 소스 매핑을 생성하거나 업데이트합니다.

### 로깅 구성(AWS CLI)
<a name="esm-logging-cli"></a>

#### 로깅을 사용하여 이벤트 소스 매핑 생성
<a name="esm-logging-cli-create"></a>

다음 예제에서는 로깅 구성을 사용하여 Amazon MSK 이벤트 소스 매핑을 생성합니다.

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics AWSKafkaTopic \
  --event-source-arn arn:aws:kafka:us-east-1:123456789012:cluster/my-cluster/abc123 \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=3 \
  --logging-config '{"SystemLogLevel":"DEBUG"}'
```

자체 관리형 Kafka의 경우 동일한 구문을 사용합니다.

```
aws lambda create-event-source-mapping \
  --function-name my-kafka-function \
  --topics AWSKafkaTopic \
  --self-managed-event-source '{"Endpoints":{"KAFKA_BOOTSTRAP_SERVERS":["abc.xyz.com:9092"]}}' \
  --starting-position LATEST \
  --provisioned-poller-config MinimumPollers=1,MaximumPollers=3 \
  --logging-config '{"SystemLogLevel":"DEBUG"}'
```

#### 로깅 구성 업데이트
<a name="esm-logging-cli-update"></a>

`update-event-source-mapping` 명령을 사용하여 로깅 구성을 추가 또는 수정합니다.

```
aws lambda update-event-source-mapping \
  --uuid 12345678-1234-1234-1234-123456789012 \
  --logging-config '{"SystemLogLevel":"WARN"}'
```

## Kafka 이벤트 소스 매핑 시스템 로그의 레코드 형식
<a name="esm-logging-record-format"></a>

Lambda 이벤트 폴러가 로그를 전송할 때 각 로그 항목에는 일반 이벤트 소스 매핑 메타데이터뿐 아니라 이벤트별 콘텐츠도 포함됩니다.

### WARN 로그 레코드
<a name="esm-logging-warn-record"></a>

WARN 레코드에는 이벤트 폴러의 오류 또는 경고가 포함되며, 이 레코드는 이벤트가 발생할 때 출력됩니다. 예제:

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1546347650000,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:12345678-1234-1234-1234-123456789012",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/tests-cluster/87654321-4321-4321-4321-876543221-s1",
    "eventProcessorId": "12345678-1234-1234-1234-123456789012/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "Timeout expired while fetching topic metadata",
        "errorCode": "org.apache.kafka.common.errors.TimeoutException"
    }
}
```

### INFO 로그 레코드
<a name="esm-logging-info-record"></a>

INFO 레코드에는 각 이벤트 폴러의 Kafka 소비자 클라이언트 구성이 포함되며, 이 레코드는 소비자가 빌드 또는 변경될 때 출력됩니다. 예제:

```
{
    "eventType": "POLLER_STATUS_EVENT",
    "timestamp": 1546347660000,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:12345678-1234-1234-1234-123456789012",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/tests-cluster/87654321-4321-4321-4321-876543221-s1",
    "eventProcessorId": "12345678-1234-1234-1234-123456789012/0",
    "logLevel": "INFO",
    "kafkaEventSourceConnection": {
        "brokerEndpoints": "boot-abcd1234.c2.kafka-serverless.us-east-1.amazonaws.com:9098",
        "consumerId": "12345678-1234-1234-1234-123456789012-0",
        "topics": [
            "test"
        ],
        "consumerGroupId": "12345678-1234-1234-1234-123456789012",
        "securityProtocol": "SASL_SSL",
        "saslMechanism": "AWS_MSK_IAM",
        "totalPartitionCount": 2,
        "assignedPartitionCount": 2,
        "partitionsAssignmentGeneration": 5,
        "assignedPartitions": [
            "test-0",
            "test-1"
        ],
        "networkConfig": {
            "ipAddresses": [
                "10.100.141.1"
            ],
            "subnetCidrBlock": "10.100.128.0/20",
            "securityGroups": [
                "sg-abcdefabcdefabcdef"
            ]
        }
    }
}
```

### DEBUG 로그 레코드
<a name="esm-logging-debug-record"></a>

DEBUG 로그에는 이벤트 소스 매핑 처리의 Kafka 오프셋 관련 정보가 포함되며, 오프셋 정보는 1분마다 출력됩니다. 예제:

```
{
    "eventType": "KAFKA_STATUS_EVENT",
    "timestamp": 1546347670000,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:12345678-1234-1234-1234-123456789012",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/tests-cluster/87654321-4321-4321-4321-876543221-s1",
    "eventProcessorId": "12345678-1234-1234-1234-123456789012/0",
    "logLevel": "DEBUG",
    "kafkaPartitionOffsets": {
        "partition": "test-1",
        "endOffset": 5004,
        "consumedOffset": 5003,
        "processedOffset": 5003,
        "committedOffset": 5004
    }
}
```

# Kafka 이벤트 소스 매핑 오류 문제 해결
<a name="with-kafka-troubleshoot"></a>

다음 주제에서는 Amazon MSK 또는 자체 관리형 Apache Kafka를 Lambda와 사용할 때 발생할 수 있는 오류 및 문제에 대한 문제 해결 조언을 제공합니다.

[문제 해결에 대한 추가 지원이 필요하면 AWS 지식 센터를 방문하십시오.](https://repost.aws/knowledge-center#AWS_Lambda)

## 인증 및 권한 부여 오류
<a name="kafka-permissions-errors"></a>

Kafka 클러스터의 데이터를 사용하는 데 필요한 권한이 누락된 경우 Lambda는 **LastProcessingResult** 아래의 이벤트 소스 매핑에 다음 오류 메시지 중 하나를 표시합니다.

**Topics**
+ [

### 클러스터가 Lambda를 인증하지 못함
](#kafka-authorize-errors)
+ [

### SASL 인증 실패
](#kafka-sasl-errors)
+ [

### 서버가 Lambda를 인증하지 못함
](#kafka-mtls-errors-server)
+ [

### Lambda가 서버를 인증하지 못함
](#kafka-mtls-errors-lambda)
+ [

### 제공된 인증서 또는 프라이빗 키가 잘못됨
](#kafka-key-errors)

### 클러스터가 Lambda를 인증하지 못함
<a name="kafka-authorize-errors"></a>

SASL/SCRAM 또는 mMTS의 경우 이 오류는 제공된 사용자에게 다음 필수 Kafka 액세스 제어 목록(ACL) 권한이 모두 있지는 않음을 나타냅니다.
+ DescribeConfigs 클러스터
+ 그룹 설명
+ 그룹 읽기
+ 주제 설명
+ Thread-Topic

필수 `kafka-cluster` 권한으로 Kafka ACL을 생성할 때 주제와 그룹을 리소스로 지정합니다. 주제 이름은 이벤트 소스 매핑의 주제와 일치해야 합니다. 그룹 이름은 이벤트 소스 매핑의 UUID와 일치해야 합니다.

실행 역할에 필요한 권한을 추가한 후 변경 사항이 적용되기까지 몇 분 정도 소요될 수 있습니다.

다음은 이 문제에 대해 [로깅 구성](esm-logging.md)을 활성화한 후 ESM 시스템 수준 로그의 예입니다.

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567890123,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE11111-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "Not authorized to access topics: [my-topic]",
        "errorCode": "org.apache.kafka.common.errors.TopicAuthorizationException"
    }
}
```

### SASL 인증 실패
<a name="kafka-sasl-errors"></a>

SASL/SCRAM 또는 SASL/PLAIN의 경우 이 오류는 제공된 로그인 자격 증명이 유효하지 않음을 나타냅니다.

IAM 액세스 제어의 경우 실행 역할에 클러스터에 대한 `kafka-cluster:Connect` 권한이 없습니다. 역할에 이 권한을 추가하고 클러스터의 Amazon 리소스 이름(ARN)을 리소스로 지정합니다.

이 오류가 간헐적으로 발생하는 경우가 있습니다. TCP 연결 수가 서비스 할당량을 초과하면 클러스터는 연결을 거부합니다. Lambda는 연결이 성공할 때까지 취소하고 다시 시도합니다. Lambda가 클러스터에 연결하고 레코드를 폴링하면 마지막 처리 결과가 `OK`로 변경됩니다.

다음은 IAM 인증을 사용하는 경우 이 문제에 대해 [로깅 구성](esm-logging.md)을 활성화한 후 ESM 시스템 수준 로그의 예입니다.

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567890456,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE22222",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE22222-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE22222/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "[a1b2c3d4-5678-90ab-cdef-EXAMPLE22222]: Access denied",
        "errorCode": "org.apache.kafka.common.errors.SaslAuthenticationException"
    }
}
```

### 서버가 Lambda를 인증하지 못함
<a name="kafka-mtls-errors-server"></a>

이 오류는 Kafka 브로커가 Lambda를 인증하지 못했음을 나타냅니다. 이 오류는 다음과 같은 이유로 발생할 수 있습니다.
+ mTLS 인증을 위한 클라이언트 인증서를 제공하지 않았습니다.
+ 클라이언트 인증서를 제공했지만 Kafka 브로커가 mTLS 인증을 사용하도록 구성되지 않았습니다.
+ Kafka 브로커가 클라이언트 인증서를 신뢰하지 않습니다.

### Lambda가 서버를 인증하지 못함
<a name="kafka-mtls-errors-lambda"></a>

이 오류는 Lambda가 Kafka 브로커를 인증하지 못했음을 나타냅니다. 이 오류는 다음과 같은 이유로 발생할 수 있습니다.
+ 자체 관리형 Apache Kafka의 경우: Kafka 브로커는 자체 서명 인증서 또는 사설 CA를 사용하지만 서버 루트 CA 인증서를 제공하지 않았습니다.
+ 자체 관리형 Apache Kafka의 경우: 서버 루트 CA 인증서가 브로커 인증서에 서명한 루트 CA와 일치하지 않습니다.
+ 브로커의 인증서에 브로커의 DNS 이름 또는 IP 주소가 주체 대체 이름으로 포함되어 있지 않기 때문에 호스트 이름 검증에 실패했습니다.

### 제공된 인증서 또는 프라이빗 키가 잘못됨
<a name="kafka-key-errors"></a>

이 오류는 Kafka 소비자가 제공된 인증서 또는 프라이빗 키를 사용할 수 없음을 나타냅니다. 인증서와 키가 PEM 형식을 사용하고 프라이빗 키 암호화가 PBES1 알고리즘을 사용하는지 확인합니다.

다음은 이 문제에 대해 [로깅 구성](esm-logging.md)을 활성화한 후 ESM 시스템 수준 로그의 예입니다.

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567891234,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE44444",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE44444-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE44444/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "Invalid PEM keystore configs",
        "errorCode": "org.apache.kafka.common.errors.InvalidConfigurationException"
    }
}
```

## 네트워크 및 연결 오류
<a name="kafka-network-errors"></a>

네트워크 구성 문제로 인해 Lambda가 Kafka 클러스터에 연결하지 못할 수 있습니다. 다음 주제에서는 일반적인 네트워크 관련 오류에 대해 설명합니다.

**Topics**
+ [

### 보안 그룹 구성으로 인한 연결 시간 초과
](#kafka-security-group-errors)
+ [

### Kafka 브로커 엔드포인트를 확인할 수 없음
](#kafka-cluster-deleted-errors)

### 보안 그룹 구성으로 인한 연결 시간 초과
<a name="kafka-security-group-errors"></a>

Kafka 클러스터와 연결된 보안 그룹이 자신으로부터의 인바운드 트래픽을 허용하지 않는 경우 Lambda가 클러스터에 연결할 수 없습니다. 보안 그룹의 인바운드 규칙이 Kafka 브로커 포트에서 보안 그룹 자체로부터의 트래픽을 허용하는지 확인하세요.

다음은 이 문제에 대해 [로깅 구성](esm-logging.md)을 활성화한 후 ESM 시스템 수준 로그의 예입니다.

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567892345,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE55555",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE55555-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE55555/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "Timeout expired while fetching topic metadata",
        "errorCode": "org.apache.kafka.common.errors.TimeoutException"
    }
}
```

또한 Kafka 소비자 INFO 로그를 확인하여 연결 및 네트워크 구성을 확인할 수도 있습니다. `brokerEndpoints` 필드에는 Kafka 브로커 주소가 표시되고, `securityProtocol` 및 `saslMechanism`(해당하는 경우)에는 인증 방법이 표시되고, `networkConfig` 필드에는 이벤트 소스 매핑에 사용되는 IP 주소, 서브넷 CIDR 블록, 보안 그룹이 표시됩니다. 나열된 보안 그룹이 필요한 인바운드 트래픽을 허용하는지 확인하세요.

```
{
    "eventType": "POLLER_STATUS_EVENT",
    "timestamp": 1734567892456,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-11111EXAMPLE",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/a1b2c3d4-5678-90ab-cdef-11111EXAMPLE-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE/0",
    "logLevel": "INFO",
    "kafkaEventSourceConnection": {
        "brokerEndpoints": "boot-abcd1234.c2.kafka-serverless.us-east-1.amazonaws.com:9098",
        "consumerId": "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE-0",
        "topics": [
            "my-topic"
        ],
        "consumerGroupId": "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE",
        "securityProtocol": "SASL_SSL",
        "saslMechanism": "AWS_MSK_IAM",
        "totalPartitionCount": 2,
        "assignedPartitionCount": 2,
        "partitionsAssignmentGeneration": 1,
        "assignedPartitions": [
            "my-topic-0",
            "my-topic-1"
        ],
        "networkConfig": {
            "ipAddresses": [
                "10.0.0.37"
            ],
            "subnetCidrBlock": "10.0.0.32/28",
            "securityGroups": [
                "sg-0123456789abcdef0"
            ]
        }
    }
}
```

### Kafka 브로커 엔드포인트를 확인할 수 없음
<a name="kafka-cluster-deleted-errors"></a>

이 오류는 Kafka 클러스터가 존재하지 않거나 삭제되었음을 나타냅니다. 이벤트 소스 매핑에 지정된 클러스터가 존재하고 활성 상태인지 확인하세요.

다음은 이 문제에 대해 [로깅 구성](esm-logging.md)을 활성화한 후 ESM 시스템 수준 로그의 예입니다.

```
{
    "eventType": "ESM_PROCESSING_EVENT",
    "timestamp": 1734567893456,
    "resourceArn": "arn:aws:lambda:us-east-1:123456789012:event-source-mapping:a1b2c3d4-5678-90ab-cdef-EXAMPLE66666",
    "eventSourceArn": "arn:aws:kafka:us-east-1:123456789012:cluster/my-kafka-cluster/12345678-abcd-1234-efgh-EXAMPLE66666-1",
    "eventProcessorId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE66666/0",
    "logLevel": "WARN",
    "error": {
        "errorMessage": "No resolvable bootstrap urls given in bootstrap.servers",
        "errorCode": "org.apache.kafka.common.config.ConfigException"
    }
}
```

## 이벤트 소스 매핑 오류
<a name="services-event-errors"></a>

Lambda 함수의 [이벤트 소스](invocation-eventsourcemapping.md)로 Apache Kafka 클러스터를 추가한 경우 함수에 오류가 발생하면 Kafka 소비자가 레코드 처리를 중지합니다. 토픽 파티션의 소비자는 레코드를 구독하고, 읽고, 처리하는 소비자입니다. 다른 Kafka 소비자는 동일한 오류가 발생하지 않는 한 레코드 처리를 계속할 수 있습니다.

중지된 소비자의 원인을 확인하려면 `StateTransitionReason` 응답의 `EventSourceMapping` 필드를 확인하세요. 다음 목록에는 발생할 수 있는 이벤트 소스 오류가 나왔습니다.

**`ESM_CONFIG_NOT_VALID`**  
이벤트 소스 매핑 구성이 잘못되었습니다.

**`EVENT_SOURCE_AUTHN_ERROR`**  
Lambda가 이벤트 소스를 인증하지 못했습니다.

**`EVENT_SOURCE_AUTHZ_ERROR`**  
Lambda에 이벤트 소스에 액세스하는 데 필요한 권한이 없습니다.

**`FUNCTION_CONFIG_NOT_VALID`**  
함수의 구성이 유효하지 않습니다.

**참고**  
Lambda 이벤트 레코드가 허용되는 크기 제한인 6MB를 초과하면 처리되지 않을 수 있습니다.

# Amazon API Gateway 엔드포인트를 사용하여 간접적으로 Lambda 함수 호출
<a name="services-apigateway"></a>

Amazon API Gateway를 사용하여 웹API와 Lambda 함수의 HTTP 엔드포인트를 생성할 수 있습니다. API Gateway는 HTTP 요청을 Lambda 함수로 라우팅하는 웹 API를 생성하고 문서화하는 도구를 제공합니다. 인증 및 승인 제어를 통해 API에 대한 액세스를 보호할 수 있습니다. API는 인터넷을 통해 트래픽을 처리하거나 VPC 내에서만 액세스할 수 있습니다.

**작은 정보**  
Lambda는 HTTP 엔드포인트를 통해 함수를 간접적으로 호출하는 두 가지 방법인 API 게이트웨이와 Lambda 함수 URL을 제공합니다. 사용 사례에 가장 적합한 방법을 잘 모르는 경우 [HTTP 요청을 사용하여 Lambda 함수를 간접 호출하는 메서드 선택](apig-http-invoke-decision.md) 섹션을 참조하세요.

API의 리소스는 GET 또는 POST와 같은 하나 이상의 메서드를 정의합니다. 메서드에는 요청을 Lambda 함수 또는 다른 통합 유형으로 라우팅하는 통합이 있습니다. 각 리소스와 메서드를 개별적으로 정의하거나 특수 리소스 및 메서드 유형을 사용하여 패턴에 맞는 모든 요청을 일치시킬 수 있습니다. [프록시 리소스](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html)는 리소스 아래의 모든 경로를 포착합니다. `ANY` 메서드는 모든 HTTP 메서드를 포착합니다.

**Topics**
+ [

## API 유형 선택
](#services-apigateway-apitypes)
+ [

## Lambda 함수에 엔드포인트 추가
](#apigateway-add)
+ [

## 프록시 통합
](#apigateway-proxy)
+ [

## 이벤트 형식
](#apigateway-example-event)
+ [

## 응답 형식
](#apigateway-types-transforms)
+ [

## 권한
](#apigateway-permissions)
+ [

## 샘플 애플리케이션
](#services-apigateway-samples)
+ [

## Powertools for AWS Lambda의 이벤트 핸들러
](#services-apigateway-powertools)
+ [

# 자습서: API Gateway에서 Lambda 사용
](services-apigateway-tutorial.md)
+ [

# API Gateway API를 사용한 Lambda 오류 처리
](services-apigateway-errors.md)
+ [

# HTTP 요청을 사용하여 Lambda 함수를 간접 호출하는 메서드 선택
](apig-http-invoke-decision.md)

## API 유형 선택
<a name="services-apigateway-apitypes"></a>

API Gateway는 Lambda 함수를 간접 호출하는 세 가지 유형의 API를 지원합니다.
+ [HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html): 가볍고 대기 시간이 짧은 RESTful API입니다.
+ [REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html): 사용자 지정 가능하고 기능이 풍부한 RESTful API입니다.
+ [WebSocket API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html): 전이중 통신을 위해 클라이언트와의 지속적인 연결을 유지하는 웹 API입니다.

HTTP API와 REST API는 모두 HTTP 요청을 처리하고 응답을 반환하는 RESTful API입니다. HTTP API는 최신 버전이며 API Gateway 버전 2 API로 빌드되었습니다. HTTP API의 새로운 기능은 다음과 같습니다.

**HTTP API 기능**
+ **자동 배포** – 경로 또는 통합을 수정하면 자동 배포가 활성화된 단계에 변경 내용이 자동으로 배포됩니다.
+ **기본 단계** – API URL의 루트 경로에서 요청을 처리하는 기본 단계(`$default`)를 만들 수 있습니다. 명명된 단계의 경우 경로 시작 부분에 단계 이름을 포함해야 합니다.
+ **CORS 구성** – CORS 헤더를 함수 코드에 수동으로 추가하는 대신 발신 응답에 추가하도록 API를 구성할 수 있습니다.

REST API는 출시 이후 API Gateway가 지원한 클래식 RESTful API입니다. REST API에는 현재 더 많은 사용자 지정, 통합 및 관리 기능이 있습니다.

**REST API 기능**
+ **통합 유형** – REST API는 사용자 지정 Lambda 통합을 지원합니다. 사용자 지정 통합을 사용하면 요청 본문만 함수로 전송하거나 변환 템플릿을 요청 본문에 적용한 후에 함수로 전송할 수 있습니다.
+ **액세스 제어** – REST API는 인증 및 승인에 대한 더 많은 옵션을 지원합니다.
+ **모니터링 및 추적** – REST API는 AWS X-Ray 추적 및 추가 로깅 옵션을 지원합니다.

자세한 비교는 *API Gateway 개발자 안내서*의 [HTTP API와 REST API 중에서 선택](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html)을 참조하세요.

또한 WebSocket API는 API Gateway 버전 2 API를 사용하고 유사한 기능 세트를 지원합니다. 클라이언트와 API 간의 지속적인 연결을 활용하는 애플리케이션에 대해 WebSocket API를 사용합니다. WebSocket API는 전이중 통신을 제공하므로 클라이언트와 API 모두 응답을 기다리지 않고 지속적으로 메시지를 전송할 수 있습니다.

HTTP API는 간소화된 이벤트 형식(버전 2.0)을 지원합니다. HTTP API의 이벤트 예제는 [API Gateway에서 HTTP API에 대한 AWS Lambda 프록시 통합 생성](https://docs.aws.amazon.com//apigateway/latest/developerguide/http-api-develop-integrations-lambda.html)을 참조하세요.

자세한 내용은 [API Gateway에서 HTTP API에 대한 AWS Lambda 프록시 통합 생성](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html)을 참조하세요.

## Lambda 함수에 엔드포인트 추가
<a name="apigateway-add"></a>

**Lambda 함수에 퍼블릭 엔드포인트를 추가하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 함수를 선택합니다.

1. **함수 개요(Function overview)**에서 **트리거 추가(Add trigger)**를 선택합니다.

1. **API 게이트웨이(API Gateway)**를 선택합니다.

1. **API 생성(Create an API)** 혹은 **기존 API 사용(Use an existing API)**을 선택합니다.

   1. **새 API:****API 유형**에서 **HTTP API**를 선택합니다. 자세한 내용은 [API 유형 선택](#services-apigateway-apitypes) 섹션을 참조하세요.

   1. **기존 API:** 드롭다운 목록에서 API를 선택하거나 API ID(예: r3pmxmplak)를 입력합니다.

1. **Security(보안)**에서 **Open(열기)**을 선택합니다.

1. **추가**를 선택합니다.

## 프록시 통합
<a name="apigateway-proxy"></a>

API Gateway API는 스테이지, 리소스, 메서드 및 통합으로 구성됩니다. 스테이지와 리소스가 엔드포인트의 경로를 결정합니다.

**API 경로 형식**
+ `/prod/` – `prod` 스테이지 및 루트 리소스입니다.
+ `/prod/user` – `prod` 스테이지 및 `user` 리소스입니다.
+ `/dev/{proxy+}` – `dev` 스테이지의 모든 경로입니다.
+ `/` – (HTTP API) 기본 스테이지 및 루트 리소스입니다.

Lambda 통합은 경로와 HTTP 메서드 조합을 Lambda 함수에 매핑합니다. HTTP 요청의 본문을 있는 그대로 전달하거나(사용자 지정 통합) 헤더, 리소스, 경로 및 메서드를 비롯한 모든 요청 정보가 포함된 문서에 요청 본문을 캡슐화하도록 API Gateway를 구성할 수 있습니다.

자세한 내용은 [API Gateway의 Lambda 프록시 통합](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html)을 참조하세요.

## 이벤트 형식
<a name="apigateway-example-event"></a>

Amazon API Gateway는 HTTP 요청의 JSON 표현을 포함하는 이벤트와 [동기적으로](invocation-sync.md) 함수를 간접 호출합니다. 사용자 지정 통합의 경우 이벤트는 요청 본문입니다. 프록시 통합의 경우 이벤트의 구조가 정의되어 있습니다. API Gateway REST API의 프록시 이벤트 예제는 *API Gateway 개발자 안내서*의 [프록시 통합에 대한 Lambda 함수의 입력 형식](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format)을 참조하세요.

## 응답 형식
<a name="apigateway-types-transforms"></a>

API Gateway는 함수의 응답을 기다렸다가 결과를 호출자에게 중계합니다. 사용자 지정 통합의 경우 함수의 출력을 HTTP 응답으로 변환하는 통합 응답 및 메서드 응답을 정의합니다. 프록시 통합의 경우 함수는 특정 형식의 응답 표현으로 응답해야 합니다.

다음 예제는 Node.js 함수의 응답 객체를 보여줍니다. 응답 객체는 JSON 문서를 포함하는 성공적인 HTTP 응답을 나타냅니다.

**Example index.mjs – 프록시 통합 응답 객체(Node.js)**  

```
var response = {
      "statusCode": 200,
      "headers": {
        "Content-Type": "application/json"
      },
      "isBase64Encoded": false,
      "multiValueHeaders": { 
        "X-Custom-Header": ["My value", "My other value"],
      },
      "body": "{\n  \"TotalCodeSize\": 104330022,\n  \"FunctionCount\": 26\n}"
    }
```

Lambda 런타임은 응답 객체를 JSON으로 직렬화하여 API로 전송합니다. API는 응답을 구문 분석하고 이를 사용하여 HTTP 응답을 만든 다음 원래 요청을 한 클라이언트로 보냅니다.

**Example HTTP 응답**  

```
< HTTP/1.1 200 OK
  < Content-Type: application/json
  < Content-Length: 55
  < Connection: keep-alive
  < x-amzn-RequestId: 32998fea-xmpl-4268-8c72-16138d629356
  < X-Custom-Header: My value
  < X-Custom-Header: My other value
  < X-Amzn-Trace-Id: Root=1-5e6aa925-ccecxmplbae116148e52f036
  <
  {
    "TotalCodeSize": 104330022,
    "FunctionCount": 26
  }
```

## 권한
<a name="apigateway-permissions"></a>

Amazon API Gateway는 함수의 [리소스 기반 정책](access-control-resource-based.md)에서 함수를 간접 호출하는 권한을 가져옵니다. 전체 API에 간접 호출 권한을 부여하거나 스테이지, 리소스 또는 메서드에 제한된 액세스 권한을 부여할 수 있습니다.

Lambda 콘솔, API Gateway 콘솔 또는 AWS SAM 템플릿을 사용하여 API를 함수에 추가할 때 함수의 리소스 기반 정책이 자동으로 업데이트됩니다. 다음은 함수 정책의 예입니다.

**Example 함수 정책**    
****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Id": "default",
  "Statement": [
    {
      "Sid": "nodejs-apig-functiongetEndpointPermissionProd-BWDBXMPLXE2F",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-2:111122223333:function:nodejs-apig-function-1G3MXMPLXVXYI",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "111122223333"
        },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:execute-api:us-east-2:111122223333:ktyvxmpls1/*/GET/"
        }
      }
    }
  ]
}
```

다음 API 작업을 사용하여 함수 정책 권한을 수동으로 관리할 수 있습니다.
+ [AddPermission](https://docs.aws.amazon.com/lambda/latest/api/API_AddPermission.html)
+ [RemovePermission](https://docs.aws.amazon.com/lambda/latest/api/API_RemovePermission.html)
+ [GetPolicy](https://docs.aws.amazon.com/lambda/latest/api/API_GetPolicy.html)

기존 API에 호출 권한을 부여하려면 `add-permission` 명령을 사용합니다. 예제:

```
aws lambda add-permission \
  --function-name my-function \
  --statement-id apigateway-get --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:us-east-2:123456789012:mnh1xmpli7/default/GET/"
```

다음 결과가 표시됩니다.

```
{
    "Statement": "{\"Sid\":\"apigateway-test-2\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-east-2:123456789012:function:my-function\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:us-east-2:123456789012:mnh1xmpli7/default/GET\"}}}"
}
```

**참고**  
함수와 API가 다른 AWS 리전에 있는 경우 소스 ARN의 리전 식별자는 API의 리전이 아닌 함수의 리전과 일치해야 합니다. API Gateway에서 함수를 간접적으로 간접 호출하면 API의 ARN을 기반으로 하지만 함수의 리전과 일치하도록 수정된 리소스 ARN을 사용합니다.

이 예제의 소스 ARN은 ID `mnh1xmpli7`과 함께 API의 기본 단계에서 루트 리소스의 GET 메서드에 대한 통합 권한을 부여합니다. 소스 ARN에 별표를 사용하여 여러 단계, 메서드 또는 리소스에 권한을 부여할 수 있습니다.

**리소스 패턴**
+ `mnh1xmpli7/*/GET/*` – 모든 단계의 모든 리소스에 대한 GET 메서드.
+ `mnh1xmpli7/prod/ANY/user` – `prod` 스테이지의 `user` 리소스에 대한 ANY 메서드.
+ `mnh1xmpli7/*/*/*` – 모든 단계의 모든 리소스에 대한 모든 메서드.

정책 보기 및 명령문 제거에 대한 자세한 내용은 [Lambda에서 리소스 기반 IAM 정책 보기](access-control-resource-based.md) 단원을 참조하세요.

## 샘플 애플리케이션
<a name="services-apigateway-samples"></a>

[Node.js를 사용하는 API Gateway](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/nodejs-apig) 샘플 앱에는 AWS X-Ray 추적이 활성화된 REST API를 생성하는 AWS SAM 템플릿이 포함된 함수가 포함되어 있습니다. 여기에는 배포, 함수 간접 호출, API 테스트 및 정리를 위한 스크립트도 포함됩니다.

## Powertools for AWS Lambda의 이벤트 핸들러
<a name="services-apigateway-powertools"></a>

Powertools for AWS Lambda 도구 키트의 이벤트 핸들러는 API Gateway 엔드포인트(HTTP 또는 REST)에서 간접 호출한 Lambda 함수를 작성할 때 라우팅, 미들웨어, CORS 구성, OpenAPI 사양 생성, 요청 검증, 오류 처리 및 기타 유용한 기능을 제공합니다. 이벤트 핸들러 유틸리티는 Python 및 TypeScript/JavaScript에서 사용할 수 있습니다. 자세한 내용은 *Powertools for AWS Lambda(Python) 설명서*의 [이벤트 핸들러 REST API](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/) 및 *Powertools for AWS Lambda(TypeScript) 설명서*의 [이벤트 핸들러 HTTP API](https://docs.aws.amazon.com/powertools/typescript/latest/features/event-handler/http/)를 참조하세요.

### Python
<a name="services-apigateway-powertools-python"></a>

```
from aws_lambda_powertools import Logger
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing.lambda_context import LambdaContext

app = APIGatewayRestResolver()
logger = Logger()

@app.get("/healthz")
def ping():
    return {"message": "health status ok"}

@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)  
def lambda_handler(event: dict, context: LambdaContext) -> dict:
    return app.resolve(event, context)
```

### Typescript
<a name="services-apigateway-powertools-typescript"></a>

```
import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest';
import { Logger } from '@aws-lambda-powertools/logger';
import {
  correlationPaths,
  search,
} from '@aws-lambda-powertools/logger/correlationId';
import type { Context } from 'aws-lambda/handler';

const logger = new Logger({
  correlationIdSearchFn: search,
});

const app = new Router({ logger });

app.get("/healthz", async () => {
  return { message: "health status ok" };
});

export const handler = async (event: unknown, context: Context) => {
  // You can continue using other utilities just as before
  logger.addContext(context);
  logger.setCorrelationId(event, correlationPaths.API_GATEWAY_REST);
  return app.resolve(event, context);
};
```

# 자습서: API Gateway에서 Lambda 사용
<a name="services-apigateway-tutorial"></a>

이 자습서에서는 HTTP 요청을 사용하여 Lambda 함수를 간접 호출하는 REST API를 생성합니다. Lambda 함수는 DynamoDB 테이블에서 생성, 읽기, 업데이트 및 삭제(CRUD) 작업을 수행합니다. 이 함수는 여기서 데모용으로 제공되지만, 모든 Lambda 함수를 간접 호출할 수 있는 API Gateway REST API를 구성하는 방법을 배울 수 있습니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/APIG_tut_resources.png)


API Gateway를 사용하면 Lambda 함수를 간접 호출할 수 있는 안전한 HTTP 엔드포인트가 사용자에게 제공되며, 트래픽을 스로틀링하고 API 간접 호출을 자동으로 검증 및 승인하여 함수에 대한 대량의 간접 호출을 관리할 수 있습니다. 또한 API Gateway는 AWS Identity and Access Management(IAM) 및 Amazon Cognito를 사용하여 유연한 보안 제어 기능을 제공합니다. 이는 애플리케이션을 호출하기 위해 사전 승인이 필요한 사용 사례에 유용합니다.

**작은 정보**  
Lambda는 HTTP 엔드포인트를 통해 함수를 간접적으로 호출하는 두 가지 방법인 API 게이트웨이와 Lambda 함수 URL을 제공합니다. 사용 사례에 가장 적합한 방법을 잘 모르는 경우 [HTTP 요청을 사용하여 Lambda 함수를 간접 호출하는 메서드 선택](apig-http-invoke-decision.md) 섹션을 참조하세요.

이 자습서를 완료하는 과정에서 다음 단계를 거치게 됩니다.

1. Python 또는 Node.js 언어로 Lambda 함수를 생성하고 구성하여 DynamoDB 테이블에 대해 작업을 수행합니다.

1. API Gateway에서 REST API를 생성하여 Lambda 함수에 연결합니다.

1. DynamoDB 테이블을 정의한 후 콘솔에서 Lambda 함수를 사용하여 테스트합니다.

1. 터미널에서 curl을 사용하여 API를 배포하고 전체 설정을 테스트합니다.

이 단계를 완료하면 API Gateway를 사용하여 어떤 규모에서든 Lambda 함수를 안전하게 간접 호출할 수 있는 HTTP 엔드포인트를 생성하는 방법을 배우게 됩니다. 또한 API를 배포하는 방법과 콘솔에서 API를 테스트하는 방법, 그리고 터미널에서 HTTP 요청을 보내 AI를 테스트하는 방법을 배우게 됩니다.

## 권한 정책 생성
<a name="services-apigateway-tutorial-policy"></a>

Lambda 함수의 [실행 역할](lambda-intro-execution-role.md)을 생성하려면 먼저 권한 정책을 생성하여 필요한 AWS 리소스에 액세스할 권한을 함수에 부여해야 합니다. 이 자습서에서는 이 정책을 통해 Lambda가 DynamoDB 테이블에서 CRUD 작업을 수행하고 Amazon CloudWatch Logs 로그에 쓸 수 있도록 합니다.

**정책 생성**

1. IAM 콘솔에서 [정책 페이지](https://console.aws.amazon.com/iam/home#/policies)를 엽니다.

1. **정책 생성**을 선택하세요.

1. **JSON** 탭에서 다음과 같은 사용자 지정 정책을 JSON 편집기에 붙여 넣습니다.

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Sid": "Stmt1428341300017",
         "Action": [
           "dynamodb:DeleteItem",
           "dynamodb:GetItem",
           "dynamodb:PutItem",
           "dynamodb:Query",
           "dynamodb:Scan",
           "dynamodb:UpdateItem"
         ],
         "Effect": "Allow",
         "Resource": "*"
       },
       {
         "Sid": "",
         "Resource": "*",
         "Action": [
           "logs:CreateLogGroup",
           "logs:CreateLogStream",
           "logs:PutLogEvents"
         ],
         "Effect": "Allow"
       }
     ]
   }
   ```

------

1. **다음: 태그**를 선택합니다.

1. **다음: 검토(Next: Review)**를 선택합니다.

1. **정책 검토**의 **이름**에 **lambda-apigateway-policy**를 입력합니다.

1. **정책 생성**을 선택합니다.

## 실행 역할 만들기
<a name="services-apigateway-tutorial-role"></a>

[실행 역할](lambda-intro-execution-role.md)은 AWS 서비스 및 리소스에 액세스할 수 있는 권한을 Lambda 함수에 부여하는 AWS Identity and Access Management(IAM) 역할입니다. 함수가 DynamoDB 테이블에 대해 작업을 수행할 수 있도록 하려면 이전 단계에서 생성한 권한 정책을 연결합니다.

**실행 역할을 생성하고 사용자 지정 권한 정책을 연결하려면**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. **역할 생성**을 선택합니다.

1. 신뢰할 수 있는 엔터티의 유형으로 **AWS 서비스**를 선택한 다음 사용 사례로 **Lambda**를 선택합니다.

1. **다음**을 선택합니다.

1. 정책 검색 상자에 **lambda-apigateway-policy**를 입력합니다.

1. 검색 결과에서 생성한 정책(`lambda-apigateway-policy`)을 선택한 후, **다음(Next)**을 선택합니다.

1. **Role details**(역할 세부 정보)에서 **Role name**(역할 이름)에 **lambda-apigateway-role**을 입력한 다음 **Create role**(역할 생성)을 선택합니다.

## Lambda 함수 생성
<a name="services-apigateway-tutorial-function"></a>

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 열고 **함수 생성**을 선택합니다.

1. **새로 작성**을 선택합니다.

1. [**함수 이름**]에 `LambdaFunctionOverHttps`을 입력합니다.

1. **런타임**에서 최신 Node.js 또는 Python 런타임을 선택합니다.

1. **권한(Permissions)**에서 **기본 실행 역할 변경(Change default execution role)**을 확장합니다.

1. **기존 역할 사용**을 선택하고 이전에 생성한 **lambda-apigateway-role** 역할을 선택합니다.

1. **함수 생성**을 선택합니다.

1. **코드 소스** 창에서 기본 코드를 다음 Node.js 또는 Python 코드로 바꿉니다.

------
#### [ Node.js ]

   함수를 배포하고 [DynamoDB 테이블을 생성](#services-apigateway-tutorial-table)할 때 `region` 설정이 AWS 리전과 일치해야 합니다.

**Example index.mjs**  

   ```
   import { DynamoDBDocumentClient, PutCommand, GetCommand, 
            UpdateCommand, DeleteCommand} from "@aws-sdk/lib-dynamodb";
   import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
   
   const ddbClient = new DynamoDBClient({ region: "us-east-2" });
   const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);
   
   // Define the name of the DDB table to perform the CRUD operations on
   const tablename = "lambda-apigateway";
   
   /**
    * Provide an event that contains the following keys:
    *
    *   - operation: one of 'create,' 'read,' 'update,' 'delete,' or 'echo'
    *   - payload: a JSON object containing the parameters for the table item
    *     to perform the operation on
    */
   export const handler = async (event, context) => {
      
        const operation = event.operation;
      
        if (operation == 'echo'){
             return(event.payload);
        }
        
       else { 
           event.payload.TableName = tablename;
           let response;
           
           switch (operation) {
             case 'create':
                  response = await ddbDocClient.send(new PutCommand(event.payload));
                  break;
             case 'read':
                  response = await ddbDocClient.send(new GetCommand(event.payload));
                  break;
             case 'update':
                  response = ddbDocClient.send(new UpdateCommand(event.payload));
                  break;
             case 'delete':
                  response = ddbDocClient.send(new DeleteCommand(event.payload));
                  break;
             default:
               response = 'Unknown operation: ${operation}';
             }
           console.log(response);
           return response;
       }
   };
   ```

------
#### [ Python ]

**Example lambda\$1function.py**  

   ```
   import boto3
   
   # Define the DynamoDB table that Lambda will connect to
   table_name = "lambda-apigateway"
   
   # Create the DynamoDB resource
   dynamo = boto3.resource('dynamodb').Table(table_name)
   
   # Define some functions to perform the CRUD operations
   def create(payload):
       return dynamo.put_item(Item=payload['Item'])
   
   def read(payload):
       return dynamo.get_item(Key=payload['Key'])
   
   def update(payload):
       return dynamo.update_item(**{k: payload[k] for k in ['Key', 'UpdateExpression', 
       'ExpressionAttributeNames', 'ExpressionAttributeValues'] if k in payload})
   
   def delete(payload):
       return dynamo.delete_item(Key=payload['Key'])
   
   def echo(payload):
       return payload
   
   operations = {
       'create': create,
       'read': read,
       'update': update,
       'delete': delete,
       'echo': echo,
   }
   
   def lambda_handler(event, context):
       '''Provide an event that contains the following keys:
         - operation: one of the operations in the operations dict below
         - payload: a JSON object containing parameters to pass to the 
           operation being performed
       '''
       
       operation = event['operation']
       payload = event['payload']
       
       if operation in operations:
           return operations[operation](payload)
           
       else:
           raise ValueError(f'Unrecognized operation "{operation}"')
   ```

------
**참고**  
이 예제에서는 DynamoDB 테이블의 이름이 함수 코드에 변수로 정의됩니다. 실제 애플리케이션에서는 이 파라미터를 환경 변수로 전달하고 테이블 이름을 하드 코딩하지 않는 것이 좋습니다. 자세한 내용은 [AWS Lambda 환경 변수 사용](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html) 섹션을 참조하세요.

1. **배포** 섹션에서 **배포**를 선택하여 함수의 코드를 업데이트하세요.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

## 함수 테스트
<a name="services-apigateway-tutorial-test-function"></a>

함수를 API Gateway와 통합하기 전에 함수를 성공적으로 배포했는지 확인합니다. Lambda 콘솔을 사용하여 함수에 테스트 이벤트를 전송합니다.

1. 함수의 Lambda 콘솔 페이지에서 **테스트** 탭을 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/test-tab.png)

1. **이벤트 JSON** 섹션까지 아래로 스크롤하고 기본 이벤트를 다음으로 바꿉니다. 이 이벤트는 Lambda 함수에서 예상되는 구조와 일치합니다.

   ```
   {
       "operation": "echo",
       "payload": {
           "somekey1": "somevalue1",
           "somekey2": "somevalue2"
       }
   }
   ```

1. **테스트**를 선택합니다.

1. **함수 실행: 성공**에서 **세부 정보**를 확장합니다. 다음과 같은 응답이 표시되어야 합니다.

   ```
   {
     "somekey1": "somevalue1",
     "somekey2": "somevalue2"
   }
   ```

## API Gateway를 사용하여 REST API 생성
<a name="services-apigateway-tutorial-api"></a>

이 단계에서는 Lambda 함수를 간접 호출하는 데 사용할 API Gateway REST API를 생성합니다.

**API를 생성하려면**

1. [API Gateway 콘솔](https://console.aws.amazon.com/apigateway)을 엽니다.

1. **API 생성**을 선택합니다.

1. **REST API** 상자에서 **빌드**를 선택합니다.

1. **API 세부 정보**에서 **새 API**를 선택한 상태로 두고 **API 이름**에 **DynamoDBOperations**를 입력합니다.

1. **API 생성**을 선택합니다.

## REST API에서 리소스 생성
<a name="services-apigateway-tutorial-resource"></a>

API에 HTTP 메서드를 추가하려면 먼저 해당 메서드가 작동하는 데 필요한 리소스를 생성해야 합니다. 여기서는 DynamoDB 테이블을 관리하기 위한 리소스를 생성합니다.

**리소스를 생성하려면**

1. [API Gateway 콘솔](https://console.aws.amazon.com/apigateway)의 사용하는 API에 대한 **리소스** 페이지에서 **리소스 생성**을 선택합니다.

1. **리소스 세부 정보**에서 **리소스 이름**에 **DynamoDBManager**를 입력합니다.

1. **리소스 생성**을 선택합니다.

## HTTP POST 메서드 생성
<a name="services-apigateway-tutorial-method"></a>

이 단계에서는 `DynamoDBManager` 리소스의 메서드(`POST`)를 생성합니다. 이 `POST` 메서드를 Lambda 함수에 연결하여 이 메서드가 HTTP 요청을 수신하면 API Gateway가 Lambda 함수를 간접 호출하도록 합니다.

**참고**  
 이 자습서에서는 HTTP 메서드(`POST`)를 하나 사용하여 DynamoDB 테이블에 대해 모든 작업을 수행하는 단일 Lambda 함수를 간접 호출합니다. 실제 애플리케이션에서는 각 작업마다 서로 다른 Lambda 함수와 HTTP 메서드를 사용하는 것이 좋습니다. 자세한 내용은 Serverless Land의 [The Lambda monolith](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/monolith)를 참조하세요.

**POST 메서드를 생성하려면**

1. API의 **리소스** 페이지에서 `/DynamoDBManager` 리소스가 강조 표시되어 있는지 확인합니다. 그런 다음, **메서드** 창에서 **메서드 생성**을 선택하세요.

1. **메서드 유형**에서 **POST**를 선택합니다.

1. **통합 유형**에서 **Lambda 함수**를 선택한 상태로 둡니다.

1. **Lambda 함수**에서 함수의 Amazon 리소스 이름(ARN)(`LambdaFunctionOverHttps`)을 선택합니다.

1. **메서드 생성**을 선택합니다.

## DynamoDB 테이블 생성
<a name="services-apigateway-tutorial-table"></a>

Lambda 함수가 CRUD 작업을 수행할 빈 DynamoDB 테이블을 생성합니다.

**DynamoDB 테이블을 생성하려면**

1. [DynamoDB 콘솔의 테이블 페이지](https://console.aws.amazon.com/dynamodbv2#tables)를 엽니다.

1. **테이블 생성**을 선택합니다.

1. **테이블 세부 정보**에서 다음을 수행합니다.

   1. **테이블 이름**에 **lambda-apigateway**을(를) 입력합니다.

   1. **파티션 키**에서 **id**를 입력하고 데이터 유형을 **문자열**로 설정합니다.

1. **Table settings**(테이블 설정)에서 **Default settings**(기본 설정)을 그대로 둡니다.

1. **테이블 생성**을 선택합니다.

## API Gateway, Lambda 및 DynamoDB의 통합 테스트
<a name="services-apigateway-tutorial-test-setup"></a>

이제 API Gateway API 메서드와 Lambda 함수 및 DynamoDB 테이블의 통합을 테스트할 준비가 되었습니다. API Gateway 콘솔을 사용하여 콘솔의 테스트 함수를 통해 `POST` 메서드에 직접 요청을 보냅니다. 이 단계에서는 먼저 `create` 작업을 사용하여 DynamoDB 테이블에 새 항목을 추가한 다음 `update` 작업을 사용하여 해당 항목을 수정합니다.

**테스트 1: DynamoDB 테이블에 새 항목을 생성하려면**

1. [API Gateway 콘솔](https://console.aws.amazon.com/apigateway)에서 API(`DynamoDBOperations`)를 선택합니다.

1. `DynamoDBManager` 리소스에서 **POST** 메서드를 선택합니다.

1. **테스트** 탭을 선택합니다. 탭을 표시하려면 오른쪽 화살표 버튼을 선택해야 할 수도 있습니다.

1. **메서드 테스트**에서 **쿼리 문자열**과 **헤더**는 비워 둡니다. **요청 본문**에 다음 JSON을 붙여넣습니다.

   ```
   {
     "operation": "create",
     "payload": {
       "Item": {
         "id": "1234ABCD",
         "number": 5
       }
     }
   }
   ```

1. **테스트**를 선택합니다.

   테스트가 완료될 때 표시되는 결과에 `200` 상태가 표시되어야 합니다. 이 상태 코드는 `create` 작업이 성공했음을 나타냅니다.

    이를 확인하려면 DynamoDB 테이블에 새 항목이 포함되어 있는지 확인합니다.

1. DynamoDB 콘솔의 [Tables](https://console.aws.amazon.com/dynamodbv2#tables)(테이블) 페이지를 열고 `lambda-apigateway` 테이블을 선택합니다.

1. **Explore table items**(테이블 항목 탐색)를 선택합니다. **Items returned**(반환된 항목) 창에 **ID**가 `1234ABCD`이고 **number**(번호)가 `5`인 항목이 하나 표시되어야 합니다. 예제:  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/items-returned.png)

**테스트 2: DynamoDB 테이블의 항목을 업데이트하려면**

1. [API Gateway 콘솔](https://console.aws.amazon.com/apigateway)에서 POST 메서드의 **테스트** 탭으로 돌아갑니다.

1. **메서드 테스트**에서 **쿼리 문자열**과 **헤더**는 비워 둡니다. **요청 본문**에 다음 JSON을 붙여넣습니다.

   ```
   {
       "operation": "update",
       "payload": {
           "Key": {
               "id": "1234ABCD"
           },
           "UpdateExpression": "SET #num = :newNum",
           "ExpressionAttributeNames": {
               "#num": "number"
           },
           "ExpressionAttributeValues": {
               ":newNum": 10
           }
       }
   }
   ```

1. **테스트**를 선택합니다.

   테스트가 완료될 때 표시되는 결과에 `200` 상태가 표시되어야 합니다. 이 상태 코드는 `update` 작업이 성공했음을 나타냅니다.

    이를 확인하려면 DynamoDB 테이블의 항목이 수정되었는지 확인하세요.

1. DynamoDB 콘솔의 [Tables](https://console.aws.amazon.com/dynamodbv2#tables)(테이블) 페이지를 열고 `lambda-apigateway` 테이블을 선택합니다.

1. **Explore table items**(테이블 항목 탐색)를 선택합니다. **Items returned**(반환된 항목) 창에 **ID**가 `1234ABCD`이고 **number**(번호)가 `10`인 항목이 하나 표시되어야 합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/items-returned-2.png)

## API 배포
<a name="services-apigateway-tutorial-deploy-api"></a>

클라이언트가 API를 호출하기 위해서는 배포 및 연결된 단계를 생성해야 합니다. 단계는 메서드와 통합을 포함한 API의 스냅샷을 나타냅니다.

**API를 배포하려면**

1. [API Gateway 콘솔](https://console.aws.amazon.com/apigateway)의 **APIs**(API) 페이지를 열고 `DynamoDBOperations` API를 선택합니다.

1. API의 **리소스** 페이지에서 **API 배포**를 선택합니다.

1. **단계**에서 **\$1새 단계\$1**를 선택하고 **단계 이름**에 **test**를 입력합니다.

1. **배포(Deploy)**를 선택합니다.

1. **단계 세부 정보** 창에서 **간접 호출 URL**을 복사합니다. 다음 단계에서는 이 URL을 사용하여 HTTP 요청을 통해 함수를 간접 호출합니다.

## curl을 사용하여 HTTP 요청을 통해 함수 간접 호출
<a name="services-apigateway-tutorial-invoke-function"></a>

이제 API에 HTTP 요청을 전송하여 Lambda 함수를 간접 호출할 수 있습니다. 이 단계에서는 DynamoDB 테이블에 새 항목을 생성한 다음, 해당 항목에 대한 읽기, 업데이트 및 삭제 작업을 수행합니다.

**curl을 사용하여 DynamoDB 테이블에 항목을 생성하려면**

1. 로컬 머신에서 터미널 또는 명령 프롬프트를 열고 이전 단계에서 복사한 간접 호출 URL을 사용하여 다음 `curl` 명령을 실행합니다. 이 명령은 다음 옵션을 사용합니다.
   + `-H`: 요청에 사용자 지정 헤더를 추가합니다. 여기서 이는 콘텐츠 유형을 JSON으로 지정합니다.
   + `-d`: 요청 본문에서 데이터를 전송합니다. 이 옵션은 기본적으로 HTTP POST 메서드를 사용합니다.

------
#### [ Linux/macOS ]

   ```
   curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
   -H "Content-Type: application/json" \
   -d '{"operation": "create", "payload": {"Item": {"id": "5678EFGH", "number": 15}}}'
   ```

------
#### [ PowerShell ]

   ```
   curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"create\", \"payload\": {\"Item\": {\"id\": \"5678EFGH\", \"number\": 15}}}'
   ```

------

   작업이 성공했다면 HTTP 상태 코드 200이 포함된 응답이 반환되어야 합니다.

1. 또한 다음 작업을 수행하여 새 항목이 테이블에 있는지 확인하기 위해 DynamoDB 콘솔을 사용할 수도 있습니다.

   1. DynamoDB 콘솔의 [Tables](https://console.aws.amazon.com/dynamodbv2#tables)(테이블) 페이지를 열고 `lambda-apigateway` 테이블을 선택합니다.

   1. **Explore table items**(테이블 항목 탐색)를 선택합니다. **Items returned**(반환된 항목) 창에 **ID**가 `5678EFGH`이고 **번호**가 `15`인 항목이 표시되어야 합니다.

**curl을 사용하여 DynamoDB 테이블에서 항목을 읽으려면**
+ 터미널 또는 명령 프롬프트에서 다음 `curl` 명령을 실행하여 방금 생성한 항목의 값을 읽습니다. 실제 간접 호출 URL을 사용하세요.

------
#### [ Linux/macOS ]

  ```
  curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
  -H "Content-Type: application/json" \
  -d '{"operation": "read", "payload": {"Key": {"id": "5678EFGH"}}}'
  ```

------
#### [ PowerShell ]

  ```
  curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"read\", \"payload\": {\"Key\": {\"id\": \"5678EFGH\"}}}'
  ```

------

  Node.js 또는 Python 함수 코드 중 무엇을 선택했는지에 따라 다음 중 하나와 같은 출력이 표시되어야 합니다.

------
#### [ Node.js ]

  ```
  {"$metadata":{"httpStatusCode":200,"requestId":"7BP3G5Q0C0O1E50FBQI9NS099JVV4KQNSO5AEMVJF66Q9ASUAAJG",
  "attempts":1,"totalRetryDelay":0},"Item":{"id":"5678EFGH","number":15}}
  ```

------
#### [ Python ]

  ```
  {"Item":{"id":"5678EFGH","number":15},"ResponseMetadata":{"RequestId":"QNDJICE52E86B82VETR6RKBE5BVV4KQNSO5AEMVJF66Q9ASUAAJG",
  "HTTPStatusCode":200,"HTTPHeaders":{"server":"Server","date":"Wed, 31 Jul 2024 00:37:01 GMT","content-type":"application/x-amz-json-1.0",
  "content-length":"52","connection":"keep-alive","x-amzn-requestid":"QNDJICE52E86B82VETR6RKBE5BVV4KQNSO5AEMVJF66Q9ASUAAJG","x-amz-crc32":"2589610852"},
  "RetryAttempts":0}}
  ```

------

**curl을 사용하여 DynamoDB 테이블의 항목을 업데이트하려면**

1. 터미널 또는 명령 프롬프트에서 다음 `curl` 명령을 실행하여 `number` 값을 변경해 방금 생성한 항목을 업데이트합니다. 실제 간접 호출 URL을 사용하세요.

------
#### [ Linux/macOS ]

   ```
   curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
   -H "Content-Type: application/json" \
   -d '{"operation": "update", "payload": {"Key": {"id": "5678EFGH"}, "UpdateExpression": "SET #num = :new_value", "ExpressionAttributeNames": {"#num": "number"}, "ExpressionAttributeValues": {":new_value": 42}}}'
   ```

------
#### [ PowerShell ]

   ```
   curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"update\", \"payload\": {\"Key\": {\"id\": \"5678EFGH\"}, \"UpdateExpression\": \"SET #num = :new_value\", \"ExpressionAttributeNames\": {\"#num\": \"number\"}, \"ExpressionAttributeValues\": {\":new_value\": 42}}}'
   ```

------

1. 항목의 `number` 값이 업데이트되었는지 확인하려면, 다음과 같이 다른 읽기 명령을 실행합니다.

------
#### [ Linux/macOS ]

   ```
   curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
   -H "Content-Type: application/json" \
   -d '{"operation": "read", "payload": {"Key": {"id": "5678EFGH"}}}'
   ```

------
#### [ PowerShell ]

   ```
   curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"read\", \"payload\": {\"Key\": {\"id\": \"5678EFGH\"}}}'
   ```

------

**curl을 사용하여 DynamoDB 테이블의 항목을 삭제하려면**

1. 터미널 또는 명령 프롬프트에서 다음 `curl` 명령을 실행하여 방금 생성한 항목을 삭제합니다. 실제 간접 호출 URL을 사용하세요.

------
#### [ Linux/macOS ]

   ```
   curl https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager \
   -H "Content-Type: application/json" \
   -d '{"operation": "delete", "payload": {"Key": {"id": "5678EFGH"}}}'
   ```

------
#### [ PowerShell ]

   ```
   curl.exe 'https://l8togsqxd8.execute-api.us-east-2.amazonaws.com/test/DynamoDBManager' -H 'Content-Type: application/json' -d '{\"operation\": \"delete\", \"payload\": {\"Key\": {\"id\": \"5678EFGH\"}}}'
   ```

------

1. 삭제 작업이 성공했는지 확인합니다. DynamoDB 콘솔 **항목 탐색** 페이지의 **반환된 항목** 창에서 **ID**가 `5678EFGH`인 항목이 더 이상 테이블에 없는지 확인합니다.

## 리소스 정리(선택 사항)
<a name="cleanup"></a>

이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.

**Lambda 함수를 삭제하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 생성한 함수를 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **confirm**를 입력하고 **Delete**(삭제)를 선택합니다.

**집행 역할 삭제**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. 생성한 실행 역할을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 역할의 이름을 입력하고 **Delete**(삭제)를 선택합니다.

**API를 삭제하려면**

1. API Gateway 콘솔의 [API 페이지](https://console.aws.amazon.com/apigateway/main/apis)를 엽니다.

1. 생성한 API를 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. **삭제**를 선택합니다.

**DynamoDB 테이블을 삭제하려면**

1. DynamoDB 콘솔의 [테이블 페이지](https://console.aws.amazon.com//dynamodb/home#tables:)를 엽니다.

1. 생성한 테이블을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 상자에 **delete**를 입력합니다.

1. **테이블 삭제**를 선택합니다.

# API Gateway API를 사용한 Lambda 오류 처리
<a name="services-apigateway-errors"></a>

API Gateway는 모든 호출 및 함수 오류를 내부 오류로 처리합니다. Lambda API가 호출 요청을 거부하면 API Gateway는 500 오류 코드를 반환합니다. 함수가 실행되지만 오류를 반환하거나 잘못된 형식으로 응답을 반환하는 경우 API Gateway에서 502를 반환합니다. 두 경우 모두 API Gateway의 응답 본문은 `{"message": "Internal server error"}`입니다.

**참고**  
API Gateway는 Lambda 호출을 다시 시도하지 않습니다. Lambda가 오류를 반환하면 API Gateway는 클라이언트에 오류 응답을 반환합니다.

다음 예제에서는 함수 오류가 발생해 API Gateway에서 502가 반환된 요청에 대한 X-Ray 추적 맵을 보여 줍니다. 클라이언트는 제네릭 오류 메시지를 수신합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/tracemap-apig-502.png)


오류 응답을 사용자 지정하려면 코드에서 오류를 포착하고 필요한 형식으로 응답을 지정해야 합니다.

**Example [index.mjs](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/nodejs-apig/function/index.mjs) – 오류 형식 지정**  

```
var formatError = function(error){
  var response = {
    "statusCode": error.statusCode,
    "headers": {
      "Content-Type": "text/plain",
      "x-amzn-ErrorType": error.code
    },
    "isBase64Encoded": false,
    "body": error.code + ": " + error.message
  }
  return response
}
```

API Gateway는 이 응답을 사용자 지정 상태 코드 및 본문을 사용한 HTTP 오류로 변환합니다. 오류를 처리했기 때문에 추적 맵에서 함수 노드는 녹색입니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/tracemap-apig-404.png)


# HTTP 요청을 사용하여 Lambda 함수를 간접 호출하는 메서드 선택
<a name="apig-http-invoke-decision"></a>

Lambda에 대한 많은 일반적인 사용 사례는 HTTP 요청을 사용하여 함수를 간접 호출하는 작업과 관련이 있습니다. 예를 들어 웹 애플리케이션이 브라우저 요청을 통해 함수를 간접적으로 호출하도록 할 수 있습니다. Lambda 함수를 사용하여 전체 REST API를 생성하거나, 모바일 앱에서 사용자 상호 작용을 처리하거나, HTTP 호출을 통해 외부 서비스의 데이터를 처리하거나, 사용자 지정 웹후크를 생성할 수도 있습니다.

다음 섹션에서는 HTTP를 통해 Lambda를 간접 호출할 때 선택하는 항목을 설명하고 특정 사용 사례에 맞는 올바른 결정을 내리는 데 도움이 되는 정보를 제공합니다.

## HTTP 간접 호출 메서드를 선택할 때 선택할 수 있는 항목은 무엇인가요?
<a name="w2aad101c29c46b9"></a>

Lambda는 HTTP 요청을 사용하여 함수를 간접 호출하는 두 가지 주요 방법인 [함수 URL](urls-configuration.md) 및 [API Gateway](services-apigateway.md)를 제공합니다. 이 두 옵션의 주요 차이는 다음과 같습니다.
+ **Lambda 함수 URL**에서는 Lambda 함수에 대한 간단한 직접 HTTP 엔드포인트를 제공합니다. 단순성과 비용 효율성에 최적화되어 있으며 HTTP를 통해 Lambda 함수를 공개할 수 있는 가장 빠른 경로를 제공합니다.
+ **API Gateway**는 완전한 기능을 갖춘 API 빌드를 위한 보다 고급 서비스입니다. API Gateway는 대규모로 프로덕션 API를 빌드 및 관리하는 데 최적화되어 있으며 보안, 모니터링 및 트래픽 관리를 위한 포괄적인 도구를 제공합니다.

## 권장 사항(요구 사항을 이미 알고 있는 경우)
<a name="w2aad101c29c46c11"></a>

요구 사항을 이미 명확히 알고 있는 경우 기본 권장 사항은 다음과 같습니다.

기본 인증 방법 및 요청/응답 처리만 필요하고 비용과 복잡성을 최소화하려는 간단한 애플리케이션 또는 프로토타이프 제작에는 **[함수 URL](urls-configuration.md)**을 사용하는 것이 좋습니다.

**[API게이트웨이](services-apigateway.md)**는 대규모 프로덕션 애플리케이션 또는 [OpenAPI 설명](https://www.openapis.org/) 지원, 인증 옵션 선택 항목, 사용자 지정 도메인 이름 또는 스로틀링, 캐싱, 요청/응답 변환을 포함한 다양한 요청/응답 처리와 같은 고급 기능이 필요한 경우에 더 적합한 선택 항목입니다.

## Lambda 함수를 간접 호출하는 방법을 선택할 때 고려할 사항
<a name="w2aad101c29c46c13"></a>

함수 URL 및 API Gateway 중에서 선택할 때는 다음 요소를 고려해야 합니다.
+ OAuth 또는 Amazon Cognito에서 사용자를 인증해야 하는지 여부와 같은 인증 요구 사항
+ 규모 조정 요구 사항 및 구현하려는 API의 복잡성
+ 요청 검증 및 요청/응답 형식 지정과 같은 고급 기능이 필요한지 여부
+ 모니터링 요구 사항
+ 비용 목표

이러한 요소를 이해하면 보안, 복잡성 및 비용 요구 사항의 균형을 가장 잘 맞추는 옵션을 선택할 수 있습니다.

다음은 두 옵션 간 주요 차이를 요약한 정보입니다.

### Authentication
<a name="w2aad101c29c46c13c11b1"></a>
+ **함수 URL**에서는 AWS Identity and Access Management(IAM)를 통해 기본 인증 옵션을 제공합니다. 엔드포인트를 퍼블릭(인증 없음) 또는 IAM 인증을 요구하도록 구성할 수 있습니다. IAM 인증을 사용하면 표준 AWS 자격 증명 또는 IAM 역할을 사용하여 액세스를 제어할 수 있습니다. 간단하게 설정할 수 있지만 이 접근 방식에서는 다른 인증 방법에 비해 제한된 옵션을 제공합니다.
+ **API Gateway**는 보다 포괄적인 인증 옵션에 대한 액세스를 제공합니다. IAM 인증 외에도 [Lambda 권한 부여자](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html)(사용자 지정 인증 로직), [Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html) 사용자 풀 및 OAuth2.0 흐름을 사용할 수 있습니다. 이러한 유연성을 통해 서드파티 인증 제공업체, 토큰 기반 인증 및 다중 인증 등 복잡한 인증 체계를 구현할 수 있습니다.

### 요청/응답 처리
<a name="w2aad101c29c46c13c11b3"></a>
+ **함수 URL**에서는 기본 HTTP 요청 및 응답 처리를 제공합니다. 이때 표준 HTTP 메서드를 지원하며 기본 제공 교차 오리진 리소스 공유(CORS) 지원을 포함합니다. 기본적으로 JSON 페이로드 및 쿼리 파라미터를 처리할 수 있지만 요청 변환 또는 검증 기능은 제공하지 않습니다. 응답 처리도 마찬가지로 간단합니다. 클라이언트는 Lambda에서 반환하는 대로 정확히 Lambda 함수로부터 응답을 수신합니다.
+ **API Gateway**에서는 정교한 요청 및 응답 처리 기능을 제공합니다. 요청 검증기를 정의하고, 매핑 템플릿을 사용하여 요청 및 응답을 변환하며, 요청/응답 헤더를 설정하고, 응답 캐싱을 구현할 수 있습니다. 또한 API Gateway는 바이너리 페이로드 및 사용자 지정 도메인 이름을 지원하며 클라이언트에 도달하기 전에 응답을 수정할 수 있습니다. JSON 스키마를 사용하여 요청/응답 검증 및 변환을 위한 모델을 설정할 수 있습니다.

### 규모 조정
<a name="w2aad101c29c46c13c11b5"></a>
+ **함수 URL**에서는 Lambda 함수의 동시성 제한에 따라 직접 조정하며 구성된 최대 동시성 제한까지 함수를 조정하여 트래픽 급증을 처리합니다. 제한에 도달하면 Lambda는 HTTP 429 응답과 함께 추가 요청에 응답합니다. 기본 제공 대기열 메커니즘이 없으므로 규모 조정 처리는 전적으로 Lambda 함수의 구성에 따라 달라집니다. 기본적으로 Lambda 함수는 AWS 리전당 동시 실행이 1,000개로 제한됩니다.
+ **API Gateway**에서는 Lambda의 자체 규모 조정 외에도 추가 규모 조정 기능을 제공합니다. 여기에는 기본 제공 요청 대기열 및 스로틀링 제어가 포함되어 있어 트래픽 급증을 보다 점진적으로 관리할 수 있습니다. API Gateway에서는 기본적으로 리전당 1초에 최대 10,000건의 요청을 처리할 수 있으며 버스트 용량에서는 1초에 5,000건의 요청을 처리할 수 있습니다. 또한 백엔드를 보호하기 위해 여러 수준(API, 단계 또는 방법)에서 요청을 스로틀링하는 도구를 제공합니다.

### 모니터링
<a name="w2aad101c29c46c13c11b7"></a>
+ **함수 URL**에서는 요청 수, 지연 시간 및 오류 비율을 포함하여 Amazon CloudWatch 지표를 통한 기본 모니터링을 제공합니다. 함수에 들어오는 원시 요청을 보여주는 표준 Lambda 지표 및 로그에 액세스할 수 있습니다. 이를 통해 핵심적인 운영 가시성을 제공하지만 지표는 주로 함수 실행에 중점을 둡니다.
+ **API Gateway**에서는 세부 지표, 로깅 및 추적 옵션을 포함한 포괄적인 모니터링 기능을 제공합니다. CloudWatch를 통해 API 직접 호출, 지연 시간, 오류 비율 및 캐시 적중/누락 비율을 모니터링할 수 있습니다. 또한 API Gateway는 분산 추적을 위해 AWS X-Ray와 통합되며 사용자 지정 가능한 로깅 형식을 제공합니다.

### 비용
<a name="w2aad101c29c46c13c11b9"></a>
+ **함수 URL**은 표준 Lambda 요금 모델을 따르므로, 함수 간접 호출 및 컴퓨팅 시간에 대한 비용만 지불하면 됩니다. URL 엔드포인트 자체에는 추가 요금이 부과되지 않습니다. 따라서 API Gateway의 추가 기능이 필요하지 않은 경우 간단한 API 또는 트래픽이 적은 애플리케이션에 비용 효율적인 선택이 됩니다.
+ **API Gateway**는 REST API에 대해 수신된 백만 개의 API 직접 호출 및 HTTP API에 대해 수신된 백만 개의 API 직접 호출을 포함하는 [프리 티어](https://aws.amazon.com/api-gateway/pricing/#Free_Tier)를 제공합니다. 프리 티어 이후에 API Gateway에서는 API 직접 호출, 데이터 전송 및 캐싱(활성화된 경우)에 대해 요금을 청구합니다. 자체 사용 사례의 비용을 파악하기 위해 API Gateway [요금 페이지](https://aws.amazon.com/api-gateway/pricing/)를 참조하세요.

### 기타 기능
<a name="w2aad101c29c46c13c11c11"></a>
+ **함수 URL**은 단순성과 직접적인 Lambda 통합을 위해 설계되었습니다. 여기에서는 HTTP 및 HTTPS 엔드포인트를 모두 지원하고, 기본 제공 CORS 지원을 제공하며, 듀얼 스택(IPv4 및 IPv6) 엔드포인트를 제공합니다. 고급 기능은 부족하지만 HTTP를 통해 Lambda 함수를 공개하는 빠르고 간단한 방법이 필요한 시나리오에서 적합합니다.
+ **API Gateway**에는 API 버전 관리, 단계 관리, 사용 계획을 위한 API 키, Swagger/OpenAPI에 관한 API 설명서, WebSocket API, VPC 내 프라이빗 API, 추가 보안을 위한 WAF 통합과 같은 많은 추가 기능이 포함되어 있습니다. 또한 카나리 배포, 테스트를 위한 모의 통합 및 Lambda 외 다른 AWS 서비스와의 통합을 지원합니다.

## Lambda 함수를 간접 호출할 메서드 선택
<a name="w2aad101c29c46c15"></a>

이제 Lambda 함수 URL 및 API Gateway 중 하나를 선택하는 기준과 이들 간의 주요 차이에 대해 알아보았으니, 요구 사항에 가장 적합한 옵션을 선택하고 다음 리소스를 사용하여 사용을 시작할 수 있습니다.

------
#### [ Function URLs ]

**다음 리소스를 사용하여 함수 URL 시작하기**
+ 자습서 [함수 URL을 사용하여 Lambda 함수 생성](urls-webhook-tutorial.md) 수행
+ 이 설명서의 [Lambda 함수 URL 생성 및 관리](urls-configuration.md) 장에서 함수 URL에 대해 자세히 알아보기
+ 다음을 수행하여 콘솔 내 안내식 자습서 **간단한 웹 앱 생성**을 시도해 보세요.

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 여세요.

1. 화면의 오른쪽 상단에 있는 아이콘을 선택하여 도움말 패널을 여세요.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/console_help_screenshot.png)

1. **자습서**를 선택하세요.

1. **간단한 웹 앱 생성**에서 **자습서 시작**을 선택하세요.

------
#### [ API Gateway ]

**다음 리소스를 사용하여 Lambda 및 API Gateway 시작하기**
+ 자습서 [API Gateway와 함께 Lambda 사용](services-apigateway-tutorial.md)에 따라 백엔드 Lambda 함수와 통합된 REST API를 생성합니다.
+ *Amazon API Gateway 개발자 안내서*의 다음 섹션에서 API Gateway가 제공하는 여러 API 유형에 대해 자세히 알아보세요.
  + [API Gateway REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html)
  + [API Gateway HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html)
  + [API Gateway WebSocket API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html)
+ *Amazon API Gateway 개발자 안내서*의 [자습서 및 워크숍](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-tutorials.html) 섹션에서 하나 이상의 예제를 시도해 보세요.

------

# 과 함께 AWS Lambda 사용AWS Infrastructure Composer
<a name="services-appcomposer"></a>

AWS Infrastructure Composer은 AWS에 최신 애플리케이션을 디자인하기 위한 비주얼 빌더입니다. 시각적 캔버스에서 AWS 서비스를 드래그, 그룹화 및 연결하여 애플리케이션 아키텍처를 설계합니다. Infrastructure Composer는 설계에서 [AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) 또는 [CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html)을 사용하여 배포할 수 있는 코드형 인프라(IaC) 템플릿을 생성합니다.

## Infrastructure Composer로 Lambda 함수 내보내기
<a name="services-appcomposer-export"></a>

Lambda 콘솔을 사용하여 기존 Lambda 함수의 구성을 기반으로 새 프로젝트를 생성하여 Infrastructure Composer 사용을 시작할 수 있습니다. 함수의 구성 및 코드를 Infrastructure Composer로 내보내서 새 프로젝트를 생성하려면 다음을 수행하세요.

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. Infrastructure Composer 프로젝트의 기준으로 사용하려는 함수를 선택합니다.

1. **함수 개요** 창에서 **Infrastructure Composer로 내보내기**를 선택합니다.

   함수의 구성 및 코드를 Infrastructure Composer로 내보내기 위해 Lambda는 계정에 Amazon S3 버킷을 생성하여 이 데이터를 임시로 저장합니다.

1. 대화 상자에서 **확인 및 프로젝트 생성**을 선택하여 이 버킷의 기본 이름을 수락하고 함수의 구성 및 코드를 Infrastructure Composer로 내보냅니다.

1. (선택 사항) Lambda가 생성하는 Amazon S3 버킷의 다른 이름을 선택하려면 새 이름을 입력하고 **확인 및 프로젝트 생성**을 선택합니다. Amazon S3 버킷에 이름은 전역적으로 고유해야 하며 [버킷 이름 지정 규칙](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)을 따라야 합니다.

1. 프로젝트 및 함수 파일을 Infrastructure Composer에 저장하려면 [로컬 동기화 모드](https://docs.aws.amazon.com/application-composer/latest/dg/reference-features-local-sync.html)를 활성화합니다.

**참고**  
이전에 **Application Composer로 내보내기** 기능을 사용하고 기본 이름을 사용하여 Amazon S3 버킷을 생성한 경우, Lambda는 이 버킷이 아직 존재한다면 재사용할 수 있습니다. 대화 상자에서 기본 버킷 이름을 수락하여 기존 버킷을 재사용합니다.

### Amazon S3 버킷 구성 전송
<a name="services-appcomposer-bucket-info"></a>

Lambda가 함수 구성을 전송하기 위해 생성하는 Amazon S3 버킷은 AES 256 암호화 표준을 사용하여 객체를 자동으로 암호화합니다. Lambda는 또한 [버킷 소유자 조건](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-owner-condition.html)을 사용하도록 버킷을 구성하여 AWS 계정만 버킷에 객체를 추가할 수 있도록 합니다.

Lambda는 업로드 후 10일이 지나면 객체를 자동으로 삭제하도록 버킷을 구성합니다. 하지만 Lambda는 버킷 자체를 자동으로 삭제하지 않습니다. AWS 계정에서 버킷을 삭제하려면 [버킷 삭제](https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-bucket.html)의 지침을 따릅니다. 기본 버킷 이름은 10자리 영숫자 문자열인 접두사 `lambdasam`을 사용하며, 함수를 생성한 AWS 리전의 위치는 다음과 같습니다.

```
lambdasam-06f22da95b-us-east-1
```

AWS 계정에 추가되어 추가 요금이 부과되지 않도록 하려면 Infrastructure Composer로 함수 내보내기를 완료하는 즉시 Amazon S3 버킷을 삭제하는 것이 좋습니다.

표준 [Amazon S3 요금](https://aws.amazon.com/s3/pricing/)이 적용됩니다.

### 필수 권한
<a name="services-appcomposer-permissions"></a>

Infrastructure Composer 기능을 포함하는 Lambda 통합을 사용하려면 AWS SAM 템플릿을 다운로드하고 Amazon S3에 함수 구성을 작성할 수 있는 특정 권한이 필요합니다.

AWS SAM 템플릿을 다운로드하려면 다음 API 작업을 사용할 권한이 있어야 합니다.
+ [GetPolicy](https://docs.aws.amazon.com/lambda/latest/api/API_GetPolicy.html)
+ [iam:GetPolicyVersion](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicyVersion.html)
+ [iam:GetRole](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetRole.html)
+ [iam:GetRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetRolePolicy.html)
+ [iam:ListAttachedRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAttachedRolePolicies.html)
+ [iam:ListRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListRolePolicies.html)
+ [iam:ListRoles](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListRoles.html)

IAM 사용자 역할에 [https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambda_ReadOnlyAccess.html](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambda_ReadOnlyAccess.html) AWS 관리형 정책을 추가하여 이러한 모든 작업을 사용할 권한을 부여할 수 있습니다.

Lambda가 Amazon S3에 함수 구성을 작성하려면 다음 API 작업을 사용할 권한이 있어야 합니다.
+ [S3:PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html)
+ [S3:CreateBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html)
+ [S3:PutBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html)
+ [S3:PutBucketLifecycleConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html)

함수 구성을 Infrastructure Composer로 내보낼 수 없는 경우 계정에 이러한 작업에 필요한 권한이 있는지 확인합니다. 필요한 권한이 있지만 여전히 함수 구성을 내보낼 수 없는 경우 Amazon S3에 대한 액세스 권한을 제한할 수 있는 [리소스 기반 정책](access-control-resource-based.md)이 있는지 확인합니다.

## 기타 리소스
<a name="w2aad101c33b7"></a>

Infrastructure Composer에서 기존 Lambda 함수를 기반으로 서버리스 애플리케이션을 설계하는 방법에 대한 자세한 자습서는 [코드형 인프라(IaC)와 함께 Lambda 사용](foundation-iac.md)를 참조하세요.

Infrastructure Composer 및 AWS SAM을 사용하여 Lambda를 사용하는 완전한 서버리스 애플리케이션을 설계 및 배포하려면 [AWS Infrastructure Composer 자습서](https://catalog.workshops.aws/serverless-patterns/en-US/dive-deeper/module1a)를 [AWS 서버리스 패턴 워크숍](https://catalog.workshops.aws/serverless-patterns/en-US)에서 찾아 따라할 수도 있습니다.

# AWS Lambda와 함께 CloudFormation 사용
<a name="services-cloudformation"></a>

AWS CloudFormation 템플릿에서는 사용자 지정 리소스의 대상으로 Lambda 함수를 지정할 수 있습니다. 사용자 지정 리소스를 사용하여 파라미터를 처리하거나 설정 값을 검색하거나 스택 수명 주기 이벤트 도중 다른 AWS 서비스를 직접 호출합니다.

다음 예시는 템플릿에 정의된 함수를 간접 호출합니다.

**Example - 사용자 지정 리소스 정의**  

```
Resources:
  primerinvoke:
    Type: [AWS::CloudFormation::CustomResource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cfn-customresource.html)
    Version: "1.0"
    Properties:
      ServiceToken: !GetAtt primer.Arn
      FunctionName: !Ref randomerror
```

서비스 토큰은 스택 생성, 업데이트 또는 삭제 시 CloudFormation이 간접 호출한 함수의 ARN(Amazon Resource Name)입니다. `FunctionName`이 원형 그대로 함수로 전달하는, CloudFormation 같은 추가 속성을 포함할 수도 있습니다.

CloudFormation은 콜백 URL을 포함하는 이벤트와 [비동기적으로](invocation-async.md) Lambda 함수를 간접 호출합니다.

**Example – CloudFormation 메시지 이벤트**  

```
{
    "RequestType": "Create",
    "ServiceToken": "arn:aws:lambda:us-east-1:123456789012:function:lambda-error-processor-primer-14ROR2T3JKU66",
    "ResponseURL": "https://cloudformation-custom-resource-response-useast1.s3-us-east-1.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-1%3A123456789012%3Astack/lambda-error-processor/1134083a-2608-1e91-9897-022501a2c456%7Cprimerinvoke%7C5d478078-13e9-baf0-464a-7ef285ecc786?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Expires=1555451971&Signature=28UijZePE5I4dvukKQqM%2F9Rf1o4%3D",
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/lambda-error-processor/1134083a-2608-1e91-9897-022501a2c456",
    "RequestId": "5d478078-13e9-baf0-464a-7ef285ecc786",
    "LogicalResourceId": "primerinvoke",
    "ResourceType": "AWS::CloudFormation::CustomResource",
    "ResourceProperties": {
        "ServiceToken": "arn:aws:lambda:us-east-1:123456789012:function:lambda-error-processor-primer-14ROR2T3JKU66",
        "FunctionName": "lambda-error-processor-randomerror-ZWUC391MQAJK"
    }
}
```

함수는 성공 또는 실패를 나타내는 콜백 URL에 대한 응답을 반환할 책임을 집니다. 전체 응답 구문은 [사용자 지정 리소스 응답 객체](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html)에서 확인할 수 있습니다.

**Example – CloudFormation 사용자 지정 리소스 응답**  

```
{
    "Status": "SUCCESS",
    "PhysicalResourceId": "2019/04/18/[$LATEST]b3d1bfc65f19ec610654e4d9b9de47a0",
    "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/lambda-error-processor/1134083a-2608-1e91-9897-022501a2c456",
    "RequestId": "5d478078-13e9-baf0-464a-7ef285ecc786",
    "LogicalResourceId": "primerinvoke"
}
```

CloudFormation은 응답 전송을 처리하는 `cfn-response`라는 라이브러리를 제공합니다. 템플릿 내에서 함수를 정의하려면, 함수를 이름으로 요청하면 됩니다. 그러면 CloudFormation이 함수를 위해 생성된 배포 패키지에 라이브러리를 추가합니다.

사용자 지정 리소스에서 사용하는 함수에 [탄력적 네트워크 인터페이스](configuration-vpc.md#configuration-vpc-enis)가 연결된 경우 다음 리소스를 VPC 정책에 추가합니다. 여기서 **region**은 함수가 있는 리전(대시 없음)입니다. 예를 들어 `us-east-1`은 `useast1`입니다. 이렇게 하면 Custom Resource가 CloudFormation 스택으로 신호를 다시 보내는 콜백 URL에 응답할 수 있습니다.

```
arn:aws:s3:::cloudformation-custom-resource-response-region",
"arn:aws:s3:::cloudformation-custom-resource-response-region/*",
```

다음 예시 함수는 두 번째 함수를 간접 호출합니다. 호출이 성공한다면, 함수는 성공 응답을 CloudFormation에 전송하고 스택 업데이트가 진행됩니다. 템플릿은 AWS Serverless Application Model에서 제공하는 [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html) 리소스 유형을 사용합니다.

**Example - 사용자 지정 리소스 함수**  

```
Transform: 'AWS::Serverless-2016-10-31'
Resources:
  primer:
    Type: [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      Handler: index.handler
      Runtime: nodejs16.x
      InlineCode: |
        var aws = require('aws-sdk');
        var response = require('cfn-response');
        exports.handler = function(event, context) {
            // For Delete requests, immediately send a SUCCESS response.
            if (event.RequestType == "Delete") {
                response.send(event, context, "SUCCESS");
                return;
            }
            var responseStatus = "FAILED";
            var responseData = {};
            var functionName = event.ResourceProperties.FunctionName
            var lambda = new aws.Lambda();
            lambda.invoke({ FunctionName: functionName }, function(err, invokeResult) {
                if (err) {
                    responseData = {Error: "Invoke call failed"};
                    console.log(responseData.Error + ":\n", err);
                }
                else responseStatus = "SUCCESS";
                response.send(event, context, responseStatus, responseData);
            });
        };
      Description: Invoke a function to create a log stream.
      MemorySize: 128
      Timeout: 8
      Role: !GetAtt role.Arn
      Tracing: Active
```

사용자 지정 리소스가 간접 호출하는 함수가 템플릿에 정의되어 있지 않다면, AWS CloudFormation 사용 설명서의 [cfn-response 모듈](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html)에서 `cfn-response`의 소스 코드를 얻을 수 있습니다.

사용자 지정 리소스에 대한 자세한 내용은 *AWS CloudFormation 사용 설명서*의 [사용자 지정 리소스](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html)를 참조하세요.

# Lambda로 Amazon DocumentDB 이벤트 처리
<a name="with-documentdb"></a>

Amazon DocumentDB 클러스터를 이벤트 소스로 구성하면 Lambda 함수를 사용하여 [Amazon DocumentDB(MongoDB 호환) 변경 스트림](https://docs.aws.amazon.com/documentdb/latest/developerguide/change_streams.html)의 이벤트를 처리할 수 있습니다. 그런 다음 Amazon DocumentDB 클러스터에서 데이터가 변경될 때마다 Lambda 함수를 호출하여 이벤트 기반 워크로드를 자동화할 수 있습니다.

**참고**  
Lambda는 Amazon DocumentDB 버전 4.0 및 5.0만 지원합니다. Lambda는 버전 3.6을 지원하지 않습니다.  
또한 이벤트 소스 매핑의 경우 Lambda는 인스턴스 기반 클러스터와 리전 클러스터만 지원합니다. Lambda는 [탄력적 클러스터](https://docs.aws.amazon.com/documentdb/latest/developerguide/docdb-using-elastic-clusters.html) 또는 [글로벌 클러스터](https://docs.aws.amazon.com/documentdb/latest/developerguide/global-clusters.html)를 지원하지 않습니다. Lambda를 클라이언트로 사용하여 Amazon DocumentDB에 연결할 때는 이 제한이 적용되지 않습니다. Lambda는 모든 클러스터 유형에 연결하여 CRUD 작업을 수행할 수 있습니다.

Lambda는 Amazon DocumentDB 변경 스트림의 이벤트를 도착 순서대로 순차적으로 처리합니다. 따라서 함수는 Amazon DocumentDB에서 한 번에 하나의 동시 간접 호출만 처리할 수 있습니다. 함수를 모니터링하기 위해 함수의 [동시성 지표](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-concurrency.html)를 추적할 수 있습니다.

**주의**  
Lambda 이벤트 소스 매핑은 각 이벤트를 한 번 이상 처리하므로 레코드가 중복될 수 있습니다. 중복 이벤트와 관련된 잠재적 문제를 방지하려면 함수 코드를 멱등성으로 만드는 것이 좋습니다. 자세한 내용은 AWS 지식 센터의 [함수를 멱등성 Lambda 함수로 만들려면 어떻게 해야 하나요?](https://repost.aws/knowledge-center/lambda-function-idempotent)를 참조하세요.

**Topics**
+ [

## 예시 Amazon DocumentDB 이벤트
](#docdb-sample-event)
+ [

## 사전 조건 및 권한
](#docdb-prereqs)
+ [

## 네트워크 보안 구성
](#docdb-network)
+ [

## Amazon DocumentDB 이벤트 소스 매핑 생성(콘솔)
](#docdb-configuration)
+ [

## Amazon DocumentDB 이벤트 소스 매핑 생성(SDK 또는 CLI)
](#docdb-api)
+ [

## 폴링 및 스트리밍 시작 위치
](#docdb-stream-polling)
+ [

## Amazon DocumentDB 이벤트 소스 모니터링
](#docdb-monitoring)
+ [

# 자습서: Amazon DocumentDB Streams와 함께 AWS Lambda 사용
](with-documentdb-tutorial.md)

## 예시 Amazon DocumentDB 이벤트
<a name="docdb-sample-event"></a>

```
{
    "eventSourceArn": "arn:aws:rds:us-east-1:123456789012:cluster:canaryclusterb2a659a2-qo5tcmqkcl03",
    "events": [
        {
            "event": {
                "_id": {
                    "_data": "0163eeb6e7000000090100000009000041e1"
                },
                "clusterTime": {
                    "$timestamp": {
                        "t": 1676588775,
                        "i": 9
                    }
                },
                "documentKey": {
                    "_id": {
                        "$oid": "63eeb6e7d418cd98afb1c1d7"
                    }
                },
                "fullDocument": {
                    "_id": {
                        "$oid": "63eeb6e7d418cd98afb1c1d7"
                    },
                    "anyField": "sampleValue"
                },
                "ns": {
                    "db": "test_database",
                    "coll": "test_collection"
                },
                "operationType": "insert"
            }
        }
    ],
    "eventSource": "aws:docdb"
}
```

이 예제의 이벤트와 해당 셰이프에 대한 자세한 내용은 MongoDB Documentation 웹 사이트의 [Change Events](https://www.mongodb.com/docs/manual/reference/change-events/)를 참조하세요.

## 사전 조건 및 권한
<a name="docdb-prereqs"></a>

Lambda 함수에 Amazon DocumentDB를 이벤트 소스로 사용하기 전에 다음 사전 요구 사항을 확인하세요. 다음을 수행해야 합니다.
+ **함수와 동일한 AWS 계정 및 AWS 리전에 기존 Amazon DocumentDB 클러스터가 있어야 합니다.** 기존 클러스터가 없다면 **Amazon DocumentDB 개발자 안내서의 [Get Started with Amazon DocumentDB](https://docs.aws.amazon.com/documentdb/latest/developerguide/get-started-guide.html)에 나와 있는 단계에 따라 하나 생성하면 됩니다. 또는 [자습서: Amazon DocumentDB Streams와 함께 AWS Lambda 사용](with-documentdb-tutorial.md) 안내서의 첫 번째 단계 집합은 필요한 모든 사전 조건이 있는 Amazon DocumentDB 클러스터를 생성하는 과정을 안내합니다.
+ **Lambda가 Amazon DocumentDB 클러스터와 연결된 Amazon Virtual Private Cloud(Amazon VPC) 리소스에 액세스할 수 있도록 허용해야 합니다.** 자세한 내용은 [네트워크 보안 구성](#docdb-network) 섹션을 참조하세요.
+ **Amazon DocumentDB 클러스터에서 TLS를 활성화합니다.** 이것이 기본 설정입니다. TLS를 사용하지 않도록 설정하면 Lambda가 클러스터와 통신할 수 없습니다.
+ **Amazon DocumentDB 클러스터에서 변경 스트림을 활성화해야 합니다.** 자세한 내용은 **Amazon DocumentDB 개발자 안내서의 [Using Change Streams with Amazon DocumentDB](https://docs.aws.amazon.com/documentdb/latest/developerguide/change_streams.html)를 참조하세요.
+ **Amazon DocumentDB 클러스터에 액세스할 수 있도록 Lambda에 보안 인증을 제공해야 합니다.** 이벤트 소스를 설정할 때 클러스터에 액세스하는 데 필요한 인증 세부 정보(사용자 이름 및 암호)가 포함된 [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) 키를 제공합니다. 설치 중 이 키를 제공하려면 다음 중 하나를 수행합니다.
  + 설정에 Lambda 콘솔을 사용하는 경우 **Secrets Manager 키** 필드에 키를 제공합니다.
  + 설정에 AWS Command Line Interface(AWS CLI)를 사용하는 경우 `source-access-configurations` 옵션에 이 키를 제공합니다. [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 명령 또는 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 명령과 함께 이 옵션을 포함할 수 있습니다. 예제:

    ```
    aws lambda create-event-source-mapping \
        ...
        --source-access-configurations  '[{"Type":"BASIC_AUTH","URI":"arn:aws:secretsmanager:us-west-2:123456789012:secret:DocDBSecret-AbC4E6"}]' \
        ...
    ```
+ **Amazon DocumentDB 스트림과 관련된 리소스를 관리할 수 있는 권한을 Lambda에 부여해야 합니다.** 함수의 [실행 역할](lambda-intro-execution-role.md)에 다음 권한을 수동으로 추가합니다.
  + [rds:DescribeDBClusters](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBClusters.html)
  + [rds:DescribeDBClusterParameters](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBClusterParameters.html)
  + [rds:DescribeDBSubnetGroups](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DescribeDBSubnetGroups.html)
  + [ec2:CreateNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html)
  + [ec2:DescribeNetworkInterfaces](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html)
  + [ec2:DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
  + [ec2:DeleteNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkInterface.html)
  + [ec2:DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
  + [ec2:DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)
  + [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)
  + [secretsmanager:GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html)
+ **Lambda로 전송하는 Amazon DocumentDB 변경 스트림 이벤트의 크기를 6MB 미만으로 유지해야 합니다.** Lambda는 최대 6MB의 페이로드 크기를 지원합니다. 변경 스트림이 Lambda에 6MB보다 큰 이벤트를 전송하려고 하면 Lambda는 메시지를 삭제하고 `OversizedRecordCount` 지표를 내보냅니다. Lambda는 최대한 모든 지표를 전송합니다.

**참고**  
Lambda 함수의 최대 제한 시간은 일반적으로 15분이지만 Amazon MSK, 자체 관리형 Apache Kafka, Amazon DocumentDB, ActiveMQ 및 RabbitMQ용 Amazon MQ에 대한 이벤트 소스 매핑은 최대 제한 시간이 14분인 함수만 지원합니다. 이 제약 조건에 따라 이벤트 소스 매핑에서 함수 오류 및 재시도를 적절히 처리할 수 있습니다.

## 네트워크 보안 구성
<a name="docdb-network"></a>

이벤트 소스 매핑을 통해 Lambda에 Amazon DocumentDB에 대한 전체 액세스 권한을 부여하려면 클러스터에서 퍼블릭 엔드포인트(퍼블릭 IP 주소)를 사용하거나 클러스터를 생성한 Amazon VPC에 대한 액세스 권한을 제공해야 합니다.

Lambda에서 Amazon DocumentDB를 사용하는 경우 Amazon VPC의 리소스에 대한 액세스 권한을 제공하는 [AWS PrivateLink VPC 엔드포인트를 생성](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html)합니다.

**참고**  
이벤트 폴러에 기본(온디맨드) 모드를 사용하는 이벤트 소스 매핑을 포함하는 함수에 대해 AWS PrivateLink VPC 엔드포인트가 필요합니다. 이벤트 소스 매핑에서 [프로비저닝된 모드](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)를 사용하는 경우 AWS PrivateLink VPC 엔드포인트를 구성하지 않아도 됩니다.

다음 리소스에 대한 액세스를 제공하는 엔드포인트를 생성합니다.
+  Lambda - Lambda 서비스 위탁자에 대한 엔드포인트를 생성합니다.
+  AWS STS - 서비스 위탁자가 사용자를 대신하여 역할을 맡을 수 있도록 AWS STS에 대한 엔드포인트를 생성합니다.
+  Secrets Manager - 클러스터에서 Secrets Manager를 사용하여 자격 증명을 저장하는 경우 Secrets Manager를 위한 엔드포인트를 생성합니다.

또는 Amazon VPC의 각 퍼블릭 서브넷에 NAT 게이트웨이를 구성합니다. 자세한 내용은 [VPC 연결 Lambda 함수에 대한 인터넷 액세스 활성화](configuration-vpc-internet.md) 섹션을 참조하세요.

Amazon DocumentDB에 대한 이벤트 소스 매핑을 생성하면 Lambda는 Amazon VPC에 대해 구성된 서브넷과 보안 그룹을 위한 탄력적 네트워크 인터페이스(ENI)가 이미 존재하는지 확인합니다. Lambda가 기존 ENI를 찾으면 이를 재사용하려고 시도합니다. 그렇지 않으면 Lambda가 이벤트 소스에 연결하고 함수를 간접 호출하기 위해 새 ENI를 생성합니다.

**참고**  
Lambda 함수는 항상 Lambda 서비스가 소유한 VPC 내에서 실행됩니다. 함수의 VPC 구성은 이벤트 소스 매핑에 영향을 미치지 않습니다. 이벤트 소스의 네트워킹 구성에 따라 Lambda가 이벤트 소스에 연결하는 방식이 결정됩니다.

클러스터가 포함된 Amazon VPC에 대한 보안 그룹을 구성합니다. 기본적으로 Amazon DocumentDB는 `27017` 포트를 사용합니다.
+ 인바운드 규칙 – 이벤트 소스와 연결된 보안 그룹에 대한 기본 브로커 포트의 모든 트래픽을 허용합니다. 또는 자체 참조 보안 그룹 규칙을 사용하여 동일한 보안 그룹 내의 인스턴스에서 액세스를 허용할 수 있습니다.
+ 아웃바운드 규칙 - 함수가 AWS 서비스와 통신해야 하는 경우 외부 대상에 대한 포트 `443`의 모든 트래픽을 허용합니다. 다른 AWS 서비스와 통신할 필요가 없는 경우 자체 참조 보안 그룹 규칙을 사용하여 브로커에 대한 액세스를 제한할 수도 있습니다.
+ Amazon VPC 엔드포인트 인바운드 규칙 - Amazon VPC 엔드포인트를 사용하는 경우 Amazon VPC 엔드포인트와 연결된 보안 그룹이 클러스터 보안 그룹에서 `443` 포트의 인바운드 트래픽을 허용해야 합니다.

클러스터가 인증을 사용하는 경우 Secrets Manager 엔드포인트에 대한 엔드포인트 정책을 제한할 수도 있습니다. Secrets Manager API를 직접 호출하기 위해 Lambda는 Lambda 서비스 위탁자가 아닌 함수 역할을 사용합니다.

**Example VPC 엔드포인트 정책 — Secrets Manager 엔드포인트**  

```
{
      "Statement": [
          {
              "Action": "secretsmanager:GetSecretValue",
              "Effect": "Allow",
              "Principal": {
                  "AWS": [
                      "arn:aws::iam::123456789012:role/my-role"
                  ]
              },
              "Resource": "arn:aws::secretsmanager:us-west-2:123456789012:secret:my-secret"
          }
      ]
  }
```

Amazon VPC 엔드포인트를 사용하는 경우 AWS에서는 엔드포인트의 탄력적 네트워크 인터페이스(ENI)를 사용하여 함수를 간접 호출하도록 API 직접 호출을 라우팅합니다. Lambda 서비스 위탁자는 해당 ENI를 사용하는 모든 역할과 함수에서 `lambda:InvokeFunction`을 직접 호출해야 합니다.

기본적으로 Amazon VPC 엔드포인트에는 리소스에 대한 광범위한 액세스를 허용하는 개방형 IAM 정책이 있습니다. 모범 사례는 해당 엔드포인트를 사용하여 필요한 작업을 수행하도록 이러한 정책을 제한하는 것입니다. 이벤트 소스 매핑이 Lambda 함수를 간접 호출할 수 있도록 하려면 VPC 엔드포인트 정책에서 Lambda 서비스 위탁자가 `sts:AssumeRole` 및 `lambda:InvokeFunction`을 직접 호출할 수 있도록 허용해야 합니다. 조직 내에서 발생하는 API 직접 호출만 허용하도록 VPC 엔드포인트 정책을 제한하면 이벤트 소스 매핑이 제대로 작동하지 않으므로 이 정책에는 `"Resource": "*"`가 필요합니다.

다음 예제 VPC 엔드포인트 정책은 AWS STS 및 Lambda 엔드포인트에 대해 Lambda 서비스 위탁자에 필요한 액세스 권한을 부여하는 방법을 안내합니다.

**Example VPC 엔드포인트 정책 - AWS STS 엔드포인트**  

```
{
      "Statement": [
          {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
    }
```

**Example VPC 엔드포인트 정책 - Lambda 엔드포인트**  

```
{
      "Statement": [
          {
              "Action": "lambda:InvokeFunction",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
  }
```

## Amazon DocumentDB 이벤트 소스 매핑 생성(콘솔)
<a name="docdb-configuration"></a>

Lambda 함수가 Amazon DocumentDB 클러스터의 변경 스트림에서 읽을 수 있도록 [이벤트 소스 매핑](invocation-eventsourcemapping.md)을 생성합니다. 이 섹션에서는 Lambda 콘솔에서 이를 수행하는 방법을 설명합니다. AWS SDK 및 AWS CLI 지침은 [Amazon DocumentDB 이벤트 소스 매핑 생성(SDK 또는 CLI)](#docdb-api) 섹션을 참조하세요.

**Amazon DocumentDB 이벤트 소스 매핑 생성(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

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

1. **함수 개요(Function overview)**에서 **트리거 추가(Add trigger)**를 선택합니다.

1. **트리거 구성** 아래의 드롭다운 목록에서 **DocumentDB**를 선택합니다.

1. 필요한 옵션을 구성한 다음 **추가**를 선택합니다.

Lambda는 Amazon DocumentDB 이벤트 소스에 대해 다음과 같은 옵션을 지원합니다.
+ **DocumentDB 클러스터** - Amazon DocumentDB 클러스터를 선택합니다.
+ **트리거 활성화** - 즉시 트리거를 활성화할지 여부를 선택합니다. 이 확인란을 선택하면 이벤트 소스 매핑을 생성할 때 함수가 지정된 Amazon DocumentDB 변경 스트림으로부터 즉시 트래픽을 수신하기 시작합니다. 테스트할 이벤트 소스 매핑을 비활성화된 상태로 생성하려면 확인란 선택을 취소하는 것이 좋습니다. 생성 후에는 언제든지 이벤트 소스 매핑을 활성화할 수 있습니다.
+ **데이터베이스 이름 —** 클러스터 내에서 사용할 데이터베이스의 이름을 입력합니다.
+ (선택 사항) **컬렉션 이름** - 사용할 데이터베이스 내의 컬렉션 이름을 입력합니다. 컬렉션을 지정하지 않으면 Lambda는 데이터베이스의 각 컬렉션에서 모든 이벤트를 수신합니다.
+ **배치 크기 —** 단일 배치에서 검색할 최대 메시지 수를 설정합니다. 최대 10,000. 기본 크기는 100입니다.
+ **시작 위치 —** 스트림에서 레코드 읽기를 시작할 위치를 선택합니다.
  + **최신 —** 스트림에 추가된 새 레코드만 처리합니다. 함수는 Lambda가 이벤트 소스 생성을 완료한 후에만 레코드 처리를 시작합니다. 즉, 이벤트 소스가 성공적으로 생성될 때까지 일부 레코드가 삭제될 수 있습니다.
  + **수평 트리밍** – 스트림의 모든 레코드를 처리합니다. Lambda는 클러스터의 로그 보존 기간을 사용하여 이벤트 읽기를 시작할 위치를 결정합니다. 구체적으로 Lambda는 `current_time - log_retention_duration`에서 읽기를 시작합니다. Lambda가 모든 이벤트를 제대로 읽으려면 이 타임스탬프 전에 변경 스트림이 이미 활성화되어 있어야 합니다.
  + **타임스탬프** – 특정 시간에 시작하는 레코드를 시작합니다. Lambda가 모든 이벤트를 제대로 읽으려면 지정된 타임스탬프 전에 변경 스트림이 이미 활성화되어 있어야 합니다.
+ **인증 —** 클러스터에서 브로커에 액세스하기 위한 인증 방법을 선택합니다.
  + **BASIC\$1AUTH —** 기본 인증을 사용하는 경우 클러스터에 액세스하기 위한 자격 증명이 포함된 Secrets Manager 키를 제공해야 합니다.
+ **Secrets Manager 키** - Amazon DocumentDB 클러스터에 액세스하는 데 필요한 인증 세부 정보(사용자 이름 및 암호)가 포함된 Secrets Manager 키를 선택합니다.
+ (선택 사항) **배치 기간** – 함수를 호출하기 전에 레코드를 수집할 최대 시간(초)을 최대 300초로 설정합니다.
+ (선택 사항) **전체 문서 구성** - 문서 업데이트 작업의 경우 스트림으로 전송할 내용을 선택합니다. 기본값은 `Default`이며, 이는 각 변경 스트림 이벤트에 대해 Amazon DocumentDB가 변경 내용을 설명하는 델타만 전송한다는 것을 의미합니다. 이 필드에 대한 자세한 내용은 MongoDB Javadoc API 설명서의 [FullDocument](https://mongodb.github.io/mongo-java-driver/3.9/javadoc/com/mongodb/client/model/changestream/FullDocument.html#DEFAULT)를 참조하세요.
  + **기본값 —** Lambda는 변경 사항을 설명하는 문서의 일부만 전송합니다.
  + **UpdateLookup —** Lambda는 전체 문서의 복사본과 함께 변경 사항을 설명하는 델타를 전송합니다.

## Amazon DocumentDB 이벤트 소스 매핑 생성(SDK 또는 CLI)
<a name="docdb-api"></a>

[AWS SDK](https://aws.amazon.com/developer/tools/)를 사용하여 Amazon DocumentDB 이벤트 소스 매핑을 생성하거나 관리하려면 다음 API 작업을 사용합니다.
+ [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html)
+ [ListEventSourceMappings](https://docs.aws.amazon.com/lambda/latest/api/API_ListEventSourceMappings.html)
+ [GetEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_GetEventSourceMapping.html)
+ [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html)
+ [DeleteEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_DeleteEventSourceMapping.html)

AWS CLI를 사용하여 이벤트 소스 매핑을 생성하려면 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 명령을 사용합니다. 다음 예제에서는 이 명령을 사용하여 `my-function`이라는 함수를 Amazon DocumentDB 변경 스트림에 매핑합니다. 이벤트 소스는 Amazon 리소스 이름(ARN)으로 지정되고, 배치 크기는 500이며 Unix 시간의 타임스탬프부터 시작합니다. 또한 이 명령은 Lambda가 Amazon DocumentDB에 연결하는 데 사용하는 Secrets Manager 키를 지정합니다. 데이터베이스와 읽을 컬렉션을 지정하는 `document-db-event-source-config` 파라미터도 포함되어 있습니다.

```
aws lambda create-event-source-mapping --function-name my-function \
    --event-source-arn arn:aws:rds:us-west-2:123456789012:cluster:privatecluster7de2-epzcyvu4pjoy
    --batch-size 500 \
    --starting-position AT_TIMESTAMP \
    --starting-position-timestamp 1541139109 \
    --source-access-configurations '[{"Type":"BASIC_AUTH","URI":"arn:aws:secretsmanager:us-east-1:123456789012:secret:DocDBSecret-BAtjxi"}]' \
    --document-db-event-source-config '{"DatabaseName":"test_database", "CollectionName": "test_collection"}' \
```

다음과 유사한 출력 화면이 표시되어야 합니다.

```
{
    "UUID": "2b733gdc-8ac3-cdf5-af3a-1827b3b11284",
    "BatchSize": 500,
    "DocumentDBEventSourceConfig": {
        "CollectionName": "test_collection",
        "DatabaseName": "test_database",
        "FullDocument": "Default"
    },
    "MaximumBatchingWindowInSeconds": 0,
    "EventSourceArn": "arn:aws:rds:us-west-2:123456789012:cluster:privatecluster7de2-epzcyvu4pjoy",
    "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:my-function",
    "LastModified": 1541348195.412,
    "LastProcessingResult": "No records processed",
    "State": "Creating",
    "StateTransitionReason": "User action"
}
```

생성 후 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 명령을 사용하여 Amazon DocumentDB 이벤트 소스에 대한 설정을 업데이트합니다. 다음 예제는 배치 크기를 1,000으로 업데이트하고 배치 기간을 10초로 업데이트합니다. 이 명령을 실행하려면 `list-event-source-mapping` 명령 또는 Lambda 콘솔을 사용하여 검색할 수 있는 이벤트 소스 매핑의 UUID가 필요합니다.

```
aws lambda update-event-source-mapping --function-name my-function \
    --uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
    --batch-size 1000 \
    --batch-window 10
```

다음과 유사한 출력이 표시되어야 합니다.

```
{
    "UUID": "2b733gdc-8ac3-cdf5-af3a-1827b3b11284",
    "BatchSize": 500,
    "DocumentDBEventSourceConfig": {
        "CollectionName": "test_collection",
        "DatabaseName": "test_database",
        "FullDocument": "Default"
    },
    "MaximumBatchingWindowInSeconds": 0,
    "EventSourceArn": "arn:aws:rds:us-west-2:123456789012:cluster:privatecluster7de2-epzcyvu4pjoy",
    "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:my-function",
    "LastModified": 1541359182.919,
    "LastProcessingResult": "OK",
    "State": "Updating",
    "StateTransitionReason": "User action"
}
```

Lambda는 설정을 비동기식으로 업데이트하므로 프로세스가 완료된 후에야 출력에 이러한 변경 사항이 표시되지 않을 수 있습니다. 이벤트 소스 매핑의 현재 설정을 보려면 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html) 명령을 사용합니다.

```
aws lambda get-event-source-mapping --uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b
```

다음과 유사한 출력이 표시되어야 합니다.

```
{
    "UUID": "2b733gdc-8ac3-cdf5-af3a-1827b3b11284",
    "DocumentDBEventSourceConfig": {
        "CollectionName": "test_collection",
        "DatabaseName": "test_database",
        "FullDocument": "Default"
    },
    "BatchSize": 1000,
    "MaximumBatchingWindowInSeconds": 10,
    "EventSourceArn": "arn:aws:rds:us-west-2:123456789012:cluster:privatecluster7de2-epzcyvu4pjoy",
    "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:my-function",
    "LastModified": 1541359182.919,
    "LastProcessingResult": "OK",
    "State": "Enabled",
    "StateTransitionReason": "User action"
}
```

Amazon DocumentDB 이벤트 소스 매핑을 삭제하려면 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/delete-event-source-mapping.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/delete-event-source-mapping.html) 명령을 사용합니다.

```
aws lambda delete-event-source-mapping \
    --uuid 2b733gdc-8ac3-cdf5-af3a-1827b3b11284
```

## 폴링 및 스트리밍 시작 위치
<a name="docdb-stream-polling"></a>

이벤트 소스 매핑 생성 및 업데이트 중 스트림 폴링은 최종적으로 일관됩니다.
+ 이벤트 소스 매핑 생성 중 스트림에서 이벤트 폴링을 시작하는 데 몇 분 정도 걸릴 수 있습니다.
+ 이벤트 소스 매핑 업데이트 중 스트림에서 이벤트 폴링을 중지했다가 다시 시작하는 데 몇 분 정도 걸릴 수 있습니다.

이 동작은 스트림의 시작 위치로 `LATEST`를 지정하면 이벤트 소스 매핑이 생성 또는 업데이트 중에 이벤트를 놓칠 수 있음을 의미합니다. 누락된 이벤트가 없도록 하기 위해서는 스트림 시작 위치를 `TRIM_HORIZON` 또는 `AT_TIMESTAMP`로 지정하세요.

## Amazon DocumentDB 이벤트 소스 모니터링
<a name="docdb-monitoring"></a>

Amazon DocumentDB 이벤트 소스를 모니터링하는 데 도움이 되도록 Lambda는 함수가 레코드 배치 처리를 완료할 때 `IteratorAge` 지표를 내보냅니다. *반복기 수명*은 가장 최근 이벤트의 타임스탬프와 현재 타임스탬프 간의 차이입니다. 기본적으로 `IteratorAge` 지표는 배치에서 마지막으로 처리된 레코드가 얼마나 오래되었는지를 나타냅니다. 함수가 현재 새 이벤트를 처리하고 있다면 반복기 수명을 사용하여 레코드가 추가된 후 함수에서 레코드를 처리할 때까지 지연 시간을 추정할 수 있습니다. `IteratorAge`의 증가 추세는 함수에 문제가 있음을 나타낼 수 있습니다. 자세한 내용은 [Lambda에서 CloudWatch 지표 사용](monitoring-metrics.md) 섹션을 참조하세요.

Amazon DocumentDB 변경 스트림은 이벤트 간의 큰 시간 간격을 처리하는 데 최적화되지 않았습니다. Amazon DocumentDB 이벤트 소스에서 오랜 기간 동안 이벤트가 수신되지 않으면 Lambda가 이벤트 소스 매핑을 비활성화할 수 있습니다. 이 기간은 클러스터의 크기와 기타 워크로드에 따라 몇 주에서 몇 개월까지 다양할 수 있습니다.

Lambda는 최대 6MB의 페이로드를 지원합니다. 하지만 Amazon DocumentDB 변경 스트림 이벤트의 크기는 최대 16MB일 수 있습니다. 변경 스트림이 Lambda에 6MB보다 큰 변경 스트림 이벤트를 전송하려고 하면 Lambda는 메시지를 삭제하고 `OversizedRecordCount` 지표를 내보냅니다. Lambda는 최대한 모든 지표를 전송합니다.

# 자습서: Amazon DocumentDB Streams와 함께 AWS Lambda 사용
<a name="with-documentdb-tutorial"></a>

 이 자습서에서는 Amazon DocumentDB(MongoDB 호환) 변경 스트림의 이벤트를 사용하는 기본 Lambda 함수를 생성합니다. 이 자습서를 완료하는 과정에서 다음 단계를 거치게 됩니다.
+ Amazon DocumentDB 클러스터를 설정하고, 연결하고, 변경 스트림을 활성화합니다.
+ Lambda 함수를 생성하고 Amazon DocumentDB 클러스터를 함수의 이벤트 소스로 구성합니다.
+ Amazon DocumentDB 데이터베이스에 항목을 삽입하여 설정을 테스트합니다.

## Amazon DocumentDB 클러스터 생성
<a name="docdb-documentdb-cluster"></a>

1. [Amazon DocumentDB 콘솔](https://console.aws.amazon.com/docdb/home#)을 엽니다. **클러스터**에서 **생성**을 선택합니다.

1. 다음 구성을 사용하여 클러스터를 생성합니다.
   + **클러스터 유형**에서 **인스턴스 기반 클러스터**를 선택합니다. 이는 기본 옵션입니다.
   + **클러스터 구성**에서 **엔진 버전** 5.0.0이 선택되어 있는지 확인합니다. 이는 기본 옵션입니다.
   + **인스턴스 구성**에서
     + **DB 인스턴스 클래스**에서 **메모리 최적화 클래스**를 선택합니다. 이는 기본 옵션입니다.
     + **일반 복제본 인스턴스 수**에서 1을 선택합니다.
     + **인스턴스 클래스**에서 기본 선택을 사용합니다.
   + **인증**에 기본 사용자 이름을 입력하고 **자체 관리형**을 선택합니다. 암호를 입력한 다음 확인합니다.
   + 다른 기본 설정을 모두 유지합니다.

1. **클러스터 생성**을 선택합니다.

## Secrets Manager에서 보안 암호 생성
<a name="docdb-secret-in-secrets-manager"></a>

Amazon DocumentDB에서 클러스터를 생성하는 동안 AWS Secrets Manager 보안 암호를 생성하여 데이터베이스 자격 증명을 저장합니다. 이후 단계에서 Lambda 이벤트 소스 매핑을 생성할 때 이 보안 암호를 제공합니다.

**Secrets Manager에서 보안 암호 생성**

1. [Secrets Manager](https://console.aws.amazon.com/secretsmanager/home#) 콘솔을 열고 **새 보안 암호 저장**을 선택합니다.

1. **보안 암호 유형 선택)**에서 다음 옵션을 선택합니다.
   + **기본 세부 정보**에서
     + **보안 암호 유형**: Amazon DocumentDB 데이터베이스의 자격 증명
     + **자격 증명**에 Amazon DocumentDB 클러스터를 생성하는 데 사용한 동일한 사용자 이름과 암호를 입력합니다.
     + **데이터베이스**: Amazon DocumentDB 클러스터를 선택합니다.
     + **다음**을 선택합니다.

1. **보안 암호 구성**에서 다음 옵션을 선택합니다.
   + **비밀 이름**: `DocumentDBSecret`
   + **다음**을 선택합니다.

1. **다음**을 선택합니다.

1. **저장(Store)**을 선택합니다.

1. 콘솔을 새로 고쳐 `DocumentDBSecret` 보안 암호가 성공적으로 저장되었는지 확인합니다.

**보안 ARN**을 기록해 둡니다. 이는 이후 단계에서 필요합니다.

## 클러스터에 연결
<a name="docdb-connect-to-cluster"></a>

**AWS CloudShell을 사용하여 Amazon DocumentDB 클러스터에 연결**

1. Amazon DocumentDB 관리 콘솔의 **클러스터**에서 생성한 클러스터를 찾습니다. 클러스터 옆의 확인란을 클릭하여 클러스터를 선택합니다.

1. **클러스터에 연결**을 선택합니다. CloudShell **명령 실행** 화면이 나타납니다.

1. **새 환경 이름** 필드에 ‘테스트’와 같은 고유한 이름을 입력하고 **생성 및 실행**을 선택합니다.

1. 메시지가 표시되면 암호를 입력합니다. 프롬프트가 `rs0 [direct: primary] <env-name>>`이 되면 Amazon DocumentDB 클러스터에 성공적으로 연결된 것입니다.

## 변경 스트림 활성화
<a name="docdb-activate-change-streams"></a>

이 자습서에서는 Amazon DocumentDB 클러스터에 있는 `docdbdemo` 데이터베이스의 `products` 컬렉션에 대한 변경 사항을 추적합니다. [변경 스트림](https://docs.aws.amazon.com/documentdb/latest/developerguide/change_streams.html)을 활성화하면 됩니다.

**클러스터 내에 새 데이터베이스 생성**

1. 다음 명령을 실행하여 `docdbdemo`이라는 새 데이터베이스를 생성합니다.

   ```
   use docdbdemo
   ```

1. 터미널 창에서 다음 명령을 사용하여 `docdbdemo`에 레코드를 삽입합니다.

   ```
   db.products.insertOne({"hello":"world"})
   ```

   다음과 같이 출력되어야 합니다.

   ```
   {
     acknowledged: true,
     insertedId: ObjectId('67f85066ca526410fd531d59')
   }
   ```

1. 그리고 다음 명령을 사용하여 `docdbdemo` 데이터베이스의 `products` 컬렉션에서 변경 스트림을 활성화합니다.

   ```
   db.adminCommand({modifyChangeStreams: 1,
       database: "docdbdemo",
       collection: "products", 
       enable: true});
   ```

    다음과 유사한 출력 화면이 표시되어야 합니다.

   ```
   { "ok" : 1, "operationTime" : Timestamp(1680126165, 1) }
   ```

## 인터페이스 VPC 엔드포인트 생성
<a name="docdb-create-interface-vpc-endpoints"></a>

다음으로 [인터페이스 VPC 엔드포인트](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html#create-interface-endpoint-aws)를 생성하여 Lambda와 Secrets Manager(나중에 클러스터 액세스 자격 증명을 저장하는 데 사용됨)가 기본 VPC에 연결할 수 있는지 확인합니다.

**인터페이스 VPC 엔드포인트 생성**

1. [VPC 콘솔](https://console.aws.amazon.com/vpc/home#)을 엽니다. 왼쪽 메뉴의 **Virtual Private Cloud**에서 **엔드포인트**를 선택합니다.

1. **엔드포인트 생성**을 선택합니다. 다음 구성으로 엔드포인트를 생성합니다.
   + **이름 태그**에 `lambda-default-vpc`를 입력합니다.
   + **서비스 범주**에서 AWS 서비스를 선택합니다.
   + **서비스** 검색 상자에 `lambda`를 입력합니다. `com.amazonaws.<region>.lambda` 형식의 서비스를 선택합니다.
   + **VPC**에서 Amazon DocumentDB 클러스터가 있는 VPC를 선택합니다. 이는 일반적으로 [기본 VPC](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html)입니다.
   + **서브넷**에서 각 가용 영역 옆의 확인란을 선택합니다. 각 가용 영역에 대한 올바른 서브넷 ID를 선택합니다.
   + **IP 주소 유형**에서 IPv4를 선택합니다.
   + **보안 그룹**에서 Amazon DocumentDB 클러스터가 사용하는 보안 그룹을 선택합니다. 이는 일반적으로 `default` 보안 그룹입니다.
   + 다른 기본 설정을 모두 유지합니다.
   + **엔드포인트 생성**을 선택합니다.

1. 다시 **엔드포인트 생성**을 선택합니다. 다음 구성으로 엔드포인트를 생성합니다.
   + **이름 태그**에 `secretsmanager-default-vpc`를 입력합니다.
   + **서비스 범주**에서 AWS 서비스를 선택합니다.
   + **서비스** 검색 상자에 `secretsmanager`를 입력합니다. `com.amazonaws.<region>.secretsmanager` 형식의 서비스를 선택합니다.
   + **VPC**에서 Amazon DocumentDB 클러스터가 있는 VPC를 선택합니다. 이는 일반적으로 [기본 VPC](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html)입니다.
   + **서브넷**에서 각 가용 영역 옆의 확인란을 선택합니다. 각 가용 영역에 대한 올바른 서브넷 ID를 선택합니다.
   + **IP 주소 유형**에서 IPv4를 선택합니다.
   + **보안 그룹**에서 Amazon DocumentDB 클러스터가 사용하는 보안 그룹을 선택합니다. 이는 일반적으로 `default` 보안 그룹입니다.
   + 다른 기본 설정을 모두 유지합니다.
   + **엔드포인트 생성**을 선택합니다.

 이것으로 이 자습서의 클러스터 설정 부분이 완료되었습니다.

## 실행 역할 생성
<a name="docdb-create-the-execution-role"></a>

 다음 단계에서는 Lambda 함수를 생성합니다. 먼저 함수에 클러스터에 액세스할 수 있는 권한을 제공하는 실행 역할을 생성해야 합니다. 이 작업을 수행하려면 먼저 IAM 정책을 생성한 다음 이 정책을 IAM 역할에 연결합니다.

**IAM 정책 생성**

1. IAM 콘솔에서 [정책 페이지](https://console.aws.amazon.com/iam/home#/policies)를 열고 **정책 생성**을 선택합니다.

1. **JSON** 탭을 선택합니다. 다음 정책에서 명령문의 마지막 줄에 있는 Secrets Manager 리소스 ARN을 이전의 보안 암호 ARN으로 바꾸고 정책을 편집기에 복사합니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Sid": "LambdaESMNetworkingAccess",
               "Effect": "Allow",
               "Action": [
                   "ec2:CreateNetworkInterface",
                   "ec2:DescribeNetworkInterfaces",
                   "ec2:DescribeVpcs",
                   "ec2:DeleteNetworkInterface",
                   "ec2:DescribeSubnets",
                   "ec2:DescribeSecurityGroups",
                   "kms:Decrypt"
               ],
               "Resource": "*"
           },
           {
               "Sid": "LambdaDocDBESMAccess",
               "Effect": "Allow",
               "Action": [
                   "rds:DescribeDBClusters",
                   "rds:DescribeDBClusterParameters",
                   "rds:DescribeDBSubnetGroups"
               ],
               "Resource": "*"
           },
           {
               "Sid": "LambdaDocDBESMGetSecretValueAccess",
               "Effect": "Allow",
               "Action": [
                   "secretsmanager:GetSecretValue"
               ],
               "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:DocumentDBSecret"
           }
       ]
   }
   ```

------

1. **다음: 태그**를 선택하고 **다음: 검토**를 선택합니다.

1. **이름**에서 `AWSDocumentDBLambdaPolicy`을 입력합니다.

1. **정책 생성**을 선택합니다.

**IAM 역할을 만들려면**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 열고 **역할 생성**을 선택합니다.

1. **신뢰할 수 있는 엔터티 선택**에서 다음 옵션을 선택합니다.
   + **신뢰할 수 있는 엔티티 유형**: AWS 서비스
   + **서비스 또는 사용 사례**: Lambda
   + **다음**을 선택합니다.

1. **권한 추가**에서 방금 생성한 `AWSDocumentDBLambdaPolicy` 정책과 `AWSLambdaBasicExecutionRole`을 선택하여 함수에 Amazon CloudWatch Logs에 쓸 수 있는 권한을 부여합니다.

1. **다음**을 선택합니다.

1. **역할 이름**에 `AWSDocumentDBLambdaExecutionRole`을 입력합니다.

1. **역할 생성**을 선택합니다.

## Lambda 함수 생성
<a name="docdb-create-the-lambda-function"></a>

이 자습서에서는 Python 3.14 런타임을 사용하지만 다른 런타임의 예제 코드 파일도 제공했습니다. 다음 상자에서 탭을 선택하여 관심 있는 런타임에 대한 코드를 볼 수 있습니다.

코드가 Amazon DocumentDB 이벤트 입력을 수신하고 이벤트에 포함된 메시지를 처리합니다.

**Lambda 함수를 만들려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. **함수 생성**을 선택합니다.

1. **새로 작성**을 선택합니다.

1. **기본 정보**에서 다음과 같이 합니다.

   1. **함수 이름**에 `ProcessDocumentDBRecords`을 입력합니다.

   1. **런타임**에서 **Python 3.14**를 선택합니다.

   1. **아키텍처**에서는 **x86\$164**를 선택합니다.

1. **기본 실행 역할 변경** 탭에서 다음을 수행합니다.

   1. 탭을 확장한 다음 **기존 역할 사용**을 선택합니다.

   1. 이전에 생성한 `AWSDocumentDBLambdaExecutionRole`을 선택합니다.

1. **함수 생성**을 선택합니다.

**함수 코드 배포**

1. 다음 상자에서 **Python** 탭을 선택하고 코드를 복사합니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 Amazon DocumentDB 이벤트 소비  

   ```
   using Amazon.Lambda.Core;
   using System.Text.Json;
   using System;
   using System.Collections.Generic;
   using System.Text.Json.Serialization;
   //Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
   [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
   
   namespace LambdaDocDb;
   
   public class Function
   {
       
        /// <summary>
       /// Lambda function entry point to process Amazon DocumentDB events.
       /// </summary>
       /// <param name="event">The Amazon DocumentDB event.</param>
       /// <param name="context">The Lambda context object.</param>
       /// <returns>A string to indicate successful processing.</returns>
       public string FunctionHandler(Event evnt, ILambdaContext context)
       {
           
           foreach (var record in evnt.Events)
           {
               ProcessDocumentDBEvent(record, context);
           }
   
           return "OK";
       }
   
        private void ProcessDocumentDBEvent(DocumentDBEventRecord record, ILambdaContext context)
       {
           
           var eventData = record.Event;
           var operationType = eventData.OperationType;
           var databaseName = eventData.Ns.Db;
           var collectionName = eventData.Ns.Coll;
           var fullDocument = JsonSerializer.Serialize(eventData.FullDocument, new JsonSerializerOptions { WriteIndented = true });
   
           context.Logger.LogLine($"Operation type: {operationType}");
           context.Logger.LogLine($"Database: {databaseName}");
           context.Logger.LogLine($"Collection: {collectionName}");
           context.Logger.LogLine($"Full document:\n{fullDocument}");
       }
   
   
   
       public class Event
       {
           [JsonPropertyName("eventSourceArn")]
           public string EventSourceArn { get; set; }
   
           [JsonPropertyName("events")]
           public List<DocumentDBEventRecord> Events { get; set; }
   
           [JsonPropertyName("eventSource")]
           public string EventSource { get; set; }
       }
   
       public class DocumentDBEventRecord
       {
           [JsonPropertyName("event")]
           public EventData Event { get; set; }
       }
   
       public class EventData
       {
           [JsonPropertyName("_id")]
           public IdData Id { get; set; }
   
           [JsonPropertyName("clusterTime")]
           public ClusterTime ClusterTime { get; set; }
   
           [JsonPropertyName("documentKey")]
           public DocumentKey DocumentKey { get; set; }
   
           [JsonPropertyName("fullDocument")]
           public Dictionary<string, object> FullDocument { get; set; }
   
           [JsonPropertyName("ns")]
           public Namespace Ns { get; set; }
   
           [JsonPropertyName("operationType")]
           public string OperationType { get; set; }
       }
   
       public class IdData
       {
           [JsonPropertyName("_data")]
           public string Data { get; set; }
       }
   
       public class ClusterTime
       {
           [JsonPropertyName("$timestamp")]
           public Timestamp Timestamp { get; set; }
       }
   
       public class Timestamp
       {
           [JsonPropertyName("t")]
           public long T { get; set; }
   
           [JsonPropertyName("i")]
           public int I { get; set; }
       }
   
       public class DocumentKey
       {
           [JsonPropertyName("_id")]
           public Id Id { get; set; }
       }
   
       public class Id
       {
           [JsonPropertyName("$oid")]
           public string Oid { get; set; }
       }
   
       public class Namespace
       {
           [JsonPropertyName("db")]
           public string Db { get; set; }
   
           [JsonPropertyName("coll")]
           public string Coll { get; set; }
       }
   }
   ```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 Amazon DocumentDB 이벤트 소비  

   ```
   package main
   
   import (
   	"context"
   	"encoding/json"
   	"fmt"
   
   	"github.com/aws/aws-lambda-go/lambda"
   )
   
   type Event struct {
   	Events []Record `json:"events"`
   }
   
   type Record struct {
   	Event struct {
   		OperationType string `json:"operationType"`
   		NS            struct {
   			DB   string `json:"db"`
   			Coll string `json:"coll"`
   		} `json:"ns"`
   		FullDocument interface{} `json:"fullDocument"`
   	} `json:"event"`
   }
   
   func main() {
   	lambda.Start(handler)
   }
   
   func handler(ctx context.Context, event Event) (string, error) {
   	fmt.Println("Loading function")
   	for _, record := range event.Events {
   		logDocumentDBEvent(record)
   	}
   
   	return "OK", nil
   }
   
   func logDocumentDBEvent(record Record) {
   	fmt.Printf("Operation type: %s\n", record.Event.OperationType)
   	fmt.Printf("db: %s\n", record.Event.NS.DB)
   	fmt.Printf("collection: %s\n", record.Event.NS.Coll)
   	docBytes, _ := json.MarshalIndent(record.Event.FullDocument, "", "  ")
   	fmt.Printf("Full document: %s\n", string(docBytes))
   }
   ```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda로 Amazon DocumentDB 이벤트 소비  

   ```
   import java.util.List;
   import java.util.Map;
   
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   
   public class Example implements RequestHandler<Map<String, Object>, String> {
   
       @SuppressWarnings("unchecked")
       @Override
       public String handleRequest(Map<String, Object> event, Context context) {
           List<Map<String, Object>> events = (List<Map<String, Object>>) event.get("events");
           for (Map<String, Object> record : events) {
               Map<String, Object> eventData = (Map<String, Object>) record.get("event");
               processEventData(eventData);
           }
   
           return "OK";
       }
   
       @SuppressWarnings("unchecked")
       private void processEventData(Map<String, Object> eventData) {
           String operationType = (String) eventData.get("operationType");
           System.out.println("operationType: %s".formatted(operationType));
   
           Map<String, Object> ns = (Map<String, Object>) eventData.get("ns");
   
           String db = (String) ns.get("db");
           System.out.println("db: %s".formatted(db));
           String coll = (String) ns.get("coll");
           System.out.println("coll: %s".formatted(coll));
   
           Map<String, Object> fullDocument = (Map<String, Object>) eventData.get("fullDocument");
           System.out.println("fullDocument: %s".formatted(fullDocument));
       }
   
   }
   ```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda로 Amazon DocumentDB 이벤트 소비  

   ```
   console.log('Loading function');
   exports.handler = async (event, context) => {
       event.events.forEach(record => {
           logDocumentDBEvent(record);
       });
       return 'OK';
   };
   
   const logDocumentDBEvent = (record) => {
       console.log('Operation type: ' + record.event.operationType);
       console.log('db: ' + record.event.ns.db);
       console.log('collection: ' + record.event.ns.coll);
       console.log('Full document:', JSON.stringify(record.event.fullDocument, null, 2));
   };
   ```
TypeScript를 사용하여 Lambda로 Amazon DocumentDB 이벤트 소비  

   ```
   import { DocumentDBEventRecord, DocumentDBEventSubscriptionContext } from 'aws-lambda';
   
   console.log('Loading function');
   
   export const handler = async (
     event: DocumentDBEventSubscriptionContext,
     context: any
   ): Promise<string> => {
     event.events.forEach((record: DocumentDBEventRecord) => {
       logDocumentDBEvent(record);
     });
     return 'OK';
   };
   
   const logDocumentDBEvent = (record: DocumentDBEventRecord): void => {
     console.log('Operation type: ' + record.event.operationType);
     console.log('db: ' + record.event.ns.db);
     console.log('collection: ' + record.event.ns.coll);
     console.log('Full document:', JSON.stringify(record.event.fullDocument, null, 2));
   };
   ```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 Amazon DocumentDB 이벤트 소비  

   ```
   <?php
   
   require __DIR__.'/vendor/autoload.php';
   
   use Bref\Context\Context;
   use Bref\Event\Handler;
   
   class DocumentDBEventHandler implements Handler
   {
       public function handle($event, Context $context): string
       {
   
           $events = $event['events'] ?? [];
           foreach ($events as $record) {
               $this->logDocumentDBEvent($record['event']);
           }
           return 'OK';
       }
   
       private function logDocumentDBEvent($event): void
       {
           // Extract information from the event record
   
           $operationType = $event['operationType'] ?? 'Unknown';
           $db = $event['ns']['db'] ?? 'Unknown';
           $collection = $event['ns']['coll'] ?? 'Unknown';
           $fullDocument = $event['fullDocument'] ?? [];
   
           // Log the event details
   
           echo "Operation type: $operationType\n";
           echo "Database: $db\n";
           echo "Collection: $collection\n";
           echo "Full document: " . json_encode($fullDocument, JSON_PRETTY_PRINT) . "\n";
       }
   }
   return new DocumentDBEventHandler();
   ```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 Amazon DocumentDB 이벤트 소비  

   ```
   import json
   
   def lambda_handler(event, context):
       for record in event.get('events', []):
           log_document_db_event(record)
       return 'OK'
   
   def log_document_db_event(record):
       event_data = record.get('event', {})
       operation_type = event_data.get('operationType', 'Unknown')
       db = event_data.get('ns', {}).get('db', 'Unknown')
       collection = event_data.get('ns', {}).get('coll', 'Unknown')
       full_document = event_data.get('fullDocument', {})
   
       print(f"Operation type: {operation_type}")
       print(f"db: {db}")
       print(f"collection: {collection}")
       print("Full document:", json.dumps(full_document, indent=2))
   ```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 Amazon DocumentDB 이벤트 소비  

   ```
   require 'json'
   
   def lambda_handler(event:, context:)
     event['events'].each do |record|
       log_document_db_event(record)
     end
     'OK'
   end
   
   def log_document_db_event(record)
     event_data = record['event'] || {}
     operation_type = event_data['operationType'] || 'Unknown'
     db = event_data.dig('ns', 'db') || 'Unknown'
     collection = event_data.dig('ns', 'coll') || 'Unknown'
     full_document = event_data['fullDocument'] || {}
   
     puts "Operation type: #{operation_type}"
     puts "db: #{db}"
     puts "collection: #{collection}"
     puts "Full document: #{JSON.pretty_generate(full_document)}"
   end
   ```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-docdb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 Amazon DocumentDB 이벤트 소비  

   ```
   use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
   use aws_lambda_events::{
       event::documentdb::{DocumentDbEvent, DocumentDbInnerEvent},
      };
   
   
   // Built with the following dependencies:
   //lambda_runtime = "0.11.1"
   //serde_json = "1.0"
   //tokio = { version = "1", features = ["macros"] }
   //tracing = { version = "0.1", features = ["log"] }
   //tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
   //aws_lambda_events = "0.15.0"
   
   async fn function_handler(event: LambdaEvent<DocumentDbEvent>) ->Result<(), Error> {
       
       tracing::info!("Event Source ARN: {:?}", event.payload.event_source_arn);
       tracing::info!("Event Source: {:?}", event.payload.event_source);
     
       let records = &event.payload.events;
      
       if records.is_empty() {
           tracing::info!("No records found. Exiting.");
           return Ok(());
       }
   
       for record in records{
           log_document_db_event(record);
       }
   
       tracing::info!("Document db records processed");
   
       // Prepare the response
       Ok(())
   
   }
   
   fn log_document_db_event(record: &DocumentDbInnerEvent)-> Result<(), Error>{
       tracing::info!("Change Event: {:?}", record.event);
       
       Ok(())
   
   }
   
   #[tokio::main]
   async fn main() -> Result<(), Error> {
       tracing_subscriber::fmt()
       .with_max_level(tracing::Level::INFO)
       .with_target(false)
       .without_time()
       .init();
   
       let func = service_fn(function_handler);
       lambda_runtime::run(func).await?;
       Ok(())
       
   }
   ```

------

1. Lambda 콘솔의 **코드 소스** 창에서 Code Editor에 코드를 붙여넣고 Lambda가 생성한 코드를 바꿉니다.

1. **배포** 섹션에서 **배포**를 선택하여 함수의 코드를 업데이트하세요.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

## Lambda 이벤트 소스 매핑 생성
<a name="docdb-create-the-lambda-event-source-mapping"></a>

 Amazon DocumentDB 변경 스트림을 Lambda 함수와 연결하는 이벤트 소스 매핑을 생성합니다. 이 이벤트 소스 매핑을 생성하면 AWS Lambda가 스트림 폴링을 즉시 시작합니다.

**이벤트 소스 매핑 생성**

1. Lambda 콘솔에서 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 앞에서 생성한 `ProcessDocumentDBRecords` 함수를 선택합니다.

1. **구성** 탭을 선택한 다음 왼쪽 메뉴에서 **트리거**를 선택합니다.

1. **트리거 추가**를 선택합니다.

1. **트리거 구성**에서 소스로 **Amazon DocumentDB**를 선택합니다.

1. 다음 구성으로 이벤트 소스 매핑을 생성합니다.
   + **Amazon DocumentDB 클러스터**: 이전에 생성한 클러스터를 선택합니다.
   + **데이터베이스 이름**: docdbdemo
   + **컬렉션 이름**: 제품
   + **배치 크기**: 1
   + **시작 위치**: 최신
   + **인증**: BASIC\$1AUTH
   + **Secrets Manager 키**: Amazon DocumentDB 클러스터의 보안 암호를 선택합니다. 예를 들어, `rds!cluster-12345678-a6f0-52c0-b290-db4aga89274f`라고 합니다.
   + **배치 창**: 1
   + **전체 문서 구성**: UpdateLookup

1. **추가**를 선택합니다. 이벤트 소스 매핑을 생성하는 데 몇 분 정도 걸릴 수 있습니다.

## 함수 테스트
<a name="docdb-test-insert"></a>

이벤트 소스 매핑이 **활성화됨** 상태가 될 때까지 기다립니다. 몇 분 정도 걸릴 수 있습니다. 그런 다음 데이터베이스 레코드를 삽입, 업데이트 및 삭제하여 엔드 투 엔드 설정을 테스트합니다. 시작하기 전:

1. CloudShell 환경에서 [Amazon DocumentDB 클러스터에 다시 연결](#docdb-connect-to-cluster)합니다.

1. 다음 명령을 실행하여 `docdbdemo` 데이터베이스를 사용하고 있는지 확인합니다.

   ```
   use docdbdemo
   ```

### 레코드 삽입
<a name="docdb-test-insert"></a>

`docdbdemo` 데이터베이스의 `products` 컬렉션에 레코드 삽입:

```
db.products.insertOne({"name":"Pencil", "price": 1.00})
```

[CloudWatch Logs를 확인](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-console)하여 함수가 이 이벤트를 성공적으로 처리했는지 확인합니다. 다음과 같은 로그 항목이 표시되어야 합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/documentdb-insert-log.png)


### 레코드 업데이트
<a name="docdb-test-update"></a>

다음 명령을 사용하여 방금 삽입한 레코드를 업데이트합니다.

```
db.products.updateOne(
    { "name": "Pencil" },
    { $set: { "price": 0.50 }}
)
```

[CloudWatch Logs를 확인](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-console)하여 함수가 이 이벤트를 성공적으로 처리했는지 확인합니다. 다음과 같은 로그 항목이 표시되어야 합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/documentdb-update-log.png)


### 레코드 삭제
<a name="docdb-test-delete"></a>

다음 명령을 사용하여 방금 업데이트한 레코드를 삭제합니다.

```
db.products.deleteOne( { "name": "Pencil" } )
```

[CloudWatch Logs를 확인](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-console)하여 함수가 이 이벤트를 성공적으로 처리했는지 확인합니다. 다음과 같은 로그 항목이 표시되어야 합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/documentdb-delete-log.png)


## 문제 해결
<a name="docdb-lambda-troubleshooting"></a>

함수의 CloudWatch 로그에 데이터베이스 이벤트가 없으면 다음을 확인합니다.
+ Lambda 이벤트 소스 매핑(트리거라고도 함)이 **활성화됨** 상태인지 확인합니다. 이벤트 소스 매핑을 생성하는 데 몇 분 정도 걸릴 수 있습니다.
+ 이벤트 소스 매핑이 **활성화됨** 상태이지만 여전히 CloudWatch에 데이터베이스 이벤트가 표시되지 않는 경우
  + 이벤트 소스 매핑의 **데이터베이스 이름**이 `docdbdemo`로 설정되어 있는지 확인합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/documentdb-trigger.png)
  + 이벤트 소스 매핑의 **마지막 처리 결과 필드**에 ‘문제: 연결 오류. 인증이 필요한 경우 VPC가 Secrets Manager뿐만 아니라 Lambda 및 STS에 연결할 수 있어야 합니다.’라는 메시지가 표시되는지 확인합니다. 이 오류가 표시되면 [Lambda 및 Secrets Manager VPC 인터페이스 엔드포인트를 생성](#docdb-create-interface-vpc-endpoints)했는지, 그리고 엔드포인트가 Amazon DocumentDB 클러스터에서 사용하는 것과 동일한 VPC 및 서브넷을 사용하는지 확인합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/documentdb-lastprocessingresult.png)

## 리소스 정리
<a name="docdb-cleanup"></a>

 이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.

**Lambda 함수를 삭제하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 생성한 함수를 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **confirm**를 입력하고 **Delete**(삭제)를 선택합니다.

**집행 역할 삭제**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. 생성한 실행 역할을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 역할의 이름을 입력하고 **Delete**(삭제)를 선택합니다.

**VPC 엔드포인트 삭제**

1. [VPC 콘솔](https://console.aws.amazon.com/vpc/home#)을 엽니다. 왼쪽 메뉴의 **Virtual Private Cloud**에서 **엔드포인트**를 선택합니다.

1. 생성한 엔드포인트를 선택합니다.

1. **작업(Actions)**, **VPC 엔드포인트 삭제(Delete VPC endpoints)**를 차례로 선택합니다.

1. 텍스트 입력 필드에 **delete**을 입력합니다.

1. **삭제**를 선택합니다.

**Amazon DocumentDB 클러스터 삭제**

1. [Amazon DocumentDB 콘솔](https://console.aws.amazon.com/docdb/home#)을 엽니다.

1. 이 자습서용으로 생성한 Amazon DocumentDB 클러스터를 선택하고 삭제 방지를 비활성화합니다.

1. 기본 **클러스터** 페이지에서 Amazon DocumentDB 클러스터를 다시 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. **최종 클러스터 스냅샷 생성**에서 **아니요**를 선택합니다.

1. 텍스트 입력 필드에 **delete**을 입력합니다.

1. **삭제**를 선택합니다.

**Secrets Manager에서 보안 암호 삭제**

1. [Secrets Manager 콘솔](https://console.aws.amazon.com/secretsmanager/home#)을 엽니다.

1. 이 자습서용으로 생성한 보안 암호를 선택합니다.

1. **작업**, **보안 암호 삭제**를 선택합니다.

1. **삭제 예약(Schedule deletion)**을 선택합니다.

# Amazon DynamoDB에서 AWS Lambda 사용
<a name="with-ddb"></a>

**참고**  
Lambda 함수 이외의 대상으로 데이터를 전송하거나 데이터를 전송하기 전에 데이터를 보강하려는 경우 [Amazon EventBridge 파이프](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes.html)를 참조하세요.

AWS Lambda 함수를 사용하여 [Amazon DynamoDB 데이터 스트림](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html)의 레코드를 처리할 수 있습니다. DynamoDB Streams를 사용하여 DynamoDB 테이블이 업데이트될 때마다 추가 작업을 수행하는 Lambda 함수를 트리거할 수 있습니다.

DynamoDB 스트림을 처리할 때, 배치의 일부 레코드가 실패하는 경우 처리 완료된 레코드가 재시도되지 않도록 부분 배치 응답 로직을 구현해야 합니다. Powertools for AWS Lambda의 [배치 프로세서 유틸리티](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)는 Python, TypeScript, .NET 및 Java에서 사용할 수 있으며, 부분 배치 응답 로직을 자동으로 처리하여 개발 시간을 단축하고 신뢰성을 개선하여 해당 구현을 간소화합니다.

**Topics**
+ [

## 폴링 및 배치 처리 스트림
](#dynamodb-polling-and-batching)
+ [

## 폴링 및 스트리밍 시작 위치
](#dyanmo-db-stream-poll)
+ [

## DynamoDB Streams 내 샤드의 동시 리더
](#events-dynamodb-simultaneous-readers)
+ [

## 예제 이벤트
](#events-sample-dynamodb)
+ [

# Lambda로 DynamoDB 레코드 처리
](services-dynamodb-eventsourcemapping.md)
+ [

# DynamoDB 및 Lambda로 부분 배치 응답 구성
](services-ddb-batchfailurereporting.md)
+ [

# Lambda에서 DynamoDB 이벤트 소스에 대한 폐기된 레코드 유지
](services-dynamodb-errors.md)
+ [

# Lambda에서 상태 저장 DynamoDB 스트림 처리 구현
](services-ddb-windows.md)
+ [

# Amazon DynamoDB 이벤트 소스 매핑을 위한 Lambda 파라미터
](services-ddb-params.md)
+ [

# DynamoDB 이벤트 소스를 통해 이벤트 필터링 사용
](with-ddb-filtering.md)
+ [

# 자습서: Amazon DynamoDB Streams와 함께 AWS Lambda 사용
](with-ddb-example.md)

## 폴링 및 배치 처리 스트림
<a name="dynamodb-polling-and-batching"></a>

Lambda는 초당 4회의 기본 속도로 레코드에 대해 DynamoDB 스트림의 샤드를 폴링합니다. 레코드를 사용할 수 있으면 Lambda가 함수를 간접 호출하고 결과를 기다립니다. 처리가 성공하면 Lambda가 레코드를 더 받을 때까지 폴링을 재개합니다.

기본적으로, Lambda는 레코드가 사용 가능하게 되는 즉시 함수를 간접 호출합니다. Lambda가 이벤트 소스에서 읽는 배치에 하나의 레코드만 있는 경우, Lambda는 함수에 하나의 레코드만 전송합니다. 소수의 레코드로 함수를 호출하는 것을 피하려면 *일괄 처리 기간*을 구성하여 이벤트 소스가 최대 5분 동안 레코드를 버퍼링하도록 지정할 수 있습니다. 함수를 호출하기 전에 Lambda는 전체 배치가 수집되거나, 일괄 처리 기간이 만료되거나, 배치가 페이로드 한도인 6MB에 도달할 때까지 이벤트 소스에서 레코드를 계속 읽습니다. 자세한 내용은 [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching) 섹션을 참조하세요.

**주의**  
Lambda 이벤트 소스 매핑은 각 이벤트를 한 번 이상 처리하므로 레코드가 중복될 수 있습니다. 중복 이벤트와 관련된 잠재적 문제를 방지하려면 함수 코드를 멱등성으로 만드는 것이 좋습니다. 자세한 내용은 AWS 지식 센터의 [함수를 멱등성 Lambda 함수로 만들려면 어떻게 해야 하나요?](https://repost.aws/knowledge-center/lambda-function-idempotent)를 참조하세요.

Lambda는 처리를 위해 다음 배치를 전송하기 전에 구성된 [확장](lambda-extensions.md)이 완료될 때까지 기다리지 않습니다. 즉, Lambda가 다음 레코드 배치를 처리할 때 확장이 계속 실행될 수 있습니다. 이로 인해 계정의 [동시성](lambda-concurrency.md) 설정 또는 스로틀링을 위반하는 경우 제한 문제가 발생할 수 있습니다. 이것이 잠재적인 문제인지 여부를 탐지하려면 함수를 모니터링하고 이벤트 소스 매핑에 대해 예상보다 높은 [동시성 지표](monitoring-concurrency.md#general-concurrency-metrics)가 표시되는지 확인하세요. 간접 호출 간격이 짧기 때문에 Lambda는 일시적으로 동시성 사용량을 샤드 수보다 더 높게 보고할 수 있습니다. 확장이 없는 Lambda 함수에서도 마찬가지입니다.

DynamoDB 데이터 스트림의 한 샤드와 하나 이상의 Lambda 간접 호출을 동시에 처리하도록 [ParallelizationFactor](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-ParallelizationFactor) 설정을 구성합니다. Lambda가 병렬화 계수를 통해 샤드에서 폴링하는 동시 배치의 수는 1(기본값)부터 10까지 지정할 수 있습니다. 예를 들어 `ParallelizationFactor`를 2로 설정하는 경우, 최대 100개의 DynamoDB 스트림 샤드를 처리하기 위한 200번의 동시 Lambda 간접 호출을 보유할 수 있습니다(실제 `ConcurrentExecutions` 지표의 값은 다를 수 있음). 이는 데이터 볼륨이 일시적이고 [IteratorAge](monitoring-metrics-types.md#performance-metrics)가 높은 경우 처리량을 스케일 업하는 데 도움을 줍니다. 샤드당 동시 배치 수를 늘려도 Lambda는 항목(파티션 및 정렬 키) 수준에서 순차적인 처리를 계속 보장합니다.

## 폴링 및 스트리밍 시작 위치
<a name="dyanmo-db-stream-poll"></a>

이벤트 소스 매핑 생성 및 업데이트 중 스트림 폴링은 최종적으로 일관됩니다.
+ 이벤트 소스 매핑 생성 중 스트림에서 이벤트 폴링을 시작하는 데 몇 분 정도 걸릴 수 있습니다.
+ 이벤트 소스 매핑 업데이트 중 스트림에서 이벤트 폴링을 중지했다가 다시 시작하는 데 몇 분 정도 걸릴 수 있습니다.

이 동작은 스트림의 시작 위치로 `LATEST`를 지정하면 이벤트 소스 매핑이 생성 또는 업데이트 중에 이벤트를 놓칠 수 있음을 의미합니다. 누락된 이벤트가 없도록 스트림 시작 위치를 `TRIM_HORIZON`으로 지정하세요.

## DynamoDB Streams 내 샤드의 동시 리더
<a name="events-dynamodb-simultaneous-readers"></a>

글로벌 테이블이 아닌 단일 리전 테이블의 경우 최대 2개의 Lambda 함수가 동시에 동일 DynamoDB Streams 샤드에서 읽기 작업을 수행하도록 설계할 수 있습니다. 이 제한을 초과하면 요청 병목이 발생할 수 있습니다. 글로벌 테이블의 경우 요청 제한을 피하기 위해 동시 함수 수를 1로 제한하는 것이 좋습니다.

## 예제 이벤트
<a name="events-sample-dynamodb"></a>

**Example**  

```
{
  "Records": [
    {
      "eventID": "1",
      "eventVersion": "1.0",
      "dynamodb": {
        "Keys": {
          "Id": {
            "N": "101"
          }
        },
        "NewImage": {
          "Message": {
            "S": "New item!"
          },
          "Id": {
            "N": "101"
          }
        },
        "StreamViewType": "NEW_AND_OLD_IMAGES",
        "SequenceNumber": "111",
        "SizeBytes": 26
      },
      "awsRegion": "us-west-2",
      "eventName": "INSERT",
      "eventSourceARN": "arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525",
      "eventSource": "aws:dynamodb"
    },
    {
      "eventID": "2",
      "eventVersion": "1.0",
      "dynamodb": {
        "OldImage": {
          "Message": {
            "S": "New item!"
          },
          "Id": {
            "N": "101"
          }
        },
        "SequenceNumber": "222",
        "Keys": {
          "Id": {
            "N": "101"
          }
        },
        "SizeBytes": 59,
        "NewImage": {
          "Message": {
            "S": "This item has changed"
          },
          "Id": {
            "N": "101"
          }
        },
        "StreamViewType": "NEW_AND_OLD_IMAGES"
      },
      "awsRegion": "us-west-2",
      "eventName": "MODIFY",
      "eventSourceARN": "arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525",
      "eventSource": "aws:dynamodb"
    }
  ]}
```

# Lambda로 DynamoDB 레코드 처리
<a name="services-dynamodb-eventsourcemapping"></a>

이벤트 소스 매핑을 생성하여 Lambda가 스트림의 레코드를 Lambda 함수로 전송하도록 지시합니다. 여러 이벤트 소스 매핑을 생성하여 여러 Lambda 함수로 동일한 데이터를 처리하거나, 단일 함수로 여러 스트림의 항목을 처리할 수 있습니다.

다른 AWS 계정에서 스트림의 레코드를 처리하도록 이벤트 소스 매핑을 구성할 수 있습니다. 자세한 내용은 [계정 간 이벤트 소스 매핑 생성](#services-dynamodb-eventsourcemapping-cross-account)를 참조하세요.

DynamoDB 스트림에서 읽도록 함수를 구성하려면 [AWSLambdaDynamoDBExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaDynamoDBExecutionRole.html) AWS 관리형 정책을 실행 역할에 연결한 다음 **DynamoDB** 트리거를 생성합니다.

**권한 추가 및 트리거 생성**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

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

1. **구성(Configuration)** 탭을 선택한 다음, **권한(Permissions)**을 선택합니다.

1. **역할 이름**에서 실행 역할에 대한 링크를 선택합니다. 이 링크를 클릭하면 IAM 콘솔에서 역할이 열립니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/execution-role.png)

1. **권한 추가**를 선택하고 **정책 연결**을 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/attach-policies.png)

1. 검색 필드에 `AWSLambdaDynamoDBExecutionRole`를 입력합니다. 실행 역할에 이 정책을 추가합니다. 함수가 DynamoDB 스트림에서 읽는 데 필요한 권한을 포함하는 AWS관리형 정책입니다. 이 정책에 대한 자세한 내용은 *AWS 관리형 정책 참조*의 [AWSLambdaDynamoDBExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaDynamoDBExecutionRole.html)을 참조하세요.

1. Lambda 콘솔에서 함수로 돌아갑니다. **함수 개요(Function overview)**에서 **트리거 추가(Add trigger)**를 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/add-trigger.png)

1. 트리거 유형을 선택합니다.

1. 필요한 옵션을 구성한 다음 **추가**를 선택합니다.

Lambda는 DynamoDB 이벤트 소스에 대해 다음 옵션을 지원합니다.

**이벤트 소스 옵션**
+ **DynamoDB 테이블** – 레코드를 읽을 DynamoDB 테이블입니다.
+ **배치 크기(Batch size)** - 각 배치에서 함수에 보낼 레코드 수입니다(최대 10,000개). Lambda는 한 번의 호출로 배치의 모든 레코드를 함수에 전달합니다. 단, 이벤트의 총 크기가 동기식 호출에 대한 [페이로드 한도](gettingstarted-limits.md)(6MB)를 초과하지 않아야 합니다.
+ **배치 기간(Batch window)** - 함수를 호출하기 전에 레코드를 수집할 최대 기간(단위: 초)를 지정합니다.
+ **시작 위치** – 새 레코드만, 또는 기존의 모든 레코드를 처리합니다.
  + **최신** – 스트림에 추가된 새 레코드를 처리합니다.
  + **수평 트리밍** – 스트림의 모든 레코드를 처리합니다.

  기존 레코드 처리 후 함수는 캐치업되고 새 레코드를 계속 처리합니다.
+ **On-failure destination**(실패 시 대상) – 처리할 수 없는 레코드에 대한 표준 SQS 대기열 또는 표준 SNS 주제입니다. 너무 오래되었거나 모든 재시도를 다 사용한 레코드 배치를 폐기할 때, Lambda는 해당 배치에 대한 세부 정보를 대기열 또는 주제로 보냅니다.
+ **Retry attempts(재시도)** - 함수가 오류를 반환할 때 Lambda에서 재시도하는 최대 횟수입니다. 이는 배치가 함수에 도달하지 않은 제한 또는 서비스 오류에 적용되지 않습니다.
+ **Maximum age of record(최대 레코드 사용 기간)** – Lambda에서 함수로 보내는 최대 레코드 사용 기간입니다.
+ **Split batch on error(오류 시 배치 분할)** – 함수에서 오류를 반환하면 재시도하기 전에 배치를 두 개로 분할합니다. 원래 배치 크기 설정은 변경되지 않습니다.
+ **Concurrent batches per shard(샤드당 동시 배치)** – 동일한 샤드의 여러 배치를 동시에 처리합니다.
+ **활성화** – 이벤트 소스 매핑을 활성화하려면 true로 설정합니다. 레코드 처리를 중지하려면 false로 설정합니다. Lambda는 마지막으로 처리된 레코드를 추적하여 매핑이 다시 활성화되면 해당 지점부터 처리를 다시 시작합니다.

**참고**  
DynamoDB 트리거의 일부로 Lambda에서 간접 호출한 GetRecords API 간접 호출에 대해서는 요금이 부과되지 않습니다.

나중에 이벤트 소스 구성을 관리하기 위해 디자이너에서 트리거를 선택합니다.

## 계정 간 이벤트 소스 매핑 생성
<a name="services-dynamodb-eventsourcemapping-cross-account"></a>

Amazon DynamoDB는 이제 [리소스 기반 정책](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/access-control-resource-based.html)을 지원합니다. 이 기능을 사용하면 한 AWS 계정에서 다른 계정의 Lambda 함수를 사용하여 DynamoDB 스트림의 데이터를 처리할 수 있습니다.

다른 AWS 계정에서 DynamoDB 스트림을 사용하여 Lambda 함수에 대한 이벤트 소스 매핑을 생성하려면 리소스 기반 정책을 사용하여 스트림을 구성해서 Lambda 함수에 레코드 읽기 권한을 부여합니다. 교차 계정 액세스를 허용하도록 스트림을 구성하는 방법을 자세히 알아보려면 *Amazon DynamoDB 개발자 안내서*의 [교차 계정 Lambda 함수를 통한 액세스 공유](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/rbac-cross-account-access.html#rbac-analyze-cross-account-lambda-access)를 참조하세요.

스트림에서 Lambda 함수에 필요한 권한을 부여하는 리소스 기반 정책을 구성한 후에는 교차 계정 스트림 ARN을 사용하여 이벤트 소스 매핑을 생성합니다. 교차 계정 DynamoDB 콘솔의 테이블 **내보내기 및 스트림** 탭에서 스트림 ARN을 찾을 수 있습니다.

Lambda 콘솔을 사용하는 경우 이벤트 소스 매핑 생성 페이지의 DynamoDB 테이블 입력 필드에 스트림 ARN을 직접 붙여넣습니다.

 **참고:** 교차 리전 트리거는 지원되지 않습니다.

# DynamoDB 및 Lambda로 부분 배치 응답 구성
<a name="services-ddb-batchfailurereporting"></a>

이벤트 소스에서 스트리밍 데이터를 사용하고 처리할 때 기본적으로 Lambda는 배치가 완전히 성공한 경우에만 배치의 가장 높은 시퀀스 번호로 체크포인트를 수행합니다. Lambda는 다른 모든 결과를 완전한 실패로 처리하고 재시도 제한까지 배치 처리를 재시도합니다. 스트림에서 배치를 처리하는 동안 부분적인 성공을 허용하려면 `ReportBatchItemFailures`를 설정합니다. 부분적인 성공을 허용하면 레코드에 대한 재시도 횟수를 줄이는 데 도움이 되지만 성공한 레코드의 재시도 가능성을 완전히 막지는 못합니다.

`ReportBatchItemFailures`를 켜려면 [FunctionResponseTypes](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-FunctionResponseTypes) 목록에 열거형 값 **ReportBatchItemFailures**를 포함시킵니다. 이 목록은 함수에 대해 활성화된 응답 유형을 나타냅니다. 이벤트 소스 매핑을 [생성](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html)하거나 [업데이트](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html)할 때 이 목록을 구성할 수 있습니다.

**참고**  
함수 코드가 부분 배치 실패 응답을 반환하더라도 이벤트 소스 매핑에 대해 `ReportBatchItemFailures` 기능이 명시적으로 활성화되지 않으면 Lambda가 해당 응답을 처리하지 않습니다.

## 보고서 구문
<a name="streams-batchfailurereporting-syntax"></a>

배치 항목 실패에 대한 보고를 구성할 때 `StreamsEventResponse` 클래스는 배치 항목 실패 목록과 함께 반환됩니다. `StreamsEventResponse` 객체를 사용하여 배치에서 첫 번째 실패한 레코드의 시퀀스 번호를 반환할 수 있습니다. 올바른 응답 구문을 사용하여 고유한 사용자 지정 클래스를 생성할 수도 있습니다. 다음 JSON 구조는 필요한 응답 구문을 보여줍니다.

```
{ 
  "batchItemFailures": [ 
        {
            "itemIdentifier": "<SequenceNumber>"
        }
    ]
}
```

**참고**  
`batchItemFailures` 어레이에 여러 항목이 포함되어 있으면 Lambda는 시퀀스 번호가 가장 낮은 레코드를 체크포인트로 사용합니다. 그런 다음 Lambda는 해당 체크포인트에서 시작하여 모든 레코드를 다시 시도합니다.

## 성공 및 실패 조건
<a name="streams-batchfailurereporting-conditions"></a>

Lambda는 다음 중 하나를 반환할 경우 배치를 완전한 성공으로 처리합니다.
+ 비어 있는 `batchItemFailure` 목록
+ null `batchItemFailure` 목록
+ 비어 있는 `EventResponse`
+ null `EventResponse`

Lambda는 다음 중 하나를 반환할 경우 배치를 완전한 실패로 처리합니다.
+ 빈 문자열 `itemIdentifier`
+ null `itemIdentifier`
+ 키 이름이 잘못된 `itemIdentifier`

Lambda는 재시도 전략에 따라 실패를 재시도합니다.

## 배치 이등분
<a name="streams-batchfailurereporting-bisect"></a>

호출이 실패하고 `BisectBatchOnFunctionError`가 활성화되어 있으면 `ReportBatchItemFailures` 설정에 관계 없이 배치가 이등분됩니다.

부분적 배치 성공 응답이 수신되고 `BisectBatchOnFunctionError` 및 `ReportBatchItemFailures`가 모두 활성화되면 배치가 반환된 시퀀스 번호에서 이등분되고 Lambda는 나머지 레코드만 재시도합니다.

부분 배치 응답 로직 구현을 간소화하려면 이러한 복잡성을 자동 처리할 수 있는 Powertools for AWS Lambda의 [배치 프로세서 유틸리티](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)를 사용하는 것이 좋습니다.

다음은 일괄적으로 실패한 메시지 ID 목록을 반환하는 함수 코드의 몇 가지 예입니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 DynamoDB 배치 항목 실패 보고.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
using System.Text.Json;
using System.Text;
using Amazon.Lambda.Core;
using Amazon.Lambda.DynamoDBEvents;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace AWSLambda_DDB;

public class Function
{
    public StreamsEventResponse FunctionHandler(DynamoDBEvent dynamoEvent, ILambdaContext context)

    {
        context.Logger.LogInformation($"Beginning to process {dynamoEvent.Records.Count} records...");
        List<StreamsEventResponse.BatchItemFailure> batchItemFailures = new List<StreamsEventResponse.BatchItemFailure>();
        StreamsEventResponse streamsEventResponse = new StreamsEventResponse();

        foreach (var record in dynamoEvent.Records)
        {
            try
            {
                var sequenceNumber = record.Dynamodb.SequenceNumber;
                context.Logger.LogInformation(sequenceNumber);
            }
            catch (Exception ex)
            {
                context.Logger.LogError(ex.Message);
                batchItemFailures.Add(new StreamsEventResponse.BatchItemFailure() { ItemIdentifier = record.Dynamodb.SequenceNumber });
            }
        }

        if (batchItemFailures.Count > 0)
        {
            streamsEventResponse.BatchItemFailures = batchItemFailures;
        }

        context.Logger.LogInformation("Stream processing complete.");
        return streamsEventResponse;
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 DynamoDB 배치 항목 실패 보고.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

type BatchItemFailure struct {
	ItemIdentifier string `json:"ItemIdentifier"`
}

type BatchResult struct {
	BatchItemFailures []BatchItemFailure `json:"BatchItemFailures"`
}

func HandleRequest(ctx context.Context, event events.DynamoDBEvent) (*BatchResult, error) {
	var batchItemFailures []BatchItemFailure
	curRecordSequenceNumber := ""

	for _, record := range event.Records {
		// Process your record
		curRecordSequenceNumber = record.Change.SequenceNumber
	}

	if curRecordSequenceNumber != "" {
		batchItemFailures = append(batchItemFailures, BatchItemFailure{ItemIdentifier: curRecordSequenceNumber})
	}
	
	batchResult := BatchResult{
		BatchItemFailures: batchItemFailures,
	}

	return &batchResult, nil
}

func main() {
	lambda.Start(HandleRequest)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda로 DynamoDB 배치 항목 실패 보고.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent;
import com.amazonaws.services.lambda.runtime.events.StreamsEventResponse;
import com.amazonaws.services.lambda.runtime.events.models.dynamodb.StreamRecord;

import java.util.ArrayList;
import java.util.List;

public class ProcessDynamodbRecords implements RequestHandler<DynamodbEvent, StreamsEventResponse> {

    @Override
    public StreamsEventResponse handleRequest(DynamodbEvent input, Context context) {

        List<StreamsEventResponse.BatchItemFailure> batchItemFailures = new ArrayList<>();
        String curRecordSequenceNumber = "";

        for (DynamodbEvent.DynamodbStreamRecord dynamodbStreamRecord : input.getRecords()) {
          try {
                //Process your record
                StreamRecord dynamodbRecord = dynamodbStreamRecord.getDynamodb();
                curRecordSequenceNumber = dynamodbRecord.getSequenceNumber();
                
            } catch (Exception e) {
                /* Since we are working with streams, we can return the failed item immediately.
                   Lambda will immediately begin to retry processing from this failed item onwards. */
                batchItemFailures.add(new StreamsEventResponse.BatchItemFailure(curRecordSequenceNumber));
                return new StreamsEventResponse(batchItemFailures);
            }
        }
       
       return new StreamsEventResponse();   
    }
}
```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda로 DynamoDB 배치 항목 실패 보고.  

```
export const handler = async (event) => {
  const records = event.Records;
  let curRecordSequenceNumber = "";

  for (const record of records) {
    try {
      // Process your record
      curRecordSequenceNumber = record.dynamodb.SequenceNumber;
    } catch (e) {
      // Return failed record's sequence number
      return { batchItemFailures: [{ itemIdentifier: curRecordSequenceNumber }] };
    }
  }

  return { batchItemFailures: [] };
};
```
TypeScript를 사용하여 Lambda로 DynamoDB 배치 항목 실패 보고.  

```
import {
  DynamoDBBatchResponse,
  DynamoDBBatchItemFailure,
  DynamoDBStreamEvent,
} from "aws-lambda";

export const handler = async (
  event: DynamoDBStreamEvent
): Promise<DynamoDBBatchResponse> => {
  const batchItemFailures: DynamoDBBatchItemFailure[] = [];
  let curRecordSequenceNumber;

  for (const record of event.Records) {
    curRecordSequenceNumber = record.dynamodb?.SequenceNumber;

    if (curRecordSequenceNumber) {
      batchItemFailures.push({
        itemIdentifier: curRecordSequenceNumber,
      });
    }
  }

  return { batchItemFailures: batchItemFailures };
};
```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 DynamoDB 배치 항목 실패 보고.  

```
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\DynamoDb\DynamoDbEvent;
use Bref\Event\Handler as StdHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler implements StdHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handle(mixed $event, Context $context): array
    {
        $dynamoDbEvent = new DynamoDbEvent($event);
        $this->logger->info("Processing records");

        $records = $dynamoDbEvent->getRecords();
        $failedRecords = [];
        foreach ($records as $record) {
            try {
                $data = $record->getData();
                $this->logger->info(json_encode($data));
                // TODO: Do interesting work based on the new data
            } catch (Exception $e) {
                $this->logger->error($e->getMessage());
                // failed processing the record
                $failedRecords[] = $record->getSequenceNumber();
            }
        }
        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords records");

        // change format for the response
        $failures = array_map(
            fn(string $sequenceNumber) => ['itemIdentifier' => $sequenceNumber],
            $failedRecords
        );

        return [
            'batchItemFailures' => $failures
        ];
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 DynamoDB 배치 항목 실패 보고.  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def handler(event, context):
    records = event.get("Records")
    curRecordSequenceNumber = ""
    
    for record in records:
        try:
            # Process your record
            curRecordSequenceNumber = record["dynamodb"]["SequenceNumber"]
        except Exception as e:
            # Return failed record's sequence number
            return {"batchItemFailures":[{"itemIdentifier": curRecordSequenceNumber}]}

    return {"batchItemFailures":[]}
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 DynamoDB 배치 항목 실패 보고.  

```
def lambda_handler(event:, context:)
    records = event["Records"]
    cur_record_sequence_number = ""
  
    records.each do |record|
      begin
        # Process your record
        cur_record_sequence_number = record["dynamodb"]["SequenceNumber"]
      rescue StandardError => e
        # Return failed record's sequence number
        return {"batchItemFailures" => [{"itemIdentifier" => cur_record_sequence_number}]}
      end
    end
  
    {"batchItemFailures" => []}
  end
```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 DynamoDB 배치 항목 실패 보고.  

```
use aws_lambda_events::{
    event::dynamodb::{Event, EventRecord, StreamRecord},
    streams::{DynamoDbBatchItemFailure, DynamoDbEventResponse},
};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};

/// Process the stream record
fn process_record(record: &EventRecord) -> Result<(), Error> {
    let stream_record: &StreamRecord = &record.change;

    // process your stream record here...
    tracing::info!("Data: {:?}", stream_record);

    Ok(())
}

/// Main Lambda handler here...
async fn function_handler(event: LambdaEvent<Event>) -> Result<DynamoDbEventResponse, Error> {
    let mut response = DynamoDbEventResponse {
        batch_item_failures: vec![],
    };

    let records = &event.payload.records;

    if records.is_empty() {
        tracing::info!("No records found. Exiting.");
        return Ok(response);
    }

    for record in records {
        tracing::info!("EventId: {}", record.event_id);

        // Couldn't find a sequence number
        if record.change.sequence_number.is_none() {
            response.batch_item_failures.push(DynamoDbBatchItemFailure {
                item_identifier: Some("".to_string()),
            });
            return Ok(response);
        }

        // Process your record here...
        if process_record(record).is_err() {
            response.batch_item_failures.push(DynamoDbBatchItemFailure {
                item_identifier: record.change.sequence_number.clone(),
            });
            /* Since we are working with streams, we can return the failed item immediately.
            Lambda will immediately begin to retry processing from this failed item onwards. */
            return Ok(response);
        }
    }

    tracing::info!("Successfully processed {} record(s)", records.len());

    Ok(response)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        // disable printing the name of the module in every log line.
        .with_target(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

## Powertools for AWS Lambda 배치 프로세서 사용
<a name="services-ddb-batchfailurereporting-powertools"></a>

Powertools for AWS Lambda의 배치 프로세서 유틸리티는 부분 배치 응답 로직을 자동으로 처리하여 배치 실패 보고 구현에 따르는 복잡성을 줄입니다. 다음은 배치 프로세서를 사용하는 예제입니다.

**Python**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서를](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/) 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 DynamoDB 스트림 레코드를 처리합니다.  

```
import json
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.batch import BatchProcessor, EventType, process_partial_response
from aws_lambda_powertools.utilities.data_classes import DynamoDBStreamEvent
from aws_lambda_powertools.utilities.typing import LambdaContext

processor = BatchProcessor(event_type=EventType.DynamoDBStreams)
logger = Logger()

def record_handler(record):
    logger.info(record)
    # Your business logic here
    # Raise an exception to mark this record as failed
    
def lambda_handler(event, context: LambdaContext):
    return process_partial_response(
        event=event, 
        record_handler=record_handler, 
        processor=processor,
        context=context
    )
```

**TypeScript**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서를](https://docs.aws.amazon.com/powertools/typescript/latest/features/batch/) 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 DynamoDB 스트림 레코드를 처리합니다.  

```
import { BatchProcessor, EventType, processPartialResponse } from '@aws-lambda-powertools/batch';
import { Logger } from '@aws-lambda-powertools/logger';
import type { DynamoDBStreamEvent, Context } from 'aws-lambda';

const processor = new BatchProcessor(EventType.DynamoDBStreams);
const logger = new Logger();

const recordHandler = async (record: any): Promise<void> => {
    logger.info('Processing record', { record });
    // Your business logic here
    // Throw an error to mark this record as failed
};

export const handler = async (event: DynamoDBStreamEvent, context: Context) => {
    return processPartialResponse(event, recordHandler, processor, {
        context,
    });
};
```

**Java**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서를](https://docs.powertools.aws.dev/lambda/java/latest/utilities/batch/) 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 DynamoDB 스트림 레코드를 처리합니다.  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent;
import com.amazonaws.services.lambda.runtime.events.StreamsEventResponse;
import software.amazon.lambda.powertools.batch.BatchMessageHandlerBuilder;
import software.amazon.lambda.powertools.batch.handler.BatchMessageHandler;

public class DynamoDBStreamBatchHandler implements RequestHandler<DynamodbEvent, StreamsEventResponse> {

    private final BatchMessageHandler<DynamodbEvent, StreamsEventResponse> handler;

    public DynamoDBStreamBatchHandler() {
        handler = new BatchMessageHandlerBuilder()
                .withDynamoDbBatchHandler()
                .buildWithRawMessageHandler(this::processMessage);
    }

    @Override
    public StreamsEventResponse handleRequest(DynamodbEvent ddbEvent, Context context) {
        return handler.processBatch(ddbEvent, context);
    }

    private void processMessage(DynamodbEvent.DynamodbStreamRecord dynamodbStreamRecord, Context context) {
        // Process the change record
    }
}
```

**.NET**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서를](https://docs.aws.amazon.com/powertools/dotnet/utilities/batch-processing/) 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 DynamoDB 스트림 레코드를 처리합니다.  

```
using System;
using System.Threading;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.Lambda.DynamoDBEvents;
using Amazon.Lambda.Serialization.SystemTextJson;
using AWS.Lambda.Powertools.BatchProcessing;

[assembly: LambdaSerializer(typeof(DefaultLambdaJsonSerializer))]

namespace HelloWorld;

public class Customer
{
    public string? CustomerId { get; set; }
    public string? Name { get; set; }
    public string? Email { get; set; }
    public DateTime CreatedAt { get; set; }
}

internal class TypedDynamoDbRecordHandler : ITypedRecordHandler<Customer> 
{
    public async Task<RecordHandlerResult> HandleAsync(Customer customer, CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(customer.Email)) 
        {
            throw new ArgumentException("Customer email is required");
        }

        return await Task.FromResult(RecordHandlerResult.None); 
    }
}

public class Function
{
    [BatchProcessor(TypedRecordHandler = typeof(TypedDynamoDbRecordHandler))]
    public BatchItemFailuresResponse HandlerUsingTypedAttribute(DynamoDBEvent _)
    {
        return TypedDynamoDbStreamBatchProcessor.Result.BatchItemFailuresResponse; 
    }
}
```

# Lambda에서 DynamoDB 이벤트 소스에 대한 폐기된 레코드 유지
<a name="services-dynamodb-errors"></a>

DynamoDB 이벤트 소스 매핑에 대한 오류 처리는 오류가 함수 간접 호출 전에 발생하는지 아니면 함수 간접 호출 중에 발생하는지 여부에 따라 달라집니다.
+ **간접 호출 전:** Lambda 이벤트 소스 매핑이 스로틀링 또는 기타 문제로 인해 함수를 간접적으로 간접 호출할 수 없는 경우 레코드가 만료되거나 이벤트 소스 매핑에 구성된 최대 기간([MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds))을 초과할 때까지 재시도합니다.
+ **간접 호출 중:** 함수가 간접적으로 간접 호출되었지만 오류가 반환되는 경우 Lambda는 레코드가 만료되거나 최대 기간([MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds))을 초과하거나 구성된 재시도 할당량([MaximumRetryAttempts](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRetryAttempts))에 도달할 때까지 재시도합니다. 함수 오류의 경우 실패한 배치를 두 개의 작은 배치로 분할하여 잘못된 레코드를 격리하고 시간 초과를 방지하는 [BisectBatchOnFunctionError](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-response-BisectBatchOnFunctionError)를 구성할 수도 있습니다. 배치를 분할할 때는 재시도 할당량이 소모되지 않습니다.

오류 처리에서 실패를 측정하는 경우 Lambda는 레코드를 폐기하고 스트림에서 배치 처리를 계속합니다. 기본 설정을 사용하는 경우 이는 잘못된 레코드가 영향을 받은 샤드에 대한 처리를 최대 1일 동안 차단할 수 있음을 의미합니다. 이를 방지하려면 함수의 이벤트 소스 매핑을 사용자의 사례에 적합한 최대 레코드 사용 기간 및 합당한 재시도 횟수로 구성합니다.

## 실패한 간접 호출에 대한 대상 구성
<a name="dynamodb-on-failure-destination-console"></a>

실패한 이벤트 소스 매핑 간접 호출 기록을 보관하려면 함수의 이벤트 소스 매핑에 대상을 추가합니다. 대상으로 전송된 각 레코드는 실패한 간접 호출에 대한 메타데이터를 포함하는 JSON 문서입니다. Amazon S3 대상의 경우 Lambda는 메타데이터와 함께 전체 간접 호출 레코드를 전송합니다. 모든 Amazon SNS 주제, Amazon SQS 대기열, Amazon S3 버킷 또는 Kafka를 대상으로 구성할 수 있습니다.

Amazon S3 대상을 사용하면 [Amazon S3 이벤트 알림](https://docs.aws.amazon.com/) 기능을 통해 객체를 대상 S3 버킷에 업로드할 때 알림을 받을 수 있습니다. 실패한 배치에서 자동 처리를 수행하기 위해 다른 Lambda 함수를 간접 호출하도록 S3 이벤트 알림을 구성할 수도 있습니다.

실행 역할에 대상에 대한 권한이 있어야 합니다.
+ **SQS 대상:** [sqs:SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)
+ **SNS 대상:** [sns:Publish](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html)
+ **S3 대상:** [s3:PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 및 [s3:ListBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/ListObjectsV2.html)
+ **Kafka 대상:** [kafka-cluster:WriteData](https://docs.aws.amazon.com/msk/latest/developerguide/kafka-actions.html)

Kafka 주제를 Kafka 이벤트 소스 매핑의 실패 시 대상으로 구성할 수 있습니다. Lambda가 재시도 횟수를 소진한 후 레코드를 처리할 수 없거나 레코드가 최대 수명을 초과하는 경우 Lambda는 나중에 처리할 수 있도록 실패한 레코드를 지정된 Kafka 주제로 보냅니다. 자세한 내용은 [Kafka 주제를 실패 시 대상으로 사용](kafka-on-failure-destination.md) 항목을 참조하세요.

S3 대상에 대해 자체 KMS 키를 사용하여 암호화를 활성화한 경우 함수의 실행 역할에 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)를 직접 호출할 수 있는 권한도 있어야 합니다. KMS 키와 S3 버킷 대상이 Lambda 함수 및 실행 역할과 다른 계정에 있는 경우 실행 역할을 신뢰하도록 KMS 키를 구성하여 kms:GenerateDataKey를 허용합니다.

이 콘솔을 사용하여 장애 시 대상을 구성하려면 다음 단계를 따르세요.

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 함수를 선택합니다.

1. **함수 개요(Function overview)**에서 **대상 추가(Add destination)**를 선택합니다.

1. **소스**의 경우 **이벤트 소스 매핑 간접 호출**을 선택합니다.

1. **이벤트 소스 매핑**의 경우 이 함수에 대해 구성된 이벤트 소스를 선택합니다.

1. **조건**의 경우 **실패 시**를 선택합니다. 이벤트 소스 매핑 간접 호출의 경우 이 조건만 수락됩니다.

1. **대상 유형**의 경우 Lambda가 간접 호출 레코드를 전송할 대상 유형을 선택합니다.

1. **Destination(대상)**에서 리소스를 선택합니다.

1. **저장**을 선택합니다.

AWS Command Line Interface(AWS CLI)를 사용하여 장애 시 대상을 구성할 수도 있습니다. 예를 들어, 다음 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 명령은 SQS 장애 시 대상이 있는 이벤트 소스 매핑을 `MyFunction`에 추가합니다.

```
aws lambda create-event-source-mapping \
--function-name "MyFunction" \
--event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525 \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sqs:us-east-1:123456789012:dest-queue"}}'
```

다음 [update-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 명령은 두 번의 재시도 시도 후 또는 레코드가 1시간 이상 지난 경우 SNS 대상으로 실패한 간접 호출 레코드를 전송하도록 이벤트 소스 매핑을 업데이트합니다.

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--maximum-retry-attempts 2 \
--maximum-record-age-in-seconds 3600 \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sns:us-east-1:123456789012:dest-topic"}}'
```

업데이트된 설정은 비동기식으로 적용되며 프로세스가 완료된 후에야 출력에 반영됩니다. [get-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html) 명령을 사용하여 현재 상태를 봅니다.

대상을 제거하려면 `destination-config` 파라미터의 인수로 빈 문자열을 제공합니다.

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--destination-config '{"OnFailure": {"Destination": ""}}'
```

### Amazon S3에 대한 보안 모범 사례
<a name="ddb-s3-destination-security"></a>

함수 구성에서 대상을 제거하지 않고 대상으로 구성된 S3 버킷을 삭제하면 보안 위험이 초래될 수 있습니다. 사용자의 대상 버킷 이름을 다른 사용자가 알고 있는 경우 AWS 계정에서 버킷을 다시 생성할 수 있습니다. 실패한 간접 호출에 대한 레코드가 해당 버킷으로 전송되어 함수의 데이터가 공개될 수 있습니다.

**주의**  
함수의 간접 호출 레코드를 다른 AWS 계정의 S3 버킷으로 전송할 수 없도록 하려면 계정의 버킷에 대한 `s3:PutObject` 권한을 제한하는 조건을 함수의 실행 역할에 추가합니다.

다음 예제에서는 함수의 `s3:PutObject` 권한을 계정의 버킷으로 제한하는 IAM 정책을 보여줍니다. 또한 이 정책에서는 Lambda가 S3 버킷을 대상으로 사용하는 데 필요한 `s3:ListBucket` 권한도 부여합니다.

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "S3BucketResourceAccountWrite",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::*/*",
                "arn:aws:s3:::*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:ResourceAccount": "111122223333"
                }
            }
        }
    ]
}
```

AWS Management Console 또는 AWS CLI를 사용하여 함수의 실행 역할에 권한 정책을 추가하려면 다음 절차의 지침을 참조하세요.

------
#### [ Console ]

**함수의 실행 역할에 권한 정책을 추가하는 방법(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 실행 역할을 수정하려는 Lambda 함수를 선택하세요.

1. **구성** 탭을 선택한 다음 **사용 권한**을 선택합니다.

1. **실행 역할** 탭에서 함수의 **역할 이름**을 선택하여 역할의 IAM 콘솔 페이지를 여세요.

1. 다음을 수행하여 역할에 기본 권한 정책을 추가하세요.

   1. **권한** 창에서 **권한 추가**를 선택하고 **인라인 정책 생성**을 선택하세요.

   1. **정책 편집기**에서 **JSON**을 선택하세요.

   1. 추가하려는 정책을 편집기에 붙여넣고(이때 기존 JSON 대체) **다음**을 선택하세요.

   1. **정책 세부 정보** 아래에 **정책 이름**을 입력하세요.

   1. **정책 생성**을 선택합니다.

------
#### [ AWS CLI ]

**함수의 실행 역할에 권한 정책을 추가하는 방법(CLI)**

1. 필요한 권한이 있는 JSON 정책 문서를 생성하고 로컬 디렉터리에 저장하세요.

1. IAM `put-role-policy` CLI 명령을 사용하여 함수의 실행 역할에 권한을 추가하세요. JSON 정책 문서를 저장한 디렉터리에서 다음 명령을 실행하고 역할 이름, 정책 이름 및 정책 문서를 고유한 값으로 바꾸세요.

   ```
   aws iam put-role-policy \
   --role-name my_lambda_role \
   --policy-name LambdaS3DestinationPolicy \
   --policy-document file://my_policy.json
   ```

------

### Amazon SNS 및 Amazon SQS 간접 호출 레코드 예제
<a name="kinesis-on-failure-destination-example-sns-sqs"></a>

다음 예제에서는 DynamoDB 스트림에 대해 Lambda가 SQS 또는 SNS 대상으로 전송하는 간접 호출 레코드를 보여줍니다.

```
{
    "requestContext": {
        "requestId": "316aa6d0-8154-xmpl-9af7-85d5f4a6bc81",
        "functionArn": "arn:aws:lambda:us-east-2:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted",
        "approximateInvokeCount": 1
    },
    "responseContext": {
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:13:49.717Z",
    "DDBStreamBatchInfo": {
        "shardId": "shardId-00000001573689847184-864758bb",
        "startSequenceNumber": "800000000003126276362",
        "endSequenceNumber": "800000000003126276362",
        "approximateArrivalOfFirstRecord": "2019-11-14T00:13:19Z",
        "approximateArrivalOfLastRecord": "2019-11-14T00:13:19Z",
        "batchSize": 1,
        "streamArn": "arn:aws:dynamodb:us-east-2:123456789012:table/mytable/stream/2019-11-14T00:04:06.388"
    }
}
```

이 정보를 사용하여 문제 해결을 위해 스트림에서 영향을 받은 레코드를 검색할 수 있습니다. 실제 레코드는 포함되지 않으므로 이 레코드를 처리하고 실제 레코드가 만료되고 없어지기 전에 스트림에서 해당 레코드를 검색해야 합니다.

### Amazon S3 간접 호출 레코드 예제
<a name="kinesis-on-failure-destination-example-sns-sqs-s3"></a>

다음 예제에서는 DynamoDB 스트림에 대해 Lambda가 S3 버킷으로 전송하는 간접 호출 레코드를 보여줍니다. SQS 및 SNS 대상에 대한 이전 예제의 모든 필드 외에도 `payload` 필드에는 원래 간접 호출 레코드가 이스케이프된 JSON 문자열로 포함되어 있습니다.

```
{
    "requestContext": {
        "requestId": "316aa6d0-8154-xmpl-9af7-85d5f4a6bc81",
        "functionArn": "arn:aws:lambda:us-east-2:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted",
        "approximateInvokeCount": 1
    },
    "responseContext": {
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:13:49.717Z",
    "DDBStreamBatchInfo": {
        "shardId": "shardId-00000001573689847184-864758bb",
        "startSequenceNumber": "800000000003126276362",
        "endSequenceNumber": "800000000003126276362",
        "approximateArrivalOfFirstRecord": "2019-11-14T00:13:19Z",
        "approximateArrivalOfLastRecord": "2019-11-14T00:13:19Z",
        "batchSize": 1,
        "streamArn": "arn:aws:dynamodb:us-east-2:123456789012:table/mytable/stream/2019-11-14T00:04:06.388"
    },
    "payload": "<Whole Event>" // Only available in S3
}
```

간접 호출 레코드를 포함하는 S3 객체는 다음 이름 지정 규칙을 사용합니다.

```
aws/lambda/<ESM-UUID>/<shardID>/YYYY/MM/DD/YYYY-MM-DDTHH.MM.SS-<Random UUID>
```

# Lambda에서 상태 저장 DynamoDB 스트림 처리 구현
<a name="services-ddb-windows"></a>

Lambda 함수는 연속 스트림 처리 애플리케이션을 실행할 수 있습니다. 스트림은 애플리케이션을 통해 연속적으로 흐르는 무한 데이터를 나타냅니다. 이 지속적으로 업데이트되는 입력의 정보를 분석하기 위해 시간의 항으로 정의된 윈도우를 사용하여 포함된 레코드를 바인딩할 수 있습니다.

텀블링 기간은 일정한 간격으로 시작되고 끝나는 고유한 시간대입니다. 기본적으로 Lambda 호출은 상태 비저장입니다. 즉, 외부 데이터베이스 없이는 여러 연속 호출에서 데이터를 처리하는 데 사용할 수 없습니다. 그러나 텀블링 기간을 활성화하면 호출 간에 상태를 유지할 수 있습니다. 이 상태에는 현재 윈도우에 대해 이전에 처리된 메시지의 집계 결과가 포함됩니다. 상태는 샤드당 최대 1MB가 될 수 있습니다. 이 크기를 초과하면 Lambda가 윈도우를 조기 종료합니다.

스트림의 각 레코드는 특정 윈도우에 속합니다. Lambda는 각 레코드를 한 번 이상 처리하지만 각 레코드가 한 번만 처리된다고 보장하지는 않습니다. 드물게 오류 처리와 같이 일부 레코드가 두 번 이상 처리될 수 있습니다. 레코드는 항상 처음부터 순서대로 처리됩니다. 레코드가 두 번 이상 처리되는 경우 레코드가 비순차적으로 처리될 수 있습니다.

## 집계 및 처리
<a name="streams-tumbling-processing"></a>

집계 및 해당 집계의 최종 결과 처리를 위해 사용자 관리형 함수가 간접 호출됩니다. Lambda는 윈도우 내에서 수신한 모든 레코드를 집계합니다. 이러한 레코드를 각각 별도의 호출인 여러 배치에서 받을 수 있습니다. 각 호출은 상태를 수신합니다. 따라서 텀블링 기간을 사용할 때 Lambda 함수 응답에는 `state` 속성을 포함해야 합니다. 응답에 `state` 속성이 포함되지 않은 경우 Lambda는 이 호출이 실패한 것으로 간주합니다. 이 조건을 충족하기 위해 함수는 다음 JSON 모양의 `TimeWindowEventResponse` 객체를 반환할 수 있습니다.

**Example `TimeWindowEventResponse` 값**  

```
{
    "state": {
        "1": 282,
        "2": 715
    },
    "batchItemFailures": []
}
```

**참고**  
Java 함수의 경우 `Map<String, String>`을 사용하여 상태를 나타내는 것이 좋습니다.

윈도우 끝에서 `isFinalInvokeForWindow` 플래그는 이것이 최종 상태이며 처리 준비가 되었음을 나타내기 위해 `true`로 설정됩니다. 처리 후 윈도우가 완료되고 최종 호출이 완료된 다음 상태가 삭제됩니다.

윈도우 끝에서 Lambda가 집계 결과에 대한 작업을 위해 최종 처리를 사용합니다. 최종 처리는 동기식으로 간접 호출됩니다. 성공적인 호출 후 함수가 시퀀스 번호를 검사하고 스트림 처리가 계속됩니다. 호출이 실패하면 Lambda 함수는 호출이 성공할 때까지 추가 처리를 일시 중단합니다.

**Example DynamodbTimeWindowEvent**  

```
{
   "Records":[
      {
         "eventID":"1",
         "eventName":"INSERT",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "NewImage":{
               "Message":{
                  "S":"New item!"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"111",
            "SizeBytes":26,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      },
      {
         "eventID":"2",
         "eventName":"MODIFY",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "NewImage":{
               "Message":{
                  "S":"This item has changed"
               },
               "Id":{
                  "N":"101"
               }
            },
            "OldImage":{
               "Message":{
                  "S":"New item!"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"222",
            "SizeBytes":59,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      },
      {
         "eventID":"3",
         "eventName":"REMOVE",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "OldImage":{
               "Message":{
                  "S":"This item has changed"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"333",
            "SizeBytes":38,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      }
   ],
    "window": {
        "start": "2020-07-30T17:00:00Z",
        "end": "2020-07-30T17:05:00Z"
    },
    "state": {
        "1": "state1"
    },
    "shardId": "shard123456789",
    "eventSourceARN": "stream-ARN",
    "isFinalInvokeForWindow": false,
    "isWindowTerminatedEarly": false
}
```

## 구성
<a name="streams-tumbling-config"></a>

이벤트 소스 매핑을 생성하거나 업데이트할 때 텀블링 윈도우를 구성할 수 있습니다. 텀블링 윈도우를 구성하려면 윈도우를 초 단위로 지정합니다([TumblingWindowInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-TumblingWindowInSeconds)). 다음 예제 AWS Command Line Interface(AWS CLI) 명령은 텀블링 윈도우가 120초인 스트리밍 이벤트 소스 매핑을 생성합니다. 집계 및 처리를 위해 정의된 Lambda 함수는 `tumbling-window-example-function`입니다.

```
aws lambda create-event-source-mapping \
--event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525 \
--function-name tumbling-window-example-function \
--starting-position TRIM_HORIZON \
--tumbling-window-in-seconds 120
```

Lambda는 레코드가 스트림에 삽입된 시간을 기준으로 텀블링 윈도우 경계를 결정합니다. 모든 레코드에는 Lambda가 경계 결정에서 사용하는 대략적인 타임스탬프가 있습니다.

텀블링 윈도우 집계는 리샤딩을 지원하지 않습니다. 샤드가 끝나면 Lambda는 윈도우가 닫힌 것으로 간주하며 자식 샤드는 새 상태로 고유한 윈도우를 시작합니다.

텀블링 윈도우는 기존 재시도 정책 `maxRetryAttempts` 및 `maxRecordAge`를 완벽하게 지원합니다.

**Example Handler.py - 집계 및 처리**  
다음 Python 함수는 최종 상태를 집계한 다음 처리하는 방법을 보여줍니다.  

```
def lambda_handler(event, context):
    print('Incoming event: ', event)
    print('Incoming state: ', event['state'])

#Check if this is the end of the window to either aggregate or process.
    if event['isFinalInvokeForWindow']:
        # logic to handle final state of the window
        print('Destination invoke')
    else:
        print('Aggregate invoke')

#Check for early terminations
    if event['isWindowTerminatedEarly']:
        print('Window terminated early')

    #Aggregation logic
    state = event['state']
    for record in event['Records']:
        state[record['dynamodb']['NewImage']['Id']] = state.get(record['dynamodb']['NewImage']['Id'], 0) + 1

    print('Returning state: ', state)
    return {'state': state}
```

# Amazon DynamoDB 이벤트 소스 매핑을 위한 Lambda 파라미터
<a name="services-ddb-params"></a>

모든 Lambda 이벤트 소스 유형은 동일한 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 및 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 작업을 공유합니다. 그러나 일부 파라미터만 DynamoDB Streams에 적용됩니다.


| 파라미터 | 필수 | 기본값 | 참고 | 
| --- | --- | --- | --- | 
|  BatchSize  |  N  |  100  |  최대값: 10,000  | 
|  BisectBatchOnFunctionError  |  N  |  false  | 없음  | 
|  DestinationConfig  |  N  | 해당 사항 없음  |  폐기된 레코드의 표준 Amazon SQS 대기열 또는 표준 Amazon SNS 주제 대상  | 
|  활성  |  N  |  true  | 없음  | 
|  EventSourceArn  |  Y  | 해당 사항 없음 |  데이터 스트림 또는 스트림 소비자의 ARN  | 
|  FilterCriteria  |  N  | 해당 사항 없음  |  [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)  | 
|  FunctionName  |  Y  | 해당 사항 없음  | 없음  | 
|  FunctionResponseTypes  |  N  | 해당 사항 없음 |  함수가 배치에서 특정 실패를 보고하도록 하려면 `FunctionResponseTypes`에 `ReportBatchItemFailures` 값을 포함하세요. 자세한 내용은 [DynamoDB 및 Lambda로 부분 배치 응답 구성](services-ddb-batchfailurereporting.md) 섹션을 참조하세요.  | 
|  MaximumBatchingWindowInSeconds  |  N  |  0  | 없음  | 
|  MaximumRecordAgeInSeconds  |  N  |  -1  |  -1은 무한을 의미하며 실패한 레코드는 레코드가 만료될 때까지 재시도됩니다. [DynamoDB 스트림의 데이터 보존 한도](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html#Streams.DataRetention)는 24시간입니다. 최솟값: -1 최대값: 604,800  | 
|  MaximumRetryAttempts  |  N  |  -1  |  -1(무한): 레코드가 만료될 때까지 실패한 레코드가 다시 시도됩니다 최솟값: 0 최대값: 10,000  | 
|  ParallelizationFactor  |  N  |  1  |  최댓값: 10  | 
|  StartingPosition  |  Y  | 해당 사항 없음  |  TRIM\$1HIZON 또는 LATEST  | 
|  TumblingWindowInSeconds  |  N  | 해당 사항 없음  |  최솟값: 0 최댓값: 900  | 

# DynamoDB 이벤트 소스를 통해 이벤트 필터링 사용
<a name="with-ddb-filtering"></a>

이벤트 필터링을 사용하여 Lambda가 함수로 전송하는 스트림 또는 대기열의 레코드를 제어할 수 있습니다. 이벤트 필터링의 작동 방식에 대한 일반적인 내용은 [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)을 참조하세요.

이 섹션에서는 DynamoDB 이벤트 소스에 대한 이벤트 필터링에 중점을 둡니다.

**참고**  
DynamoDB 이벤트 소스 매핑은 `dynamodb` 키에 대한 필터링만 지원합니다.

**Topics**
+ [

## DynamoDB 이벤트
](#filtering-ddb)
+ [

## 테이블 속성으로 필터링
](#filtering-ddb-attributes)
+ [

## 부울 표현식으로 필터링
](#filtering-ddb-boolean)
+ [

## Exists 연산자 사용
](#filtering-ddb-exists)
+ [

## DynamoDB 필터링을 위한 JSON 형식
](#filtering-ddb-JSON-format)

## DynamoDB 이벤트
<a name="filtering-ddb"></a>

프라이머리 키 `CustomerName`과 `AccountManager` 및 `PaymentTerms` 속성이 있는 DynamoDB 테이블이 있다고 가정해 보겠습니다. 다음은 DynamoDB 테이블 스트림의 예제 레코드를 보여줍니다.

```
{
      "eventID": "1",
      "eventVersion": "1.0",
      "dynamodb": {
          "ApproximateCreationDateTime": "1678831218.0",
          "Keys": {
              "CustomerName": {
                  "S": "AnyCompany Industries"
              }
          },
          "NewImage": {
              "AccountManager": {
                  "S": "Pat Candella"
              },
              "PaymentTerms": {
                  "S": "60 days"
              },
              "CustomerName": {
                  "S": "AnyCompany Industries"
              }
          },
          "SequenceNumber": "111",
          "SizeBytes": 26,
          "StreamViewType": "NEW_IMAGE"
      }
  }
```

DynamoDB 테이블의 키 및 속성 값을 기준으로 필터링하려면 레코드의 `dynamodb` 키를 사용하세요. 다음 섹션에는 다양한 필터 유형에 대한 예제가 나와 있습니다.

### 테이블 키로 필터링
<a name="filtering-ddb-keys"></a>

프라이머리 키 `CustomerName`이 'AnyCompany Industries'인 레코드만 함수에서 처리하도록 하려는 경우를 가정해 보겠습니다. `FilterCriteria` 객체는 다음과 같습니다.

```
{
     "Filters": [
          {
              "Pattern": "{ \"dynamodb\" : { \"Keys\" : { \"CustomerName\" : { \"S\" : [ \"AnyCompany Industries\" ] } } } }"
          }
      ]
 }
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{
     "dynamodb": {
          "Keys": {
              "CustomerName": {
                  "S": [ "AnyCompany Industries" ]
                  }
              }
          }
 }
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "dynamodb" : { "Keys" : { "CustomerName" : { "S" : [ "AnyCompany Industries" ] } } } }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"Keys\" : { \"CustomerName\" : { \"S\" : [ \"AnyCompany Industries\" ] } } } }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"Keys\" : { \"CustomerName\" : { \"S\" : [ \"AnyCompany Industries\" ] } } } }"}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
   Filters:
     - Pattern: '{ "dynamodb" : { "Keys" : { "CustomerName" : { "S" : [ "AnyCompany Industries" ] } } } }'
```

------

## 테이블 속성으로 필터링
<a name="filtering-ddb-attributes"></a>

DynamoDB에서는 `NewImage` 및 `OldImage` 키를 사용하여 속성 값을 필터링할 수도 있습니다. 최신 테이블 이미지의 `AccountManager` 속성이 'Pat Candella' 또는 'Shirley Rodriguez'인 레코드를 필터링하려고 한다고 가정해 보겠습니다. `FilterCriteria` 객체는 다음과 같습니다.

```
{
    "Filters": [
        {
            "Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\", \"Shirley Rodriguez\" ] } } } }"
        }
    ]
}
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{
    "dynamodb": {
        "NewImage": {
            "AccountManager": {
                "S": [ "Pat Candella", "Shirley Rodriguez" ]
            }
        }
    }
}
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "dynamodb" : { "NewImage" : { "AccountManager" : { "S" : [ "Pat Candella", "Shirley Rodriguez" ] } } } }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\", \"Shirley Rodriguez\" ] } } } }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\", \"Shirley Rodriguez\" ] } } } }"}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
  Filters:
    - Pattern: '{ "dynamodb" : { "NewImage" : { "AccountManager" : { "S" : [ "Pat Candella", "Shirley Rodriguez" ] } } } }'
```

------

## 부울 표현식으로 필터링
<a name="filtering-ddb-boolean"></a>

부울 AND 표현식을 사용하여 필터를 생성할 수도 있습니다. 이러한 표현식에는 테이블의 키 및 속성 파라미터가 모두 포함될 수 있습니다. `AccountManager`의 `NewImage` 값이 'Pat Candella'이고 `OldImage` 값이 'Terry Whitlock'인 레코드를 필터링하려고 한다고 가정해 보겠습니다. `FilterCriteria` 객체는 다음과 같습니다.

```
{
    "Filters": [
        {
            "Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\" ] } } } , \"dynamodb\" : { \"OldImage\" : { \"AccountManager\" : { \"S\" : [ \"Terry Whitlock\" ] } } } }"
        }
    ]
}
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{ 
    "dynamodb" : { 
        "NewImage" : { 
            "AccountManager" : { 
                "S" : [ 
                    "Pat Candella" 
                ] 
            } 
        } 
    }, 
    "dynamodb": { 
        "OldImage": { 
            "AccountManager": { 
                "S": [ 
                    "Terry Whitlock" 
                ] 
            } 
        } 
    } 
}
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "dynamodb" : { "NewImage" : { "AccountManager" : { "S" : [ "Pat Candella" ] } } } , "dynamodb" : { "OldImage" : { "AccountManager" : { "S" : [ "Terry Whitlock" ] } } } }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:dynamodb:us-east-2:123456789012:table/my-table \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\" ] } } } , \"dynamodb\" : { \"OldImage\" : { \"AccountManager\" : { \"S\" : [ \"Terry Whitlock\" ] } } } } "}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"dynamodb\" : { \"NewImage\" : { \"AccountManager\" : { \"S\" : [ \"Pat Candella\" ] } } } , \"dynamodb\" : { \"OldImage\" : { \"AccountManager\" : { \"S\" : [ \"Terry Whitlock\" ] } } } } "}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
  Filters:
    - Pattern: '{ "dynamodb" : { "NewImage" : { "AccountManager" : { "S" : [ "Pat Candella" ] } } } , "dynamodb" : { "OldImage" : { "AccountManager" : { "S" : [ "Terry Whitlock" ] } } } }'
```

------

**참고**  
DynamoDB 이벤트 필터링은 숫자 연산자(숫자 등호 및 숫자 범위)의 사용을 지원하지 않습니다. 테이블의 항목이 숫자로 저장되더라도 이러한 파라미터는 JSON 레코드 객체의 문자열로 변환됩니다.

## Exists 연산자 사용
<a name="filtering-ddb-exists"></a>

DynamoDB의 JSON 이벤트 객체가 구조화되는 방식으로 인해 Exists 연산자를 사용하려면 특별한 주의가 필요합니다. Exists 연산자는 이벤트 JSON의 리프 노드에서만 작동하므로 필터 패턴이 Exists를 사용하여 중간 노드를 테스트하는 경우에는 작동하지 않습니다. 다음 DynamoDB 테이블 항목을 고려하세요.

```
{
  "UserID": {"S": "12345"},
  "Name": {"S": "John Doe"},
  "Organizations": {"L": [
      {"S":"Sales"},
      {"S":"Marketing"},
      {"S":"Support"}
    ]
  }
}
```

`"Organizations"`가 포함된 이벤트를 테스트하는 다음과 같은 필터 패턴을 생성할 수 있습니다.

```
{ "dynamodb" : { "NewImage" : { "Organizations" : [ { "exists": true } ] } } }
```

그러나 이 필터 패턴은 `"Organizations"`가 리프 노드가 아니므로 일치하는 항목을 반환하지 않습니다. 다음 예제에서는 Exists 연산자를 올바르게 사용하여 원하는 필터 패턴을 구성하는 방법을 보여줍니다.

```
{ "dynamodb" : { "NewImage" : {"Organizations": {"L": {"S": [ {"exists": true } ] } } } } }
```

## DynamoDB 필터링을 위한 JSON 형식
<a name="filtering-ddb-JSON-format"></a>

DynamoDB 소스에서 이벤트를 올바르게 필터링하려면 데이터 필드와 데이터 필드(`dynamodb`)의 필터 기준이 모두 유효한 JSON 형식이어야 합니다. 두 필드 중 하나가 유효한 JSON 형식이 아닌 경우 Lambda는 해당 메시지를 삭제하거나 예외를 발생시킵니다. 다음 표에는 특정 동작이 요약되어 있습니다.


| 수신 데이터 형식 | 데이터 속성에 대한 필터 패턴 형식 | 결과적 작업 | 
| --- | --- | --- | 
|  유효한 JSON  |  유효한 JSON  |  Lambda는 필터 기준에 따라 필터링합니다.  | 
|  유효한 JSON  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  유효한 JSON  |  JSON 외  |  이벤트 소스 매핑 생성 또는 업데이트 시 Lambda에서 예외가 발생합니다. 데이터 속성에 대한 필터 패턴은 유효한 JSON 형식이어야 합니다.  | 
|  JSON 외  |  유효한 JSON  |  Lambda는 해당 레코드를 삭제합니다.  | 
|  JSON 외  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  JSON 외  |  JSON 외  |  이벤트 소스 매핑 생성 또는 업데이트 시 Lambda에서 예외가 발생합니다. 데이터 속성에 대한 필터 패턴은 유효한 JSON 형식이어야 합니다.  | 

# 자습서: Amazon DynamoDB Streams와 함께 AWS Lambda 사용
<a name="with-ddb-example"></a>

 이 자습서에서는 Amazon DynamoDB 스트림의 이벤트를 사용하기 위해 Lambda 함수를 생성합니다.

## 사전 조건
<a name="with-ddb-prepare"></a>

### AWS Command Line Interface 설치
<a name="install_aws_cli"></a>

아직 AWS Command Line Interface를 설치하지 않은 경우 [AWS CLI의 최신 버전 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)에서 설명하는 단계에 따라 설치하세요.

이 자습서에서는 명령을 실행할 셸 또는 명령줄 터미널이 필요합니다. Linux 및 macOS에서는 선호하는 셸과 패키지 관리자를 사용합니다.

**참고**  
Windows에서는 Lambda와 함께 일반적으로 사용하는 일부 Bash CLI 명령(예:`zip`)은 운영 체제의 기본 제공 터미널에서 지원되지 않습니다. Ubuntu와 Bash의 Windows 통합 버전을 가져오려면 [Linux용 Windows Subsystem을 설치](https://docs.microsoft.com/en-us/windows/wsl/install-win10)합니다.

## 실행 역할 생성
<a name="with-ddb-create-execution-role"></a>

함수에 AWS 리소스에 액세스할 수 있는 권한을 제공하는 [실행 역할](lambda-intro-execution-role.md)을 만듭니다.

**실행 역할을 만들려면**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. **역할 생성**을 선택합니다.

1. 다음 속성을 사용하여 역할을 만듭니다.
   + **신뢰할 수 있는 엔터티** – Lambda.
   + **권한** – **AWSLambdaDynamoDBExecutionRole**.
   + **역할 이름** – **lambda-dynamodb-role**.

**AWSLambdaDynamoDBExecutionRole**은 함수가 DynamoDB에서 항목을 읽고 CloudWatch Logs에 로그를 쓰는 데 필요한 권한을 가집니다.

## 함수 생성
<a name="with-ddb-example-create-function"></a>

DynamoDB 이벤트를 처리하는 Lambda 함수를 생성하세요. 함수 코드는 수신 이벤트 데이터 중 일부를 CloudWatch Logs에 기록합니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 DynamoDB 이벤트 사용.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
using System.Text.Json;
using System.Text;
using Amazon.Lambda.Core;
using Amazon.Lambda.DynamoDBEvents;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace AWSLambda_DDB;

public class Function
{
    public void FunctionHandler(DynamoDBEvent dynamoEvent, ILambdaContext context)
    {
        context.Logger.LogInformation($"Beginning to process {dynamoEvent.Records.Count} records...");

        foreach (var record in dynamoEvent.Records)
        {
            context.Logger.LogInformation($"Event ID: {record.EventID}");
            context.Logger.LogInformation($"Event Name: {record.EventName}");

            context.Logger.LogInformation(JsonSerializer.Serialize(record));
        }

        context.Logger.LogInformation("Stream processing complete.");
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 DynamoDB 이벤트 사용.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-lambda-go/events"
	"fmt"
)

func HandleRequest(ctx context.Context, event events.DynamoDBEvent) (*string, error) {
	if len(event.Records) == 0 {
		return nil, fmt.Errorf("received empty event")
	}

	for _, record := range event.Records {
	 	LogDynamoDBRecord(record)
	}

	message := fmt.Sprintf("Records processed: %d", len(event.Records))
	return &message, nil
}

func main() {
	lambda.Start(HandleRequest)
}

func LogDynamoDBRecord(record events.DynamoDBEventRecord){
	fmt.Println(record.EventID)
	fmt.Println(record.EventName)
	fmt.Printf("%+v\n", record.Change)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda로 DynamoDB 이벤트 소비  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent.DynamodbStreamRecord;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class example implements RequestHandler<DynamodbEvent, Void> {

    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

    @Override
    public Void handleRequest(DynamodbEvent event, Context context) {
        System.out.println(GSON.toJson(event));
        event.getRecords().forEach(this::logDynamoDBRecord);
        return null;
    }

    private void logDynamoDBRecord(DynamodbStreamRecord record) {
        System.out.println(record.getEventID());
        System.out.println(record.getEventName());
        System.out.println("DynamoDB Record: " + GSON.toJson(record.getDynamodb()));
    }
}
```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda로 DynamoDB 이벤트 사용.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
    console.log(JSON.stringify(event, null, 2));
    event.Records.forEach(record => {
        logDynamoDBRecord(record);
    });
};

const logDynamoDBRecord = (record) => {
    console.log(record.eventID);
    console.log(record.eventName);
    console.log(`DynamoDB Record: ${JSON.stringify(record.dynamodb)}`);
};
```
TypeScript를 사용하여 Lambda로 DynamoDB 이벤트 사용.  

```
export const handler = async (event, context) => {
    console.log(JSON.stringify(event, null, 2));
    event.Records.forEach(record => {
        logDynamoDBRecord(record);
    });
}
const logDynamoDBRecord = (record) => {
    console.log(record.eventID);
    console.log(record.eventName);
    console.log(`DynamoDB Record: ${JSON.stringify(record.dynamodb)}`);
};
```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 DynamoDB 이벤트 사용.  

```
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\DynamoDb\DynamoDbEvent;
use Bref\Event\DynamoDb\DynamoDbHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler extends DynamoDbHandler
{
    private StderrLogger $logger;

    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handleDynamoDb(DynamoDbEvent $event, Context $context): void
    {
        $this->logger->info("Processing DynamoDb table items");
        $records = $event->getRecords();

        foreach ($records as $record) {
            $eventName = $record->getEventName();
            $keys = $record->getKeys();
            $old = $record->getOldImage();
            $new = $record->getNewImage();
            
            $this->logger->info("Event Name:".$eventName."\n");
            $this->logger->info("Keys:". json_encode($keys)."\n");
            $this->logger->info("Old Image:". json_encode($old)."\n");
            $this->logger->info("New Image:". json_encode($new));
            
            // TODO: Do interesting work based on the new data

            // Any exception thrown will be logged and the invocation will be marked as failed
        }

        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords items");
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 DynamoDB 이벤트 사용.  

```
import json

def lambda_handler(event, context):
    print(json.dumps(event, indent=2))

    for record in event['Records']:
        log_dynamodb_record(record)

def log_dynamodb_record(record):
    print(record['eventID'])
    print(record['eventName'])
    print(f"DynamoDB Record: {json.dumps(record['dynamodb'])}")
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 DynamoDB 이벤트 사용.  

```
def lambda_handler(event:, context:)
    return 'received empty event' if event['Records'].empty?
  
    event['Records'].each do |record|
      log_dynamodb_record(record)
    end
  
    "Records processed: #{event['Records'].length}"
  end
  
  def log_dynamodb_record(record)
    puts record['eventID']
    puts record['eventName']
    puts "DynamoDB Record: #{JSON.generate(record['dynamodb'])}"
  end
```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-ddb-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 DynamoDB 이벤트 사용.  

```
use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
use aws_lambda_events::{
    event::dynamodb::{Event, EventRecord},
   };


// Built with the following dependencies:
//lambda_runtime = "0.11.1"
//serde_json = "1.0"
//tokio = { version = "1", features = ["macros"] }
//tracing = { version = "0.1", features = ["log"] }
//tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
//aws_lambda_events = "0.15.0"

async fn function_handler(event: LambdaEvent<Event>) ->Result<(), Error> {
    
    let records = &event.payload.records;
    tracing::info!("event payload: {:?}",records);
    if records.is_empty() {
        tracing::info!("No records found. Exiting.");
        return Ok(());
    }

    for record in records{
        log_dynamo_dbrecord(record);
    }

    tracing::info!("Dynamo db records processed");

    // Prepare the response
    Ok(())

}

fn log_dynamo_dbrecord(record: &EventRecord)-> Result<(), Error>{
    tracing::info!("EventId: {}", record.event_id);
    tracing::info!("EventName: {}", record.event_name);
    tracing::info!("DynamoDB Record: {:?}", record.change );
    Ok(())

}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
    .with_max_level(tracing::Level::INFO)
    .with_target(false)
    .without_time()
    .init();

    let func = service_fn(function_handler);
    lambda_runtime::run(func).await?;
    Ok(())
    
}
```

------

**함수를 만들려면**

1. 샘플 코드를 `example.js` 파일에 복사합니다.

1. 배포 패키지를 만듭니다.

   ```
   zip function.zip example.js
   ```

1. `create-function` 명령을 사용해 Lambda 함수를 만듭니다.

   ```
   aws lambda create-function --function-name ProcessDynamoDBRecords \
       --zip-file fileb://function.zip --handler example.handler --runtime nodejs24.x \
       --role arn:aws:iam::111122223333:role/lambda-dynamodb-role
   ```

## Lambda 함수 테스트
<a name="with-dbb-invoke-manually"></a>

이 단계에서는 `invoke` AWS Lambda CLI 명령과 다음 샘플 DynamoDB 이벤트를 사용하여 수동으로 Lambda 함수를 간접 호출합니다. 다음을 `input.txt`라는 파일에 복사합니다.

**Example input.txt**  

```
{
   "Records":[
      {
         "eventID":"1",
         "eventName":"INSERT",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "NewImage":{
               "Message":{
                  "S":"New item!"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"111",
            "SizeBytes":26,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      },
      {
         "eventID":"2",
         "eventName":"MODIFY",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "NewImage":{
               "Message":{
                  "S":"This item has changed"
               },
               "Id":{
                  "N":"101"
               }
            },
            "OldImage":{
               "Message":{
                  "S":"New item!"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"222",
            "SizeBytes":59,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      },
      {
         "eventID":"3",
         "eventName":"REMOVE",
         "eventVersion":"1.0",
         "eventSource":"aws:dynamodb",
         "awsRegion":"us-east-1",
         "dynamodb":{
            "Keys":{
               "Id":{
                  "N":"101"
               }
            },
            "OldImage":{
               "Message":{
                  "S":"This item has changed"
               },
               "Id":{
                  "N":"101"
               }
            },
            "SequenceNumber":"333",
            "SizeBytes":38,
            "StreamViewType":"NEW_AND_OLD_IMAGES"
         },
         "eventSourceARN":"stream-ARN"
      }
   ]
}
```

다음 `invoke` 명령을 실행합니다.

```
aws lambda invoke --function-name ProcessDynamoDBRecords \
    --cli-binary-format raw-in-base64-out \
    --payload file://input.txt outputfile.txt
```

**cli-binary-format** 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 `aws configure set cli-binary-format raw-in-base64-out`을(를) 실행하세요. 자세한 내용은 [AWS CLI 지원되는 글로벌 명령줄 옵션](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)을 *AWS Command Line Interface 사용 설명서 버전 2에서 참조하세요*.

이 함수는 응답 본문에 문자열 `message`를 반환합니다.

`outputfile.txt` 파일의 출력을 확인합니다.

## 스트림을 활성화하여 DynamoDB 테이블 생성
<a name="with-ddb-create-buckets"></a>

스트림을 활성화하여 Amazon DynamoDB 테이블을 생성합니다.

**DynamoDB 테이블을 생성하려면**

1. [DynamoDB 콘솔](https://console.aws.amazon.com/dynamodb)을 엽니다.

1. [**Create table**]을 선택합니다.

1. 다음 설정을 사용하여 테이블을 생성합니다.
   + **테이블 이름** – **lambda-dynamodb-stream**
   + **기본 키** – **id**(문자열)

1. **Create**를 선택합니다.

**스트림을 활성화하려면**

1. [DynamoDB 콘솔](https://console.aws.amazon.com/dynamodb)을 엽니다.

1. **테이블**을 선택합니다.

1. **lambda-dynamodb-stream** 테이블을 선택합니다.

1. **내보내기 및 스트림**에서 **DynamoDB 스트림 세부 정보**를 선택합니다.

1. **켜기**를 선택합니다.

1. **보기 유형**에서는 **키 속성만**을 선택합니다.

1. **스트림 켜기**를 선택합니다.

스트림 ARN을 적어둡니다. 다음 단계에서 스트림을 Lambda 함수와 연결할 때 필요합니다. 스트림 활성화에 대한 자세한 내용은 [DynamoDB 스트림을 사용하여 Table Activity 캡처](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html)를 참조하세요.

## AWS Lambda에서 이벤트 소스 추가
<a name="with-ddb-attach-notification-configuration"></a>

AWS Lambda에서 이벤트 소스 매핑을 생성합니다. 이 이벤트 소스 매핑은 DynamoDB 스트림을 Lambda 함수와 연결합니다. 이 이벤트 소스 매핑을 생성하면 AWS Lambda가 스트림 폴링을 시작합니다.

다음 AWS CLI `create-event-source-mapping` 명령을 실행합니다. 명령이 실행된 후 UUID를 적어둡니다. 예를 들어, 이벤트 소스 매핑을 삭제할 때처럼 모든 명령에서 이벤트 소스 매핑을 참조하려면 이 UUID가 필요합니다.

```
aws lambda create-event-source-mapping --function-name ProcessDynamoDBRecords \
    --batch-size 100 --starting-position LATEST --event-source DynamoDB-stream-arn
```

 이는 지정된 DynamoDB 스트림과 Lambda 함수 사이의 매핑을 생성합니다. DynamoDB 스트림을 여러 Lambda 함수와 연결하고 동일한 Lambda 함수를 여러 스트림과 연결할 수 있습니다. 하지만 Lambda 함수는 공유하는 스트림에 대해 읽기 처리량을 공유합니다.

다음 명령을 실행하여 이벤트 소스 매핑 목록을 가져올 수 있습니다.

```
aws lambda list-event-source-mappings
```

이 목록은 사용자가 생성한 모든 이벤트 소스 매핑을 반환하며 각 매핑에 대해 `LastProcessingResult`를 표시합니다. 이 필드는 문제가 있을 경우 유용한 메시지를 제공하는 데 사용됩니다. `No records processed`(AWS Lambda가 폴링을 시작하지 않았거나 스트림에 레코드가 없음을 나타냄) 및 `OK`(AWS Lambda가 레코드를 성공적으로 읽고 Lambda 함수를 간접 호출함을 나타냄) 같은 값은 아무 문제가 없다는 점을 나타냅니다. 문제가 있는 경우 오류 메시지를 수신합니다.

이벤트 소스 매핑이 많을 경우 함수 이름 파라미터를 사용하여 결과 범위를 좁히세요.

```
aws lambda list-event-source-mappings --function-name ProcessDynamoDBRecords
```

## 설정 테스트
<a name="with-ddb-final-integration-test-no-iam"></a>

종합적 경험을 테스트합니다. 테이블 업데이트를 수행할 때 DynamoDB는 이벤트 레코드를 스트림에 기록합니다. AWS Lambda가 스트림을 폴링하면 스트림의 새 레코드를 감지하고 이벤트를 함수에 전달하여 사용자를 대신하여 Lambda 함수를 간접 호출합니다.

1. DynamoDB 콘솔에서 테이블에 항목을 추가, 업데이트하고 항목을 삭제합니다. DynamoDB는 이러한 작업에 대한 레코드를 스트림에 기록합니다.

1. AWS Lambda가 스트림을 폴링하고 스트림에 대한 업데이트를 감지하면 스트림에서 찾은 이벤트 데이터를 전달하여 Lambda 함수를 간접 호출합니다.

1. 함수는 Amazon CloudWatch에서 로그를 실행하고 생성합니다. Amazon CloudWatch 콘솔에서 보고된 로그를 확인할 수 있습니다.

## 다음 단계
<a name="with-ddb-next-steps"></a>

이 자습서에서는 Lambda를 사용하여 DynamoDB 스트림 이벤트를 처리하는 기본 과정을 보여줍니다. 프로덕션 워크로드의 경우 부분 배치 응답 로직을 구현하여 개별 레코드 오류를 보다 효율적으로 처리하는 것이 좋습니다. Powertools for AWS Lambda의 [배치 프로세서 유틸리티](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)는 Python, TypeScript, .NET 및 Java에서 사용할 수 있으며 이를 위한 강력한 솔루션을 제공하여 부분 배치 응답의 복잡성을 자동으로 처리하고 처리 완료된 레코드에 대한 재시도 횟수를 줄입니다.

## 리소스 정리
<a name="cleanup"></a>

이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.

**Lambda 함수를 삭제하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 생성한 함수를 선택합니다.

1. **작업**(Actions), **삭제**(Delete)를 선택합니다.

1. 텍스트 입력 필드에 **confirm**를 입력하고 **Delete**(삭제)를 선택합니다.

**집행 역할 삭제**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. 생성한 실행 역할을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 역할의 이름을 입력하고 **Delete**(삭제)를 선택합니다.

**DynamoDB 테이블을 삭제하려면**

1. DynamoDB 콘솔의 [테이블 페이지](https://console.aws.amazon.com//dynamodb/home#tables:)를 엽니다.

1. 생성한 테이블을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 상자에 **delete**를 입력합니다.

1. **테이블 삭제**를 선택합니다.

# Lambda 함수로 Amazon EC2 수명 주기 이벤트 처리
<a name="services-ec2"></a>

AWS Lambda를 사용해 Amazon Elastic Compute Cloud의 수명 주기 이벤트를 처리하고 Amazon EC2 리소스를 관리할 수 있습니다. Amazon EC2는 인스턴스가 상태를 변경하는 경우, Amazon Elastic Block Store 볼륨 스냅샷이 완료되는 경우, 또는 스팟 인스턴스가 종료되도록 예약된 경우와 같은 [수명 주기 이벤트](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-lifecycle.html)를 [Amazon EventBridge(CloudWatch Events)](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html)에 보냅니다. 처리를 위해 이러한 이벤트를 Lambda 함수로 전달하도록 EventBridge(CloudWatch Events)를 구성합니다.

EventBridge(CloudWatch Events)는 Amazon EC2의 이벤트 문서와 비동기적으로 Lambda 함수를 호출합니다.

**Example 인스턴스 수명 주기 이벤트**  

```
{
    "version": "0",
    "id": "b6ba298a-7732-2226-xmpl-976312c1a050",
    "detail-type": "EC2 Instance State-change Notification",
    "source": "aws.ec2",
    "account": "111122223333",
    "time": "2019-10-02T17:59:30Z",
    "region": "us-east-1",
    "resources": [
        "arn:aws:ec2:us-east-1:111122223333:instance/i-0c314xmplcd5b8173"
    ],
    "detail": {
        "instance-id": "i-0c314xmplcd5b8173",
        "state": "running"
    }
}
```

이벤트를 구성하는 방법에 대한 자세한 내용은 [일정에 따라 Lambda 함수 간접 호출](with-eventbridge-scheduler.md) 섹션을 참조하세요. Amazon EBS 스냅샷 알림을 처리하는 예제 함수는 [EventBridge Scheduler for Amazon EBS](https://docs.aws.amazon.com/ebs/latest/userguide/ebs-cloud-watch-events.html)를 참조하세요.

AWS SDK를 사용하여 Amazon EC2 API로 인스턴스 및 기타 리소스를 관리할 수도 있습니다.

## EventBridge(CloudWatch Events)에 권한 부여
<a name="services-ec2-permissions"></a>

Amazon EC2의 수명 주기 이벤트를 처리하려면 EventBridge(CloudWatch Events)가 함수를 호출할 권한이 필요합니다. 이 권한은 함수의 [리소스 기반 정책](access-control-resource-based.md)에서 비롯됩니다. EventBridge(CloudWatch Events) 콘솔을 사용하여 이벤트 트리거를 구성하면 콘솔이 사용자를 대신하여 리소스 기반 정책을 업데이트합니다. 또는, 다음과 같은 문을 추가합니다.

**Example Amazon EC2 수명 주기 알림을 위한 리소스 기반 정책 문**  

```
{
  "Sid": "ec2-events",
  "Effect": "Allow",
  "Principal": {
    "Service": "events.amazonaws.com"
  },
  "Action": "lambda:InvokeFunction",
  "Resource": "arn:aws:lambda:us-east-1:12456789012:function:my-function",
  "Condition": {
    "ArnLike": {
      "AWS:SourceArn": "arn:aws:events:us-east-1:12456789012:rule/*"
    }
  }
}
```

문을 추가하려면 `add-permission` AWS CLI 명령을 사용합니다.

```
aws lambda add-permission --action lambda:InvokeFunction --statement-id ec2-events \
--principal events.amazonaws.com --function-name my-function --source-arn 'arn:aws:events:us-east-1:12456789012:rule/*'
```

함수가 AWS SDK를 사용하여 Amazon EC2 리소스를 관리하는 경우 Amazon EC2 권한을 함수의 [실행 역할](lambda-intro-execution-role.md)에 추가합니다.

# Lambda로 Application Load Balancer 요청 처리
<a name="services-alb"></a>

Lambda 함수를 사용하여 Application Load Balancer의 요청을 처리할 수 있습니다. Elastic Load Balancing은 Application Load Balancer의 대상으로 Lambda 함수를 지원합니다. 로드 밸런서 규칙을 사용하여 경로 또는 헤더 값을 기반으로 HTTP 요청을 함수에 라우팅합니다. 요청을 처리하고 Lambda 함수의 HTTP 응답을 반환합니다.

Elastic Load Balancing은 요청 본문 및 메타데이터가 포함된 이벤트와 동기적으로 Lambda 함수를 간접 호출합니다.

**Example Application Load Balancer 요청 이벤트**  

```
{
    "requestContext": {
        "elb": {
            "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/lambda-279XGJDqGZ5rsrHC2Fjr/49e9d65c45c6791a"
        }
    },
    "httpMethod": "GET",
    "path": "/lambda",
    "queryStringParameters": {
        "query": "1234ABCD"
    },
    "headers": {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "accept-encoding": "gzip",
        "accept-language": "en-US,en;q=0.9",
        "connection": "keep-alive",
        "host": "lambda-alb-123578498.us-east-1.elb.amazonaws.com",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
        "x-amzn-trace-id": "Root=1-5c536348-3d683b8b04734faae651f476",
        "x-forwarded-for": "72.12.164.125",
        "x-forwarded-port": "80",
        "x-forwarded-proto": "http",
        "x-imforwards": "20"
    },
    "body": "",
    "isBase64Encoded": False
}
```

함수는 이벤트를 처리하고 JSON 형식의 응답 문서를 로드 밸런서에 반환합니다. Elastic Load Balancing은 이 문서를 HTTP 성공 또는 오류 응답으로 변환하고 사용자에게 반환합니다.

**Example 응답 문서 형식**  

```
{
    "statusCode": 200,
    "statusDescription": "200 OK",
    "isBase64Encoded": False,
    "headers": {
        "Content-Type": "text/html"
    },
    "body": "<h1>Hello from Lambda!</h1>"
}
```

Application Load Balancer를 함수 트리거로 구성하려면 함수 실행 권한을 Elastic Load Balancing에 부여하고 해당 요청을 함수로 라우팅하는 대상 그룹을 만든 다음, 대상 그룹에 요청을 보내는 로드 밸런서에 하나의 규칙을 추가하세요.

`add-permission` 명령을 사용하여 권한 설명문을 함수의 리소스 기반 정책에 추가하세요.

```
aws lambda add-permission --function-name alb-function \
--statement-id load-balancer --action "lambda:InvokeFunction" \
--principal elasticloadbalancing.amazonaws.com
```

다음 결과가 표시됩니다:

```
{
    "Statement": "{\"Sid\":\"load-balancer\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"elasticloadbalancing.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-west-2:123456789012:function:alb-function\"}"
}
```

Application Load Balancer 리스너와 대상 그룹을 구성하는 방법에 대한 지침은 *Application Load Balancers 사용 설명서*에서 [대상으로서 Lambda 함수](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html)를 참조하세요.

## Powertools for AWS Lambda의 이벤트 핸들러
<a name="services-alb-powertools"></a>

Powertools for AWS Lambda 도구 키트의 이벤트 핸들러는 Application Load Balancer에서 간접 호출한 Lambda 함수를 작성할 때 라우팅, 미들웨어, CORS 구성, OpenAPI 사양 생성, 요청 검증, 오류 처리 및 기타 유용한 기능을 제공합니다. 이벤트 핸들러 유틸리티는 Python에서 사용할 수 있습니다. 자세한 내용은 *Powertools for AWS Lambda(Python) 설명서*의 [이벤트 핸들러 REST API](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/)를 참조하세요.

### Python
<a name="services-alb-powertools-python"></a>

```
import requests
from requests import Response

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import ALBResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()
app = ALBResolver()


@app.get("/todos")
@tracer.capture_method
def get_todos():
    todos: Response = requests.get("https://jsonplaceholder.typicode.com/todos")
    todos.raise_for_status()

    # for brevity, we'll limit to the first 10 only
    return {"todos": todos.json()[:10]}


# You can continue to use other utilities just as before
@logger.inject_lambda_context(correlation_id_path=correlation_paths.APPLICATION_LOAD_BALANCER)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
    return app.resolve(event, context)
```

# 일정에 따라 Lambda 함수 간접 호출
<a name="with-eventbridge-scheduler"></a>

[Amazon EventBridge 스케줄러](https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html)는 하나의 중앙 관리형 서비스에서 작업을 생성, 실행 및 관리할 수 있는 서버리스 스케줄러입니다. EventBridge 스케줄러를 사용하면 반복 패턴에 대해 cron 및 rate 표현식을 사용하여 일정을 만들거나 일회성 간접 호출을 구성할 수 있습니다. 전송을 위한 유연한 기간을 설정하고, 재시도 제한을 정의하고, 처리되지 않은 이벤트의 최대 보존 시간을 설정할 수 있습니다.

Lambda와 함께 EventBridge Scheduler를 설정하는 경우 EventBridge Scheduler는 Lambda 함수를 비동기적으로 호출합니다. 이 페이지에서는 EventBridge 스케줄러를 사용하여 일정에 따라 Lambda 함수를 간접적으로 호출하는 방법을 설명합니다.

## 실행 역할 설정
<a name="using-eventbridge-scheduler-execution-role"></a>

 새 일정을 생성할 때 EventBridge 스케줄러에 사용자를 대신하여 대상 API 작업을 간접적으로 호출할 수 있는 권한이 있어야 합니다. **실행 역할을 사용하여 EventBridge 스케줄러에 이러한 권한을 부여합니다. 일정의 실행 역할에 연결하는 권한 정책은 필요한 권한을 정의합니다. 이러한 권한은 EventBridge 스케줄러가 간접적으로 호출하려는 대상 API에 따라 달라집니다.

 다음 절차와 같이 EventBridge 스케줄러 콘솔을 사용하여 일정을 생성하면 EventBridge 스케줄러가 선택한 대상을 기준으로 실행 역할을 자동으로 설정합니다. EventBridge 스케줄러 SDK, AWS CLI 또는 CloudFormation 중 하나를 사용하여 일정을 생성하려면 EventBridge 스케줄러가 대상을 간접적으로 호출하는 데 필요한 권한을 부여하는 기존 실행 역할이 있어야 합니다. 일정에 대한 실행 역할을 수동으로 설정하는 방법에 대한 자세한 내용은 **EventBridge 스케줄러 사용 설명서의 [Setting up an execution role](https://docs.aws.amazon.com/scheduler/latest/UserGuide/setting-up.html#setting-up-execution-role)을 참조하세요.

## 일정 생성
<a name="using-eventbridge-scheduler-create"></a>

**콘솔을 사용하여 일정 생성**

1. [https://console.aws.amazon.com/scheduler/home](https://console.aws.amazon.com/scheduler/home/)에서 Amazon EventBridge 스케줄러 콘솔을 엽니다.

1.  **일정** 페이지에서 **일정 생성**을 선택합니다.

1.  **일정 세부 정보 지정** 페이지의 **일정 이름 및 설명** 섹션에서 다음을 수행합니다.

   1. **일정 이름**에 일정의 이름을 입력합니다. 예: **MyTestSchedule**.

   1. (선택 사항) **설명**에 일정에 대한 설명을 입력합니다. 예: **My first schedule**.

   1. **일정 그룹** 드롭다운 목록에서 일정 그룹을 선택합니다. 그룹이 없는 경우 **기본값**을 선택합니다. 일정 그룹을 생성하려면 **자체 일정 생성**을 선택합니다.

      일정 그룹을 사용하여 일정 그룹에 태그를 추가합니다.

1. 

   1. 일정 옵션을 선택합니다.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-eventbridge-scheduler.html)

1. (선택 사항) 이전 단계에서 **반복 일정**을 선택한 경우 **기간** 섹션에서 다음을 수행합니다.

   1. **시간대**에서 시간대를 선택합니다.

   1. **시작 날짜 및 시간**에 `YYYY/MM/DD` 형식으로 유효한 날짜를 입력한 다음 24시간 `hh:mm` 형식으로 타임스탬프를 지정합니다.

   1. **종료 날짜 및 시간**에 `YYYY/MM/DD` 형식으로 유효한 날짜를 입력한 다음 24시간 `hh:mm` 형식으로 타임스탬프를 지정합니다.

1. **Next**(다음)를 선택합니다.

1. **대상 선택** 페이지에서 EventBridge 스케줄러가 간접적으로 호출하는 AWS API 작업을 선택합니다.

   1. **AWS Lambda Invoke**를 선택합니다.

   1. **간접 호출** 섹션에서 함수를 선택하거나 **새 Lambda 함수 생성**을 선택합니다.

   1. (선택 사항) JSON 페이로드를 입력합니다. 페이로드를 입력하지 않으면 EventBridge 스케줄러는 빈 이벤트를 사용하여 함수를 간접적으로 호출합니다.

1. **Next**(다음)를 선택합니다.

1. **설정** 페이지에서 다음 작업을 수행합니다.

   1. 일정을 켜려면 **일정 상태**에서 **일정 활성화**를 토글합니다.

   1. 일정에 대한 재시도 정책을 구성하려면 **재시도 정책 및 데드-레터 큐(DLQ)**에서 다음을 수행합니다.
      + **재시도**를 토글합니다.
      + **최대 이벤트 수명**에 EventBridge 스케줄러가 처리되지 않은 이벤트를 보관해야 하는 최대 **시간**과 **분**을 입력합니다.
      + 최대 시간은 24시간입니다.
      + **최대 재시도 횟수**에는 대상이 오류를 반환할 경우 EventBridge 스케줄러가 일정을 재시도하는 최대 횟수를 입력합니다.

         최댓값은 185회입니다.

      재시도 정책을 사용하면 일정이 대상을 간접적으로 호출하지 못할 경우 EventBridge 스케줄러가 일정을 다시 실행합니다. 구성된 경우 일정에 대한 최대 보존 기간과 재시도 횟수를 설정해야 합니다.

   1. EventBridge 스케줄러가 전송되지 않은 이벤트를 저장하는 위치를 선택합니다.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-eventbridge-scheduler.html)

   1. 고객 관리형 키를 사용하여 대상 입력을 암호화하려면 **암호화**에서 **암호화 설정 사용자 지정(고급)**을 선택합니다.

      이 옵션을 선택하는 경우 기존 KMS 키 ARN을 입력하거나 **AWS KMS key 생성**을 선택하여 AWS KMS 콘솔로 이동합니다. EventBridge 스케줄러가 저장 데이터를 암호화하는 방법에 대한 자세한 내용은 **Amazon EventBridge 스케줄러 사용 설명서의 [Encryption at rest](https://docs.aws.amazon.com/scheduler/latest/UserGuide/encryption-rest.html)를 참조하세요.

   1. EventBridge 스케줄러가 새 실행 역할을 생성하도록 하려면 **이 일정에 대한 새 역할 생성**을 선택합니다. 그런 다음 **역할 이름**을 입력합니다. 이 옵션을 선택하면 EventBridge 스케줄러가 템플릿 대상에 필요한 필수 권한을 역할에 연결합니다.

1. **Next**(다음)를 선택합니다.

1.  **일정 검토 및 생성** 페이지에서 일정의 세부 정보를 검토합니다. 각 섹션에서 **편집**을 선택하여 해당 단계로 돌아가서 세부 정보를 편집합니다.

1. **일정 생성**을 선택합니다.

   **일정** 페이지에서 새 일정과 기존 일정 목록을 볼 수 있습니다. **상태** 열에서 새 일정이 **활성화됨** 상태인지 확인합니다.

EventBridge 스케줄러가 함수를 간접적으로 호출했는지 확인하려면 [함수의 Amazon CloudWatch 로그를 확인](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-console)합니다.

## 관련 리소스
<a name="using-eventbridge-scheduler-related-resources"></a>

 EventBridge 스케줄러에 대한 자세한 내용은 다음을 참조하세요.
+ [EventBridge 스케줄러 사용 설명서](https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html)
+ [EventBridge 스케줄러 API 참조](https://docs.aws.amazon.com/scheduler/latest/APIReference/Welcome.html)
+ [EventBridge 스케줄러 요금](https://aws.amazon.com/eventbridge/pricing/#Scheduler)

# AWS Lambda와 함께 AWS IoT 사용
<a name="services-iot"></a>

AWS IoT는 인터넷에 연결된 디바이스(예: 센서)와 AWS 클라우드 간의 안전한 통신을 제공합니다. 이를 통해 여러 디바이스에서 원격 측정 데이터를 수집하고, 저장하고, 분석할 수 있습니다.

디바이스에 대해 AWS 서비스와 상호 작용하는 AWS IoT 규칙을 생성할 수 있습니다. AWS IoT [규칙 엔진](https://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html)은 SQL 기반 언어를 사용하여 메시지 페이로드에서 데이터를 선택하고, Amazon S3, Amazon DynamoDB, AWS Lambda 등의 다른 서비스로 데이터를 전송할 수 있습니다. 다른 AWS 서비스 또는 서드 파티 서비스를 간접 호출할 경우에는 Lambda 함수를 간접 호출하는 규칙을 정의합니다.

들어오는 IoT 메시지가 규칙을 트리거하면 AWS IoT는 Lambda 함수를 [비동기적으로](invocation-async.md) 간접 호출하고 IoT 메시지의 데이터를 함수로 전달합니다.

다음 예는 온실 센서의 수분 수치를 보여줍니다. **행** 및 **pos** 값으로 센서의 위치를 식별합니다. 이 예제 이벤트는 [AWS IoT 규칙 자습서](https://docs.aws.amazon.com/iot/latest/developerguide/iot-rules-tutorial.html)의 온실 유형을 기반으로 합니다.

**Example AWS IoT 메시지 이벤트**  

```
{
    "row" : "10",
    "pos" : "23",
    "moisture" : "75"
}
```

비동기 호출의 경우 함수에서 오류를 반환할 때 Lambda에서 메시지를 대기열에 배치하고 [재시도](invocation-retries.md)합니다. 함수에서 처리하지 못한 이벤트를 유지할 [대상](invocation-async-retain-records.md#invocation-async-destinations)과 함께 함수를 구성합니다.

Lambda 함수를 간접 호출하려면 AWS IoT 서비스에 대한 권한을 부여해야 합니다. `add-permission` 명령을 사용하여 권한 설명문을 함수의 리소스 기반 정책에 추가하세요.

```
aws lambda add-permission --function-name my-function \
--statement-id iot-events --action "lambda:InvokeFunction" --principal iot.amazonaws.com
```

다음 결과가 표시됩니다:

```
{
    "Statement": "{\"Sid\":\"iot-events\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"iot.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-east-1:123456789012:function:my-function\"}"
}
```

AWS IoT에서 Lambda를 사용하는 방법에 관한 자세한 내용은 [AWS Lambda 규칙 생성](https://docs.aws.amazon.com/iot/latest/developerguide/iot-lambda-rule.html)을 참조하세요.

# Lambda를 사용해 Amazon Kinesis Data Streams의 레코드를 처리
<a name="with-kinesis"></a>

Lambda 함수를 사용하여 [Amazon Kinesis 데이터 스트림](https://docs.aws.amazon.com/streams/latest/dev/introduction.html)의 레코드를 처리할 수 있습니다. Lambda 함수를 Kinesis Data Streams 공유 처리량 소비자(표준 반복기)에 매핑하거나 [향상된 팬 아웃](https://docs.aws.amazon.com/kinesis/latest/dev/enhanced-consumers.html) 기능이 있는 전용 처리량 소비자에 매핑할 수 있습니다. 표준 반복기의 경우 Lambda는 HTTP 프로토콜을 사용하여 Kinesis 스트림의 각 샤드를 폴링합니다. 이벤트 소스 매핑은 샤드의 다른 소비자와 읽기 처리량을 공유합니다.

 Kinesis 데이터 스트림에 대한 자세한 내용은 [Amazon Kinesis Data Streams에서 데이터 읽기](https://docs.aws.amazon.com/kinesis/latest/dev/building-consumers.html)를 참조하세요.

**참고**  
Kinesis는 각 샤드에 대해 요금을 부과하고 향상된 팬아웃의 경우 스트림에서 읽은 데이터에 대해 요금을 부과합니다. 요금 세부 정보는 [Amazon Kinesis 요금](https://aws.amazon.com/kinesis/data-streams/pricing)을 참조하세요.

## 폴링 및 배치 처리 스트림
<a name="kinesis-polling-and-batching"></a>

Lambda는 데이터 스트림에서 레코드를 읽고 스트림 레코드를 포함한 이벤트와 [동기적으로](invocation-sync.md) 함수를 간접 호출합니다. Lambda는 배치의 레코드를 읽고 함수를 간접 호출하여 배치의 레코드를 처리합니다. 각 배치에는 단일 샤드/데이터 스트림의 레코드가 포함됩니다.

Lambda 함수는 데이터 스트림의 소비자 애플리케이션입니다. 이 함수는 각 샤드에서 한 번에 한 개의 레코드 배치를 처리합니다. Lambda 함수를 공유 처리량 소비자(표준 반복기)에 매핑하거나 향상된 팬 아웃 기능이 있는 전용 처리량 소비자에 매핑할 수 있습니다.
+ **표준 반복자:** Lambda는 초당 1회의 속도로 Kinesis 스트림의 각 샤드에서 레코드를 폴링합니다. 더 많은 레코드를 사용할 수 있는 경우 Lambda는 함수가 스트림을 따라잡을 때까지 배치 처리를 유지합니다. 이벤트 소스 매핑은 샤드의 다른 소비자와 읽기 처리량을 공유합니다.
+ **향상된 팬아웃:** 지연 시간을 최소화하고 읽기 처리량을 최대화하려면 [향상된 팬아웃](https://docs.aws.amazon.com/streams/latest/dev/enhanced-consumers.html)으로 데이터 스트림 소비자를 생성하세요. 향상된 팬아웃 소비자는 각 샤드에 대해 전용 연결을 설정하므로 스트림에서 읽는 다른 애플리케이션에 영향을 주지 않습니다. 스트림 소비자는 HTTP/2를 사용하여 수명이 긴 연결을 통해 레코드를 Lambda에 푸시하고 요청 헤더를 압축함으로써 지연 시간을 최소화합니다. Kinesis [RegisterStreamConsumer](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_RegisterStreamConsumer.html) API를 사용하여 스트림 소비자를 생성할 수 있습니다.

```
aws kinesis register-stream-consumer \
--consumer-name con1 \
--stream-arn arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream
```

다음 결과가 표시됩니다:

```
{
    "Consumer": {
        "ConsumerName": "con1",
        "ConsumerARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream/consumer/con1:1540591608",
        "ConsumerStatus": "CREATING",
        "ConsumerCreationTimestamp": 1540591608.0
    }
}
```

함수가 레코드를 처리하는 속도를 높이려면 [데이터 스트림에 샤드를 추가](https://repost.aws/knowledge-center/kinesis-data-streams-open-shards)합니다. Lambda는 각 샤드의 레코드를 순서대로 처리합니다. 함수가 오류를 반환하면 샤드는 추가 레코드 처리를 중지합니다. 샤드가 많을수록 한 번에 더 많은 배치가 처리되므로 동시 실행에 대한 오류의 영향이 줄어듭니다.

함수가 총 동시 배치 수를 처리하기 위해 확장할 수 없는 경우 함수에 대한 [할당량 증가를 요청](https://docs.aws.amazon.com/servicequotas/latest/userguide/request-quota-increase.html)하거나 [동시성을 예약](configuration-concurrency.md)합니다.

기본적으로, Lambda는 레코드가 사용 가능하게 되는 즉시 함수를 간접 호출합니다. Lambda가 이벤트 소스에서 읽는 배치에 하나의 레코드만 있는 경우, Lambda는 함수에 하나의 레코드만 전송합니다. 소수의 레코드로 함수를 호출하는 것을 피하려면 *일괄 처리 기간*을 구성하여 이벤트 소스가 최대 5분 동안 레코드를 버퍼링하도록 지정할 수 있습니다. 함수를 호출하기 전에 Lambda는 전체 배치가 수집되거나, 일괄 처리 기간이 만료되거나, 배치가 페이로드 한도인 6MB에 도달할 때까지 이벤트 소스에서 레코드를 계속 읽습니다. 자세한 내용은 [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching) 섹션을 참조하세요.

**주의**  
Lambda 이벤트 소스 매핑은 각 이벤트를 한 번 이상 처리하므로 레코드가 중복될 수 있습니다. 중복 이벤트와 관련된 잠재적 문제를 방지하려면 함수 코드를 멱등성으로 만드는 것이 좋습니다. 자세한 내용은 AWS 지식 센터의 [함수를 멱등성 Lambda 함수로 만들려면 어떻게 해야 하나요?](https://repost.aws/knowledge-center/lambda-function-idempotent)를 참조하세요.

Lambda는 처리를 위해 다음 배치를 전송하기 전에 구성된 [확장](lambda-extensions.md)이 완료될 때까지 기다리지 않습니다. 즉, Lambda가 다음 레코드 배치를 처리할 때 확장이 계속 실행될 수 있습니다. 이로 인해 계정의 [동시성](lambda-concurrency.md) 설정 또는 스로틀링을 위반하는 경우 제한 문제가 발생할 수 있습니다. 이것이 잠재적인 문제인지 여부를 탐지하려면 함수를 모니터링하고 이벤트 소스 매핑에 대해 예상보다 높은 [동시성 지표](monitoring-concurrency.md#general-concurrency-metrics)가 표시되는지 확인하세요. 간접 호출 간격이 짧기 때문에 Lambda는 일시적으로 동시성 사용량을 샤드 수보다 더 높게 보고할 수 있습니다. 확장이 없는 Lambda 함수에서도 마찬가지입니다.

Kinesis 데이터 스트림의 한 샤드와 하나 이상의 Lambda 간접 호출을 동시에 처리하도록 [ParallelizationFactor](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-ParallelizationFactor) 설정을 구성합니다. Lambda가 병렬화 계수를 통해 샤드에서 폴링하는 동시 배치의 수는 1(기본값)부터 10까지 지정할 수 있습니다. 예를 들어 `ParallelizationFactor`(을)를 2로 설정하는 경우 최대 100개의 Kinesis 데이터 샤드를 처리하기 위한 200번의 동시 Lambda 간접 호출을 보유할 수 있습니다(실제 `ConcurrentExecutions` 지표의 값은 다를 수 있음). 이는 데이터 볼륨이 일시적이고 `IteratorAge`가 높을 때 처리량을 확장하는 데 도움을 줍니다. 샤드당 동시 배치 수를 높여도 Lambda는 파티션-키 수준에서의 순차 처리를 계속 보장합니다.

Kinesis 집계와 함께 `ParallelizationFactor`를 사용할 수도 있습니다. 이벤트 소스 매핑의 동작은 [향상된 팬아웃](https://docs.aws.amazon.com/streams/latest/dev/enhanced-consumers.html)을 사용하는지 여부에 따라 달라집니다.
+ **향상된 팬아웃 사용 안 함**: 집계된 이벤트 내의 모든 이벤트는 동일한 파티션 키를 가져야 합니다. 파티션 키도 집계된 이벤트의 파티션 키와 일치해야 합니다. 집계된 이벤트 내의 이벤트가 다른 파티션 키를 가지는 경우 Lambda는 파티션 키를 기준으로 이벤트를 순서대로 처리한다고 보장할 수 없습니다.
+ **향상된 팬아웃 사용**: 먼저 Lambda는 집계된 이벤트를 개별 이벤트로 디코딩합니다. 집계된 이벤트는 포함된 이벤트와 다른 파티션 키를 가질 수 있습니다. 하지만 파티션 키가 일치하지 않는 이벤트는 [삭제되고 손실됩니다](https://github.com/awslabs/kinesis-aggregation/blob/master/potential_data_loss.md). Lambda는 이러한 이벤트를 처리하지 않으며 구성된 장애 대상으로 전송하지도 않습니다.

## 예제 이벤트
<a name="services-kinesis-event-example"></a>

**Example**  

```
{
    "Records": [
        {
            "kinesis": {
                "kinesisSchemaVersion": "1.0",
                "partitionKey": "1",
                "sequenceNumber": "49590338271490256608559692538361571095921575989136588898",
                "data": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
                "approximateArrivalTimestamp": 1545084650.987
            },
            "eventSource": "aws:kinesis",
            "eventVersion": "1.0",
            "eventID": "shardId-000000000006:49590338271490256608559692538361571095921575989136588898",
            "eventName": "aws:kinesis:record",
            "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-role",
            "awsRegion": "us-east-2",
            "eventSourceARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream"
        },
        {
            "kinesis": {
                "kinesisSchemaVersion": "1.0",
                "partitionKey": "1",
                "sequenceNumber": "49590338271490256608559692540925702759324208523137515618",
                "data": "VGhpcyBpcyBvbmx5IGEgdGVzdC4=",
                "approximateArrivalTimestamp": 1545084711.166
            },
            "eventSource": "aws:kinesis",
            "eventVersion": "1.0",
            "eventID": "shardId-000000000006:49590338271490256608559692540925702759324208523137515618",
            "eventName": "aws:kinesis:record",
            "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-role",
            "awsRegion": "us-east-2",
            "eventSourceARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream"
        }
    ]
}
```

# Lambda로 Amazon Kinesis Data Streams 레코드 처리
<a name="services-kinesis-create"></a>

Lambda로 Amazon Kinesis Data Streams 레코드를 처리하려면 Lambda 이벤트 소스 매핑을 생성합니다. Lambda 함수를 표준 반복자나 향상된 팬아웃 소비자에게 매핑할 수 있습니다. 자세한 내용은 [폴링 및 배치 처리 스트림](with-kinesis.md#kinesis-polling-and-batching) 섹션을 참조하세요.

## Kinesis 이벤트 소스 매핑 생성
<a name="services-kinesis-eventsourcemapping"></a>

데이터 스트림의 레코드와 함께 Lambda 함수를 간접 호출하려면 [이벤트 소스 매핑](invocation-eventsourcemapping.md)을 생성합니다. 여러 이벤트 소스 매핑을 생성하여 여러 Lambda 함수로 동일한 데이터를 처리하거나, 단일 함수로 여러 데이터 스트림의 항목을 처리할 수 있습니다. 여러 스트림에서 항목을 처리할 때 각 배치에는 단일 샤드 또는 스트림의 레코드만 포함됩니다.

다른 AWS 계정에서 스트림의 레코드를 처리하도록 이벤트 소스 매핑을 구성할 수 있습니다. 자세한 내용은 [계정 간 이벤트 소스 매핑 생성](#services-kinesis-eventsourcemapping-cross-account)를 참조하세요.

이벤트 소스 매핑을 생성하기 전에 Kinesis 데이터 스트림에서 읽을 수 있는 권한을 Lambda 함수에 부여해야 합니다. Lambda는 Kinesis 데이터 스트림 관련 리소스를 관리하기 위해 다음 권한이 필요합니다.
+ [kinesis:DescribeStream](https://docs.aws.amazon.com/lambda/latest/api/API_DescribeStream.html)
+ [kinesis:DescribeStreamSummary](https://docs.aws.amazon.com/lambda/latest/api/API_DescribeStreamSummary.html)
+ [kinesis:GetRecords](https://docs.aws.amazon.com/lambda/latest/api/API_GetRecords.html)
+ [kinesis:GetShardIterator](https://docs.aws.amazon.com/lambda/latest/api/API_GetShardIterator.html)
+ [kinesis:ListShards](https://docs.aws.amazon.com/lambda/latest/api/API_ListShards.html)
+ [kinesis:SubscribeToShard](https://docs.aws.amazon.com/lambda/latest/api/API_SubscribeToShard.html)

AWS 관리형 정책 [AWSLambdaKinesisExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaKinesisExecutionRole.html)에는 다음 권한이 포함됩니다. 다음 절차의 설명에 따라 함수에 해당 관리형 정책을 추가합니다.

**참고**  
Kinesis에 대한 이벤트 소스 매핑을 생성하고 관리하는 데 `kinesis:ListStreams` 권한이 필요하지 않습니다. 그러나 이 권한이 없는 경우 콘솔에서 이벤트 소스 매핑을 생성하면 드롭다운 목록에서 Kinesis 스트림을 선택할 수 없으며 콘솔에 오류가 표시됩니다. 이벤트 소스 매핑을 생성하려면 스트림의 Amazon 리소스 이름(ARN)을 수동으로 입력해야 합니다.
Lambda는 실패한 호출을 다시 시도할 때 `kinesis:GetRecords` 및 `kinesis:GetShardIterator` API 호출을 수행합니다.

------
#### [ AWS Management Console ]

**함수에 Kinesis 권한을 추가**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 열고 함수를 선택합니다.

1. **구성** 탭을 선택한 다음 **사용 권한**을 선택합니다.

1. **실행 역할** 창의 **역할 이름**에서 함수의 실행 역할 링크를 선택합니다. 이 링크를 클릭하면 IAM 콘솔에서의 해당 역할 페이지가 열립니다.

1. **권한 정책** 창에서 **권한 추가**를 선택한 다음 **정책 연결**을 선택합니다.

1. 검색 필드에 **AWSLambdaKinesisExecutionRole**를 입력합니다.

1. 정책 옆의 확인란을 선택하고 **권한 추가**를 선택합니다.

------
#### [ AWS CLI ]

**함수에 Kinesis 권한을 추가**
+ 함수의 실행 역할에 `AWSLambdaKinesisExecutionRole` 정책을 연결하려면 다음 CLI 명령을 실행합니다.

  ```
  aws iam attach-role-policy \
  --role-name MyFunctionRole \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaKinesisExecutionRole
  ```

------
#### [ AWS SAM ]

**함수에 Kinesis 권한을 추가**
+ 함수 정의에서 다음 예제처럼 `Policies` 속성을 추가합니다.

  ```
  Resources:
    MyFunction:
      Type: AWS::Serverless::Function
      Properties:
        CodeUri: ./my-function/
        Handler: index.handler
        Runtime: nodejs24.x
        Policies:
          - AWSLambdaKinesisExecutionRole
  ```

------

필요한 권한을 구성한 후 이벤트 소스 매핑을 생성합니다.

------
#### [ AWS Management Console ]

**Kinesis 이벤트 소스 매핑 생성**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 열고 함수를 선택합니다.

1. **함수 개요** 창에서 **트리거 추가**를 선택합니다.

1. **트리거 구성**에서 소스로 **Kinesis**를 선택합니다.

1. 이벤트 소스 매핑을 생성할 Kinesis 스트림과 필요에 따라 스트림 소비자를 선택합니다.

1. (선택 사항)이벤트 소스 매핑에 대해 **배치 크기**, **시작 위치** 및 **배치 창을** 편집합니다.

1. **추가**를 선택합니다.

콘솔에서 이벤트 소스 매핑을 생성하는 경우 IAM 역할에는 [kinesis:ListStreams](https://docs.aws.amazon.com/lambda/latest/api/API_ListStreams.html) 및 [kinesis:ListStreamConsumers](https://docs.aws.amazon.com/lambda/latest/api/API_ListStreamConsumers.html) 권한이 있어야 합니다.

------
#### [ AWS CLI ]

**Kinesis 이벤트 소스 매핑 생성**
+ 다음 CLI 명령을 실행하여 Kinesis 이벤트 소스 매핑을 생성합니다. 사용 사례에 따라 배치 크기와 시작 위치를 직접 선택합니다.

  ```
  aws lambda create-event-source-mapping \
  --function-name MyFunction \
  --event-source-arn arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream \
  --starting-position LATEST \
  --batch-size 100
  ```

배치 기간을 지정하려면 `--maximum-batching-window-in-seconds` 옵션을 추가합니다. 이 파라미터와 다른 파라미터에 대한 자세한 내용은 *AWS CLI 명령 참조*의 [create-event-source mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html)을 참조하세요.

------
#### [ AWS SAM ]

**Kinesis 이벤트 소스 매핑 생성**
+ 함수 정의에서 다음 예제처럼 `KinesisEvent` 속성을 추가합니다.

  ```
  Resources:
    MyFunction:
      Type: AWS::Serverless::Function
      Properties:
        CodeUri: ./my-function/
        Handler: index.handler
        Runtime: nodejs24.x
        Policies:
          - AWSLambdaKinesisExecutionRole
        Events:
          KinesisEvent:
            Type: Kinesis
            Properties:
              Stream: !GetAtt MyKinesisStream.Arn
              StartingPosition: LATEST
              BatchSize: 100
  
    MyKinesisStream:
      Type: AWS::Kinesis::Stream
      Properties:
        ShardCount: 1
  ```

AWS SAM에서 Kinesis Data Streams의 이벤트 소스 매핑을 생성하는 방법에 대해 자세히 알아보려면 **AWS Serverless Application Model 개발자 안내서의 [Kinesis](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-kinesis.html)를 참조하세요.

------

## 폴링 및 스트리밍 시작 위치
<a name="services-kinesis-stream-start-pos"></a>

이벤트 소스 매핑 생성 및 업데이트 중 스트림 폴링은 최종적으로 일관됩니다.
+ 이벤트 소스 매핑 생성 중 스트림에서 이벤트 폴링을 시작하는 데 몇 분 정도 걸릴 수 있습니다.
+ 이벤트 소스 매핑 업데이트 중 스트림에서 이벤트 폴링을 중지했다가 다시 시작하는 데 몇 분 정도 걸릴 수 있습니다.

이 동작은 스트림의 시작 위치로 `LATEST`를 지정하면 이벤트 소스 매핑이 생성 또는 업데이트 중에 이벤트를 놓칠 수 있음을 의미합니다. 누락된 이벤트가 없도록 하기 위해서는 스트림 시작 위치를 `TRIM_HORIZON` 또는 `AT_TIMESTAMP`로 지정하세요.

## 계정 간 이벤트 소스 매핑 생성
<a name="services-kinesis-eventsourcemapping-cross-account"></a>

Amazon Kinesis Data Streams는 [리소스 기반 정책](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html)을 지원합니다. 따라서 다른 계정의 Lambda 함수를 사용하여 스트림으로 수집된 데이터를 하나의 AWS 계정에서 처리할 수 있습니다.

다른 AWS 계정에서 Kinesis 스트림을 사용하여 Lambda 함수에 대한 이벤트 소스 매핑을 생성하려면 리소스 기반 정책을 사용하여 스트림을 구성해서 Lambda 함수에 항목 읽기 권한을 부여합니다. 교차 계정 액세스를 허용하도록 스트림을 구성하는 방법을 알아보려면 Amazon Kinesis Streams 개발자 안내서의 [교차 계정 AWS Lambda 함수를 통한 액세스 공유](https://docs.aws.amazon.com/streams/latest/dev/resource-based-policy-examples.html#Resource-based-policy-examples-lambda)를 참조하세요.

Lambda 함수에 필요한 권한을 부여하는 리소스 기반 정책으로 스트림을 구성하고 나면 이전 섹션에서 설명한 방법 중 하나를 사용하여 이벤트 소스 매핑을 생성합니다.

Lambda 콘솔을 사용하여 이벤트 소스 매핑을 생성하기로 선택한 경우 스트림의 ARN을 입력 필드에 직접 붙여넣기합니다. 스트림의 소비자를 지정하려는 경우 소비자의 ARN을 붙여넣기하면 스트림 필드가 자동으로 채워집니다.

# Kinesis Data Streams 및 Lambda로 부분 배치 응답 구성
<a name="services-kinesis-batchfailurereporting"></a>

이벤트 소스에서 스트리밍 데이터를 사용하고 처리할 때 기본적으로 Lambda는 배치가 완전히 성공한 경우에만 배치의 가장 높은 시퀀스 번호로 체크포인트를 수행합니다. Lambda는 다른 모든 결과를 완전한 실패로 처리하고 재시도 제한까지 배치 처리를 재시도합니다. 스트림에서 배치를 처리하는 동안 부분적인 성공을 허용하려면 `ReportBatchItemFailures`를 설정합니다. 부분적인 성공을 허용하면 레코드에 대한 재시도 횟수를 줄이는 데 도움이 되지만 성공한 레코드의 재시도 가능성을 완전히 막지는 못합니다.

`ReportBatchItemFailures`를 켜려면 [FunctionResponseTypes](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-FunctionResponseTypes) 목록에 열거형 값 **ReportBatchItemFailures**를 포함시킵니다. 이 목록은 함수에 대해 활성화된 응답 유형을 나타냅니다. 이벤트 소스 매핑을 [생성](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html)하거나 [업데이트](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html)할 때 이 목록을 구성할 수 있습니다.

**참고**  
함수 코드가 부분 배치 실패 응답을 반환하더라도 이벤트 소스 매핑에 대해 `ReportBatchItemFailures` 기능이 명시적으로 활성화되지 않으면 Lambda가 해당 응답을 처리하지 않습니다.

## 보고서 구문
<a name="streams-batchfailurereporting-syntax"></a>

배치 항목 실패에 대한 보고를 구성할 때 `StreamsEventResponse` 클래스는 배치 항목 실패 목록과 함께 반환됩니다. `StreamsEventResponse` 객체를 사용하여 배치에서 첫 번째 실패한 레코드의 시퀀스 번호를 반환할 수 있습니다. 올바른 응답 구문을 사용하여 고유한 사용자 지정 클래스를 생성할 수도 있습니다. 다음 JSON 구조는 필요한 응답 구문을 보여줍니다.

```
{ 
  "batchItemFailures": [ 
        {
            "itemIdentifier": "<SequenceNumber>"
        }
    ]
}
```

**참고**  
`batchItemFailures` 어레이에 여러 항목이 포함되어 있으면 Lambda는 시퀀스 번호가 가장 낮은 레코드를 체크포인트로 사용합니다. 그런 다음 Lambda는 해당 체크포인트에서 시작하여 모든 레코드를 다시 시도합니다.

## 성공 및 실패 조건
<a name="streams-batchfailurereporting-conditions"></a>

Lambda는 다음 중 하나를 반환할 경우 배치를 완전한 성공으로 처리합니다.
+ 비어 있는 `batchItemFailure` 목록
+ null `batchItemFailure` 목록
+ 비어 있는 `EventResponse`
+ null `EventResponse`

Lambda는 다음 중 하나를 반환할 경우 배치를 완전한 실패로 처리합니다.
+ 빈 문자열 `itemIdentifier`
+ null `itemIdentifier`
+ 키 이름이 잘못된 `itemIdentifier`

Lambda는 재시도 전략에 따라 실패를 재시도합니다.

## 배치 이등분
<a name="streams-batchfailurereporting-bisect"></a>

호출이 실패하고 `BisectBatchOnFunctionError`가 활성화되어 있으면 `ReportBatchItemFailures` 설정에 관계 없이 배치가 이등분됩니다.

부분적 배치 성공 응답이 수신되고 `BisectBatchOnFunctionError` 및 `ReportBatchItemFailures`가 모두 활성화되면 배치가 반환된 시퀀스 번호에서 이등분되고 Lambda는 나머지 레코드만 재시도합니다.

부분 배치 응답 로직 구현을 간소화하려면 이러한 복잡성을 자동 처리할 수 있는 Powertools for AWS Lambda의 [배치 프로세서 유틸리티](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)를 사용하는 것이 좋습니다.

다음은 일괄적으로 실패한 메시지 ID 목록을 반환하는 함수 코드의 몇 가지 예입니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 Kinesis 배치 항목 실패 보고  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
﻿using System.Text;
using System.Text.Json.Serialization;
using Amazon.Lambda.Core;
using Amazon.Lambda.KinesisEvents;
using AWS.Lambda.Powertools.Logging;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace KinesisIntegration;

public class Function
{
    // Powertools Logger requires an environment variables against your function
    // POWERTOOLS_SERVICE_NAME
    [Logging(LogEvent = true)]
    public async Task<StreamsEventResponse> FunctionHandler(KinesisEvent evnt, ILambdaContext context)
    {
        if (evnt.Records.Count == 0)
        {
            Logger.LogInformation("Empty Kinesis Event received");
            return new StreamsEventResponse();
        }

        foreach (var record in evnt.Records)
        {
            try
            {
                Logger.LogInformation($"Processed Event with EventId: {record.EventId}");
                string data = await GetRecordDataAsync(record.Kinesis, context);
                Logger.LogInformation($"Data: {data}");
                // TODO: Do interesting work based on the new data
            }
            catch (Exception ex)
            {
                Logger.LogError($"An error occurred {ex.Message}");
                /* Since we are working with streams, we can return the failed item immediately.
                   Lambda will immediately begin to retry processing from this failed item onwards. */
                return new StreamsEventResponse
                {
                    BatchItemFailures = new List<StreamsEventResponse.BatchItemFailure>
                    {
                        new StreamsEventResponse.BatchItemFailure { ItemIdentifier = record.Kinesis.SequenceNumber }
                    }
                };
            }
        }
        Logger.LogInformation($"Successfully processed {evnt.Records.Count} records.");
        return new StreamsEventResponse();
    }

    private async Task<string> GetRecordDataAsync(KinesisEvent.Record record, ILambdaContext context)
    {
        byte[] bytes = record.Data.ToArray();
        string data = Encoding.UTF8.GetString(bytes);
        await Task.CompletedTask; //Placeholder for actual async work
        return data;
    }
}

public class StreamsEventResponse
{
    [JsonPropertyName("batchItemFailures")]
    public IList<BatchItemFailure> BatchItemFailures { get; set; }
    public class BatchItemFailure
    {
        [JsonPropertyName("itemIdentifier")]
        public string ItemIdentifier { get; set; }
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 Kinesis 배치 항목 실패를 보고합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"fmt"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(ctx context.Context, kinesisEvent events.KinesisEvent) (map[string]interface{}, error) {
	batchItemFailures := []map[string]interface{}{}

	for _, record := range kinesisEvent.Records {
		curRecordSequenceNumber := ""

		// Process your record
		if /* Your record processing condition here */ {
			curRecordSequenceNumber = record.Kinesis.SequenceNumber
		}

		// Add a condition to check if the record processing failed
		if curRecordSequenceNumber != "" {
			batchItemFailures = append(batchItemFailures, map[string]interface{}{"itemIdentifier": curRecordSequenceNumber})
		}
	}

	kinesisBatchResponse := map[string]interface{}{
		"batchItemFailures": batchItemFailures,
	}
	return kinesisBatchResponse, nil
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda로 Kinesis 배치 항목 실패 보고.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
import com.amazonaws.services.lambda.runtime.events.StreamsEventResponse;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class ProcessKinesisRecords implements RequestHandler<KinesisEvent, StreamsEventResponse> {

    @Override
    public StreamsEventResponse handleRequest(KinesisEvent input, Context context) {

        List<StreamsEventResponse.BatchItemFailure> batchItemFailures = new ArrayList<>();
        String curRecordSequenceNumber = "";

        for (KinesisEvent.KinesisEventRecord kinesisEventRecord : input.getRecords()) {
            try {
                //Process your record
                KinesisEvent.Record kinesisRecord = kinesisEventRecord.getKinesis();
                curRecordSequenceNumber = kinesisRecord.getSequenceNumber();

            } catch (Exception e) {
                /* Since we are working with streams, we can return the failed item immediately.
                   Lambda will immediately begin to retry processing from this failed item onwards. */
                batchItemFailures.add(new StreamsEventResponse.BatchItemFailure(curRecordSequenceNumber));
                return new StreamsEventResponse(batchItemFailures);
            }
        }
       
       return new StreamsEventResponse(batchItemFailures);   
    }
}
```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/blob/main/integration-kinesis-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Javascript를 사용하여 Lambda로 Kinesis 배치 항목 실패 보고  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
  for (const record of event.Records) {
    try {
      console.log(`Processed Kinesis Event - EventID: ${record.eventID}`);
      const recordData = await getRecordDataAsync(record.kinesis);
      console.log(`Record Data: ${recordData}`);
      // TODO: Do interesting work based on the new data
    } catch (err) {
      console.error(`An error occurred ${err}`);
      /* Since we are working with streams, we can return the failed item immediately.
            Lambda will immediately begin to retry processing from this failed item onwards. */
      return {
        batchItemFailures: [{ itemIdentifier: record.kinesis.sequenceNumber }],
      };
    }
  }
  console.log(`Successfully processed ${event.Records.length} records.`);
  return { batchItemFailures: [] };
};

async function getRecordDataAsync(payload) {
  var data = Buffer.from(payload.data, "base64").toString("utf-8");
  await Promise.resolve(1); //Placeholder for actual async work
  return data;
}
```
TypeScript를 사용하여 Lambda로 Kinesis 배치 항목 실패 보고  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import {
  KinesisStreamEvent,
  Context,
  KinesisStreamHandler,
  KinesisStreamRecordPayload,
  KinesisStreamBatchResponse,
} from "aws-lambda";
import { Buffer } from "buffer";
import { Logger } from "@aws-lambda-powertools/logger";

const logger = new Logger({
  logLevel: "INFO",
  serviceName: "kinesis-stream-handler-sample",
});

export const functionHandler: KinesisStreamHandler = async (
  event: KinesisStreamEvent,
  context: Context
): Promise<KinesisStreamBatchResponse> => {
  for (const record of event.Records) {
    try {
      logger.info(`Processed Kinesis Event - EventID: ${record.eventID}`);
      const recordData = await getRecordDataAsync(record.kinesis);
      logger.info(`Record Data: ${recordData}`);
      // TODO: Do interesting work based on the new data
    } catch (err) {
      logger.error(`An error occurred ${err}`);
      /* Since we are working with streams, we can return the failed item immediately.
            Lambda will immediately begin to retry processing from this failed item onwards. */
      return {
        batchItemFailures: [{ itemIdentifier: record.kinesis.sequenceNumber }],
      };
    }
  }
  logger.info(`Successfully processed ${event.Records.length} records.`);
  return { batchItemFailures: [] };
};

async function getRecordDataAsync(
  payload: KinesisStreamRecordPayload
): Promise<string> {
  var data = Buffer.from(payload.data, "base64").toString("utf-8");
  await Promise.resolve(1); //Placeholder for actual async work
  return data;
}
```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 Kinesis 배치 항목 실패를 보고합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\Kinesis\KinesisEvent;
use Bref\Event\Handler as StdHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler implements StdHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handle(mixed $event, Context $context): array
    {
        $kinesisEvent = new KinesisEvent($event);
        $this->logger->info("Processing records");
        $records = $kinesisEvent->getRecords();

        $failedRecords = [];
        foreach ($records as $record) {
            try {
                $data = $record->getData();
                $this->logger->info(json_encode($data));
                // TODO: Do interesting work based on the new data
            } catch (Exception $e) {
                $this->logger->error($e->getMessage());
                // failed processing the record
                $failedRecords[] = $record->getSequenceNumber();
            }
        }
        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords records");

        // change format for the response
        $failures = array_map(
            fn(string $sequenceNumber) => ['itemIdentifier' => $sequenceNumber],
            $failedRecords
        );

        return [
            'batchItemFailures' => $failures
        ];
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 Kinesis 배치 항목 실패 보고.  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def handler(event, context):
    records = event.get("Records")
    curRecordSequenceNumber = ""
    
    for record in records:
        try:
            # Process your record
            curRecordSequenceNumber = record["kinesis"]["sequenceNumber"]
        except Exception as e:
            # Return failed record's sequence number
            return {"batchItemFailures":[{"itemIdentifier": curRecordSequenceNumber}]}

    return {"batchItemFailures":[]}
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 Kinesis 배치 항목 실패를 보고합니다.  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
require 'aws-sdk'

def lambda_handler(event:, context:)
  batch_item_failures = []

  event['Records'].each do |record|
    begin
      puts "Processed Kinesis Event - EventID: #{record['eventID']}"
      record_data = get_record_data_async(record['kinesis'])
      puts "Record Data: #{record_data}"
      # TODO: Do interesting work based on the new data
    rescue StandardError => err
      puts "An error occurred #{err}"
      # Since we are working with streams, we can return the failed item immediately.
      # Lambda will immediately begin to retry processing from this failed item onwards.
      return { batchItemFailures: [{ itemIdentifier: record['kinesis']['sequenceNumber'] }] }
    end
  end

  puts "Successfully processed #{event['Records'].length} records."
  { batchItemFailures: batch_item_failures }
end

def get_record_data_async(payload)
  data = Base64.decode64(payload['data']).force_encoding('utf-8')
  # Placeholder for actual async work
  sleep(1)
  data
end
```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 Kinesis 배치 항목 실패를 보고합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use aws_lambda_events::{
    event::kinesis::KinesisEvent,
    kinesis::KinesisEventRecord,
    streams::{KinesisBatchItemFailure, KinesisEventResponse},
};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};

async fn function_handler(event: LambdaEvent<KinesisEvent>) -> Result<KinesisEventResponse, Error> {
    let mut response = KinesisEventResponse {
        batch_item_failures: vec![],
    };

    if event.payload.records.is_empty() {
        tracing::info!("No records found. Exiting.");
        return Ok(response);
    }

    for record in &event.payload.records {
        tracing::info!(
            "EventId: {}",
            record.event_id.as_deref().unwrap_or_default()
        );

        let record_processing_result = process_record(record);

        if record_processing_result.is_err() {
            response.batch_item_failures.push(KinesisBatchItemFailure {
                item_identifier: record.kinesis.sequence_number.clone(),
            });
            /* Since we are working with streams, we can return the failed item immediately.
            Lambda will immediately begin to retry processing from this failed item onwards. */
            return Ok(response);
        }
    }

    tracing::info!(
        "Successfully processed {} records",
        event.payload.records.len()
    );

    Ok(response)
}

fn process_record(record: &KinesisEventRecord) -> Result<(), Error> {
    let record_data = std::str::from_utf8(record.kinesis.data.as_slice());

    if let Some(err) = record_data.err() {
        tracing::error!("Error: {}", err);
        return Err(Error::from(err));
    }

    let record_data = record_data.unwrap_or_default();

    // do something interesting with the data
    tracing::info!("Data: {}", record_data);

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        // disable printing the name of the module in every log line.
        .with_target(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

## Powertools for AWS Lambda 배치 프로세서 사용
<a name="services-kinesis-batchfailurereporting-powertools"></a>

Powertools for AWS Lambda의 배치 프로세서 유틸리티는 부분 배치 응답 로직을 자동으로 처리하여 배치 실패 보고 구현에 따르는 복잡성을 줄입니다. 다음은 배치 프로세서를 사용하는 예제입니다.

**Python**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)를 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 Kinesis Data Streams 스트림 레코드를 처리합니다.  

```
import json
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.batch import BatchProcessor, EventType, process_partial_response
from aws_lambda_powertools.utilities.data_classes import KinesisEvent
from aws_lambda_powertools.utilities.typing import LambdaContext

processor = BatchProcessor(event_type=EventType.KinesisDataStreams)
logger = Logger()

def record_handler(record):
    logger.info(record)
    # Your business logic here
    # Raise an exception to mark this record as failed
    
def lambda_handler(event, context: LambdaContext):
    return process_partial_response(
        event=event, 
        record_handler=record_handler, 
        processor=processor,
        context=context
    )
```

**TypeScript**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서](https://docs.aws.amazon.com/powertools/typescript/latest/features/batch/)를 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 Kinesis Data Streams 스트림 레코드를 처리합니다.  

```
import { BatchProcessor, EventType, processPartialResponse } from '@aws-lambda-powertools/batch';
import { Logger } from '@aws-lambda-powertools/logger';
import type { KinesisEvent, Context } from 'aws-lambda';

const processor = new BatchProcessor(EventType.KinesisDataStreams);
const logger = new Logger();

const recordHandler = async (record: any): Promise<void> => {
    logger.info('Processing record', { record });
    // Your business logic here
    // Throw an error to mark this record as failed
};

export const handler = async (event: KinesisEvent, context: Context) => {
    return processPartialResponse(event, recordHandler, processor, {
        context,
    });
};
```

**Java**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서](https://docs.powertools.aws.dev/lambda/java/latest/utilities/batch/)를 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 Kinesis Data Streams 스트림 레코드를 처리합니다.  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
import com.amazonaws.services.lambda.runtime.events.StreamsEventResponse;
import software.amazon.lambda.powertools.batch.BatchMessageHandlerBuilder;
import software.amazon.lambda.powertools.batch.handler.BatchMessageHandler;

public class KinesisStreamBatchHandler implements RequestHandler<KinesisEvent, StreamsEventResponse> {

    private final BatchMessageHandler<KinesisEvent, StreamsEventResponse> handler;

    public KinesisStreamBatchHandler() {
        handler = new BatchMessageHandlerBuilder()
                .withKinesisBatchHandler()
                .buildWithRawMessageHandler(this::processMessage);
    }

    @Override
    public StreamsEventResponse handleRequest(KinesisEvent kinesisEvent, Context context) {
        return handler.processBatch(kinesisEvent, context);
    }

    private void processMessage(KinesisEvent.KinesisEventRecord kinesisEventRecord, Context context) {
        // Process the stream record
    }
}
```

**.NET**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서](https://docs.aws.amazon.com/powertools/dotnet/utilities/batch-processing/)를 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 Kinesis Data Streams 스트림 레코드를 처리합니다.  

```
using System;
using System.Threading;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.Lambda.KinesisEvents;
using Amazon.Lambda.Serialization.SystemTextJson;
using AWS.Lambda.Powertools.BatchProcessing;

[assembly: LambdaSerializer(typeof(DefaultLambdaJsonSerializer))]

namespace HelloWorld;

public class OrderEvent
{
    public string? OrderId { get; set; }
    public string? CustomerId { get; set; }
    public decimal Amount { get; set; }
    public DateTime OrderDate { get; set; }
}

internal class TypedKinesisRecordHandler : ITypedRecordHandler<OrderEvent> 
{
    public async Task<RecordHandlerResult> HandleAsync(OrderEvent orderEvent, CancellationToken cancellationToken)
    {
        if (string.IsNullOrEmpty(orderEvent.OrderId)) 
        {
            throw new ArgumentException("Order ID is required");
        }

        return await Task.FromResult(RecordHandlerResult.None); 
    }
}

public class Function
{
    [BatchProcessor(TypedRecordHandler = typeof(TypedKinesisRecordHandler))]
    public BatchItemFailuresResponse HandlerUsingTypedAttribute(KinesisEvent _)
    {
        return TypedKinesisStreamBatchProcessor.Result.BatchItemFailuresResponse; 
    }
}
```

# Lambda에서 Kinesis 데이터 스트림 이벤트 소스에 대한 폐기된 배치 레코드 유지
<a name="kinesis-on-failure-destination"></a>

Kinesis 이벤트 소스 매핑에 대한 오류 처리는 오류가 함수 간접 호출 전에 발생하는지 아니면 함수 간접 호출 중에 발생하는지 여부에 따라 달라집니다.
+ **간접 호출 전:** Lambda 이벤트 소스 매핑이 스로틀링 또는 기타 문제로 인해 함수를 간접적으로 간접 호출할 수 없는 경우 레코드가 만료되거나 이벤트 소스 매핑에 구성된 최대 기간([MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds))을 초과할 때까지 재시도합니다.
+ **간접 호출 중:** 함수가 간접적으로 간접 호출되었지만 오류가 반환되는 경우 Lambda는 레코드가 만료되거나 최대 기간([MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds))을 초과하거나 구성된 재시도 할당량([MaximumRetryAttempts](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRetryAttempts))에 도달할 때까지 재시도합니다. 함수 오류의 경우 실패한 배치를 두 개의 작은 배치로 분할하여 잘못된 레코드를 격리하고 시간 초과를 방지하는 [BisectBatchOnFunctionError](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-response-BisectBatchOnFunctionError)를 구성할 수도 있습니다. 배치를 분할할 때는 재시도 할당량이 소모되지 않습니다.

오류 처리에서 실패를 측정하는 경우 Lambda는 레코드를 폐기하고 스트림에서 배치 처리를 계속합니다. 기본 설정을 사용하는 경우 이는 잘못된 레코드가 영향을 받은 샤드에 대한 처리를 최대 1주 동안 차단할 수 있음을 의미합니다. 이를 방지하려면 함수의 이벤트 소스 매핑을 사용자의 사례에 적합한 최대 레코드 사용 기간 및 합당한 재시도 횟수로 구성합니다.

## 실패한 간접 호출에 대한 대상 구성
<a name="kinesis-on-failure-destination-console"></a>

실패한 이벤트 소스 매핑 간접 호출 기록을 보관하려면 함수의 이벤트 소스 매핑에 대상을 추가합니다. 대상으로 전송된 각 레코드는 실패한 간접 호출에 대한 메타데이터를 포함하는 JSON 문서입니다. Amazon S3 대상의 경우 Lambda는 메타데이터와 함께 전체 간접 호출 레코드를 전송합니다. 모든 Amazon SNS 주제, Amazon SQS 대기열, Amazon S3 버킷 또는 Kafka를 대상으로 구성할 수 있습니다.

Amazon S3 대상을 사용하면 [Amazon S3 이벤트 알림](https://docs.aws.amazon.com/) 기능을 통해 객체를 대상 S3 버킷에 업로드할 때 알림을 받을 수 있습니다. 실패한 배치에서 자동 처리를 수행하기 위해 다른 Lambda 함수를 간접 호출하도록 S3 이벤트 알림을 구성할 수도 있습니다.

실행 역할에 대상에 대한 권한이 있어야 합니다.
+ **SQS 대상:** [sqs:SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)
+ **SNS 대상:** [sns:Publish](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html)
+ **S3 대상:** [s3:PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 및 [s3:ListBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/ListObjectsV2.html)
+ **Kafka 대상:** [kafka-cluster:WriteData](https://docs.aws.amazon.com/msk/latest/developerguide/kafka-actions.html)

Kafka 주제를 Kafka 이벤트 소스 매핑의 실패 시 대상으로 구성할 수 있습니다. Lambda가 재시도 횟수를 소진한 후 레코드를 처리할 수 없거나 레코드가 최대 수명을 초과하는 경우 Lambda는 나중에 처리할 수 있도록 실패한 레코드를 지정된 Kafka 주제로 보냅니다. 자세한 내용은 [Kafka 주제를 실패 시 대상으로 사용](kafka-on-failure-destination.md) 항목을 참조하세요.

S3 대상에 대해 자체 KMS 키를 사용하여 암호화를 활성화한 경우 함수의 실행 역할에 [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)를 직접 호출할 수 있는 권한도 있어야 합니다. KMS 키와 S3 버킷 대상이 Lambda 함수 및 실행 역할과 다른 계정에 있는 경우 실행 역할을 신뢰하도록 KMS 키를 구성하여 kms:GenerateDataKey를 허용합니다.

이 콘솔을 사용하여 장애 시 대상을 구성하려면 다음 단계를 따르세요.

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 함수를 선택합니다.

1. **함수 개요(Function overview)**에서 **대상 추가(Add destination)**를 선택합니다.

1. **소스**의 경우 **이벤트 소스 매핑 간접 호출**을 선택합니다.

1. **이벤트 소스 매핑**의 경우 이 함수에 대해 구성된 이벤트 소스를 선택합니다.

1. **조건**의 경우 **실패 시**를 선택합니다. 이벤트 소스 매핑 간접 호출의 경우 이 조건만 수락됩니다.

1. **대상 유형**의 경우 Lambda가 간접 호출 레코드를 전송할 대상 유형을 선택합니다.

1. **Destination(대상)**에서 리소스를 선택합니다.

1. **저장**을 선택합니다.

AWS Command Line Interface(AWS CLI)를 사용하여 장애 시 대상을 구성할 수도 있습니다. 예를 들어, 다음 [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 명령은 SQS 장애 시 대상이 있는 이벤트 소스 매핑을 `MyFunction`에 추가합니다.

```
aws lambda create-event-source-mapping \
--function-name "MyFunction" \
--event-source-arn arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sqs:us-east-1:123456789012:dest-queue"}}'
```

다음 [update-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 명령은 두 번의 재시도 시도 후 또는 레코드가 1시간 이상 지난 경우 SNS 대상으로 실패한 간접 호출 레코드를 전송하도록 이벤트 소스 매핑을 업데이트합니다.

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--maximum-retry-attempts 2 \
--maximum-record-age-in-seconds 3600 \
--destination-config '{"OnFailure": {"Destination": "arn:aws:sns:us-east-1:123456789012:dest-topic"}}'
```

업데이트된 설정은 비동기식으로 적용되며 프로세스가 완료된 후에야 출력에 반영됩니다. [get-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-event-source-mapping.html) 명령을 사용하여 현재 상태를 봅니다.

대상을 제거하려면 `destination-config` 파라미터의 인수로 빈 문자열을 제공합니다.

```
aws lambda update-event-source-mapping \
--uuid f89f8514-cdd9-4602-9e1f-01a5b77d449b \
--destination-config '{"OnFailure": {"Destination": ""}}'
```

### Amazon S3에 대한 보안 모범 사례
<a name="kinesis-s3-destination-security"></a>

함수 구성에서 대상을 제거하지 않고 대상으로 구성된 S3 버킷을 삭제하면 보안 위험이 초래될 수 있습니다. 사용자의 대상 버킷 이름을 다른 사용자가 알고 있는 경우 AWS 계정에서 버킷을 다시 생성할 수 있습니다. 실패한 간접 호출에 대한 레코드가 해당 버킷으로 전송되어 함수의 데이터가 공개될 수 있습니다.

**주의**  
함수의 간접 호출 레코드를 다른 AWS 계정의 S3 버킷으로 전송할 수 없도록 하려면 계정의 버킷에 대한 `s3:PutObject` 권한을 제한하는 조건을 함수의 실행 역할에 추가합니다.

다음 예제에서는 함수의 `s3:PutObject` 권한을 계정의 버킷으로 제한하는 IAM 정책을 보여줍니다. 또한 이 정책에서는 Lambda가 S3 버킷을 대상으로 사용하는 데 필요한 `s3:ListBucket` 권한도 부여합니다.

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "S3BucketResourceAccountWrite",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::*/*",
                "arn:aws:s3:::*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:ResourceAccount": "111122223333"
                }
            }
        }
    ]
}
```

AWS Management Console 또는 AWS CLI를 사용하여 함수의 실행 역할에 권한 정책을 추가하려면 다음 절차의 지침을 참조하세요.

------
#### [ Console ]

**함수의 실행 역할에 권한 정책을 추가하는 방법(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 실행 역할을 수정하려는 Lambda 함수를 선택하세요.

1. **구성** 탭을 선택한 다음 **사용 권한**을 선택합니다.

1. **실행 역할** 탭에서 함수의 **역할 이름**을 선택하여 역할의 IAM 콘솔 페이지를 여세요.

1. 다음을 수행하여 역할에 기본 권한 정책을 추가하세요.

   1. **권한** 창에서 **권한 추가**를 선택하고 **인라인 정책 생성**을 선택하세요.

   1. **정책 편집기**에서 **JSON**을 선택하세요.

   1. 추가하려는 정책을 편집기에 붙여넣고(이때 기존 JSON 대체) **다음**을 선택하세요.

   1. **정책 세부 정보** 아래에 **정책 이름**을 입력하세요.

   1. **정책 생성**을 선택합니다.

------
#### [ AWS CLI ]

**함수의 실행 역할에 권한 정책을 추가하는 방법(CLI)**

1. 필요한 권한이 있는 JSON 정책 문서를 생성하고 로컬 디렉터리에 저장하세요.

1. IAM `put-role-policy` CLI 명령을 사용하여 함수의 실행 역할에 권한을 추가하세요. JSON 정책 문서를 저장한 디렉터리에서 다음 명령을 실행하고 역할 이름, 정책 이름 및 정책 문서를 고유한 값으로 바꾸세요.

   ```
   aws iam put-role-policy \
   --role-name my_lambda_role \
   --policy-name LambdaS3DestinationPolicy \
   --policy-document file://my_policy.json
   ```

------

### Amazon SNS 및 Amazon SQS 간접 호출 레코드 예제
<a name="kinesis-on-failure-destination-example-sns-sqs"></a>

다음 예는 실패한 Kinesis 이벤트 소스 간접 호출에 대해 Lambda가 SQS 대기열 또는 SNS 주제로 전송하는 내용을 보여줍니다. Lambda는 이러한 대상 유형에 대한 메타데이터만 전송하기 때문에 `streamArn`, `shardId`, `startSequenceNumber` 및 `endSequenceNumber` 필드를 사용하여 전체 원본 레코드를 확보합니다. `KinesisBatchInfo` 속성에 표시되는 모든 필드는 항상 존재합니다.

```
{
    "requestContext": {
        "requestId": "c9b8fa9f-5a7f-xmpl-af9c-0c604cde93a5",
        "functionArn": "arn:aws:lambda:us-east-2:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted",
        "approximateInvokeCount": 1
    },
    "responseContext": {
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:38:06.021Z",
    "KinesisBatchInfo": {
        "shardId": "shardId-000000000001",
        "startSequenceNumber": "49601189658422359378836298521827638475320189012309704722",
        "endSequenceNumber": "49601189658422359378836298522902373528957594348623495186",
        "approximateArrivalOfFirstRecord": "2019-11-14T00:38:04.835Z",
        "approximateArrivalOfLastRecord": "2019-11-14T00:38:05.580Z",
        "batchSize": 500,
        "streamArn": "arn:aws:kinesis:us-east-2:123456789012:stream/mystream"
    }
}
```

이 정보를 사용하여 문제 해결을 위해 스트림에서 영향을 받은 레코드를 검색할 수 있습니다. 실제 레코드는 포함되지 않으므로 이 레코드를 처리하고 실제 레코드가 만료되고 없어지기 전에 스트림에서 해당 레코드를 검색해야 합니다.

### Amazon S3 간접 호출 레코드 예제
<a name="kinesis-on-failure-destination-example-sns-sqs-s3"></a>

다음 예제에서는 실패한 Kinesis 이벤트 소스 간접 호출에 대해 Lambda가 Amazon S3 버킷으로 전송하는 내용을 보여줍니다. SQS 및 SNS 대상에 대한 이전 예제의 모든 필드 외에도 `payload` 필드에는 원래 간접 호출 레코드가 이스케이프된 JSON 문자열로 포함되어 있습니다.

```
{
    "requestContext": {
        "requestId": "c9b8fa9f-5a7f-xmpl-af9c-0c604cde93a5",
        "functionArn": "arn:aws:lambda:us-east-2:123456789012:function:myfunction",
        "condition": "RetryAttemptsExhausted",
        "approximateInvokeCount": 1
    },
    "responseContext": {
        "statusCode": 200,
        "executedVersion": "$LATEST",
        "functionError": "Unhandled"
    },
    "version": "1.0",
    "timestamp": "2019-11-14T00:38:06.021Z",
    "KinesisBatchInfo": {
        "shardId": "shardId-000000000001",
        "startSequenceNumber": "49601189658422359378836298521827638475320189012309704722",
        "endSequenceNumber": "49601189658422359378836298522902373528957594348623495186",
        "approximateArrivalOfFirstRecord": "2019-11-14T00:38:04.835Z",
        "approximateArrivalOfLastRecord": "2019-11-14T00:38:05.580Z",
        "batchSize": 500,
        "streamArn": "arn:aws:kinesis:us-east-2:123456789012:stream/mystream"
    },
    "payload": "<Whole Event>" // Only available in S3
}
```

간접 호출 레코드를 포함하는 S3 객체는 다음 이름 지정 규칙을 사용합니다.

```
aws/lambda/<ESM-UUID>/<shardID>/YYYY/MM/DD/YYYY-MM-DDTHH.MM.SS-<Random UUID>
```

# Lambda에서 상태 저장 Kinesis Data Streams 처리 구현
<a name="services-kinesis-windows"></a>

Lambda 함수는 연속 스트림 처리 애플리케이션을 실행할 수 있습니다. 스트림은 애플리케이션을 통해 연속적으로 흐르는 무한 데이터를 나타냅니다. 이 지속적으로 업데이트되는 입력의 정보를 분석하기 위해 시간의 항으로 정의된 윈도우를 사용하여 포함된 레코드를 바인딩할 수 있습니다.

텀블링 기간은 일정한 간격으로 시작되고 끝나는 고유한 시간대입니다. 기본적으로 Lambda 호출은 상태 비저장입니다. 즉, 외부 데이터베이스 없이는 여러 연속 호출에서 데이터를 처리하는 데 사용할 수 없습니다. 그러나 텀블링 기간을 활성화하면 호출 간에 상태를 유지할 수 있습니다. 이 상태에는 현재 윈도우에 대해 이전에 처리된 메시지의 집계 결과가 포함됩니다. 상태는 샤드당 최대 1MB가 될 수 있습니다. 이 크기를 초과하면 Lambda가 윈도우를 조기 종료합니다.

스트림의 각 레코드는 특정 윈도우에 속합니다. Lambda는 각 레코드를 한 번 이상 처리하지만 각 레코드가 한 번만 처리된다고 보장하지는 않습니다. 드물게 오류 처리와 같이 일부 레코드가 두 번 이상 처리될 수 있습니다. 레코드는 항상 처음부터 순서대로 처리됩니다. 레코드가 두 번 이상 처리되는 경우 레코드가 비순차적으로 처리될 수 있습니다.

## 집계 및 처리
<a name="streams-tumbling-processing"></a>

집계 및 해당 집계의 최종 결과 처리를 위해 사용자 관리형 함수가 간접 호출됩니다. Lambda는 윈도우 내에서 수신한 모든 레코드를 집계합니다. 이러한 레코드를 각각 별도의 호출인 여러 배치에서 받을 수 있습니다. 각 호출은 상태를 수신합니다. 따라서 텀블링 기간을 사용할 때 Lambda 함수 응답에는 `state` 속성을 포함해야 합니다. 응답에 `state` 속성이 포함되지 않은 경우 Lambda는 이 호출이 실패한 것으로 간주합니다. 이 조건을 충족하기 위해 함수는 다음 JSON 모양의 `TimeWindowEventResponse` 객체를 반환할 수 있습니다.

**Example `TimeWindowEventResponse` 값**  

```
{
    "state": {
        "1": 282,
        "2": 715
    },
    "batchItemFailures": []
}
```

**참고**  
Java 함수의 경우 `Map<String, String>`을 사용하여 상태를 나타내는 것이 좋습니다.

윈도우 끝에서 `isFinalInvokeForWindow` 플래그는 이것이 최종 상태이며 처리 준비가 되었음을 나타내기 위해 `true`로 설정됩니다. 처리 후 윈도우가 완료되고 최종 호출이 완료된 다음 상태가 삭제됩니다.

윈도우 끝에서 Lambda가 집계 결과에 대한 작업을 위해 최종 처리를 사용합니다. 최종 처리는 동기식으로 간접 호출됩니다. 성공적인 호출 후 함수가 시퀀스 번호를 검사하고 스트림 처리가 계속됩니다. 호출이 실패하면 Lambda 함수는 호출이 성공할 때까지 추가 처리를 일시 중단합니다.

**Example KinesisTimeWindowEvent**  

```
{
    "Records": [
        {
            "kinesis": {
                "kinesisSchemaVersion": "1.0",
                "partitionKey": "1",
                "sequenceNumber": "49590338271490256608559692538361571095921575989136588898",
                "data": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
                "approximateArrivalTimestamp": 1607497475.000
            },
            "eventSource": "aws:kinesis",
            "eventVersion": "1.0",
            "eventID": "shardId-000000000006:49590338271490256608559692538361571095921575989136588898",
            "eventName": "aws:kinesis:record",
            "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-kinesis-role",
            "awsRegion": "us-east-1",
            "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/lambda-stream"
        }
    ],
    "window": {
        "start": "2020-12-09T07:04:00Z",
        "end": "2020-12-09T07:06:00Z"
    },
    "state": {
        "1": 282,
        "2": 715
    },
    "shardId": "shardId-000000000006",
    "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/lambda-stream",
    "isFinalInvokeForWindow": false,
    "isWindowTerminatedEarly": false
}
```

## 구성
<a name="streams-tumbling-config"></a>

이벤트 소스 매핑을 생성하거나 업데이트할 때 텀블링 윈도우를 구성할 수 있습니다. 텀블링 윈도우를 구성하려면 윈도우를 초 단위로 지정합니다([TumblingWindowInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-TumblingWindowInSeconds)). 다음 예제 AWS Command Line Interface(AWS CLI) 명령은 텀블링 윈도우가 120초인 스트리밍 이벤트 소스 매핑을 생성합니다. 집계 및 처리를 위해 정의된 Lambda 함수는 `tumbling-window-example-function`입니다.

```
aws lambda create-event-source-mapping \
--event-source-arn arn:aws:kinesis:us-east-1:123456789012:stream/lambda-stream \
--function-name tumbling-window-example-function \
--starting-position TRIM_HORIZON \
--tumbling-window-in-seconds 120
```

Lambda는 레코드가 스트림에 삽입된 시간을 기준으로 텀블링 윈도우 경계를 결정합니다. 모든 레코드에는 Lambda가 경계 결정에서 사용하는 대략적인 타임스탬프가 있습니다.

텀블링 윈도우 집계는 리샤딩을 지원하지 않습니다. 샤드가 끝나면 Lambda는 현재 윈도우가 닫힌 것으로 간주하며 자식 샤드는 새 상태로 고유한 윈도우를 시작합니다. 현재 윈도우에 새 레코드가 추가되지 않으면 Lambda는 최대 2분간 기다린 후 윈도우가 끝난 것으로 간주합니다. 이렇게 하면 레코드가 간헐적으로 추가되더라도 함수가 현재 윈도우의 모든 레코드를 읽을 수 있습니다.

텀블링 윈도우는 기존 재시도 정책 `maxRetryAttempts` 및 `maxRecordAge`를 완벽하게 지원합니다.

**Example Handler.py - 집계 및 처리**  
다음 Python 함수는 최종 상태를 집계한 다음 처리하는 방법을 보여줍니다.  

```
def lambda_handler(event, context):
    print('Incoming event: ', event)
    print('Incoming state: ', event['state'])

#Check if this is the end of the window to either aggregate or process.
    if event['isFinalInvokeForWindow']:
        # logic to handle final state of the window
        print('Destination invoke')
    else:
        print('Aggregate invoke')

#Check for early terminations
    if event['isWindowTerminatedEarly']:
        print('Window terminated early')

    #Aggregation logic
    state = event['state']
    for record in event['Records']:
        state[record['kinesis']['partitionKey']] = state.get(record['kinesis']['partitionKey'], 0) + 1

    print('Returning state: ', state)
    return {'state': state}
```

# Amazon Kinesis Data Streams 이벤트 소스 매핑을 위한 Lambda 파라미터
<a name="services-kinesis-parameters"></a>

모든 Lambda 이벤트 소스 매핑은 동일한 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 및 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 작업을 공유합니다. 그러나 일부 파라미터만 Kinesis에 적용됩니다.


| 파라미터 | 필수 | 기본값 | 참고 | 
| --- | --- | --- | --- | 
|  [BatchSize](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-BatchSize)  |  N  |  100  |  최대값: 10,000  | 
|  [BisectBatchOnFunctionError](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-BisectBatchOnFunctionError)  |  N  |  false  |  없음 | 
|  [DestinationConfig](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-DestinationConfig)  |  N  | N/A |  폐기된 레코드의 Amazon SQS 대기열 또는 Amazon SNS 주제 대상. 자세한 내용은 [실패한 간접 호출에 대한 대상 구성](kinesis-on-failure-destination.md#kinesis-on-failure-destination-console) 단원을 참조하십시오.  | 
|  [활성화됨](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-Enabled)  |  N  |  true  |  없음 | 
|  [EventSourceArn](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-EventSourceArn)  |  Y  | N/A |  데이터 스트림 또는 스트림 소비자의 ARN  | 
|  [FunctionName](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-FunctionName)  |  Y  | N/A |  없음 | 
|  [FunctionResponseTypes](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-FunctionResponseTypes)  |  N  |  N/A |  함수가 배치에서 특정 실패를 보고하도록 하려면 `FunctionResponseTypes`에 `ReportBatchItemFailures` 값을 포함하세요. 자세한 내용은 [Kinesis Data Streams 및 Lambda로 부분 배치 응답 구성](services-kinesis-batchfailurereporting.md) 단원을 참조하십시오.  | 
|  [MaximumBatchingWindowInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumBatchingWindowInSeconds)  |  N  |  0  |  없음 | 
|  [MaximumRecordAgeInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRecordAgeInSeconds)  |  N  |  -1  |  -1은 무한을 의미: Lambda는 레코드를 버리지 않습니다([Kinesis Data Streams 데이터 보존 설정](https://docs.aws.amazon.com/streams/latest/dev/kinesis-extended-retention.html)은 계속 적용됨). 최솟값: -1 최대값: 604,800  | 
|  [MaximumRetryAttempts](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-MaximumRetryAttempts)  |  N  |  -1  |  -1(무한): 레코드가 만료될 때까지 실패한 레코드가 다시 시도됩니다 최솟값: -1 최대값: 10,000  | 
|  [ParallelizationFactor](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-ParallelizationFactor)  |  N  |  1  |  최댓값: 10  | 
|  [StartingPosition](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-StartingPosition)  |  Y  |  N/A |  AT\$1TIMESTAMP, TRIM\$1HORIZON, 또는 LATEST  | 
|  [StartingPositionTimestamp](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-StartingPositionTimestamp)  |  N  |  N/A |  StartingPosition이 AT\$1TIMESTAMP로 설정된 경우에만 유효합니다. 읽기를 시작하는 시간(Unix 시간 초)  | 
|  [TumblingWindowInSeconds](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html#lambda-CreateEventSourceMapping-request-TumblingWindowInSeconds)  |  N  |  N/A |  최솟값: 0 최댓값: 900  | 

# Kinesis 이벤트 소스를 통해 이벤트 필터링 사용
<a name="with-kinesis-filtering"></a>

이벤트 필터링을 사용하여 Lambda가 함수로 전송하는 스트림 또는 대기열의 레코드를 제어할 수 있습니다. 이벤트 필터링의 작동 방식에 대한 일반적인 내용은 [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)을 참조하세요.

이 섹션에서는 Kinesis 이벤트 소스에 대한 이벤트 필터링에 중점을 둡니다.

**참고**  
Kinesis 이벤트 소스 매핑은 `data` 키에 대한 필터링만 지원합니다.

**Topics**
+ [

## Kinesis 이벤트 필터링 기본 사항
](#filtering-kinesis)
+ [

## Kinesis 집계 레코드 필터링
](#filtering-kinesis-efo)

## Kinesis 이벤트 필터링 기본 사항
<a name="filtering-kinesis"></a>

생산자가 JSON 형식의 데이터를 Kinesis 데이터 스트림에 넣고 있다고 가정해 보겠습니다. 예제 레코드는 다음과 같으며, JSON 데이터는 `data` 필드에서 Base64로 인코딩된 문자열로 변환됩니다.

```
{
    "kinesis": {
        "kinesisSchemaVersion": "1.0",
        "partitionKey": "1",
        "sequenceNumber": "49590338271490256608559692538361571095921575989136588898",
        "data": "eyJSZWNvcmROdW1iZXIiOiAiMDAwMSIsICJUaW1lU3RhbXAiOiAieXl5eS1tbS1kZFRoaDptbTpzcyIsICJSZXF1ZXN0Q29kZSI6ICJBQUFBIn0=",
        "approximateArrivalTimestamp": 1545084650.987
        },
    "eventSource": "aws:kinesis",
    "eventVersion": "1.0",
    "eventID": "shardId-000000000006:49590338271490256608559692538361571095921575989136588898",
    "eventName": "aws:kinesis:record",
    "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-role",
    "awsRegion": "us-east-2",
    "eventSourceARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream"
}
```

생산자가 스트림에 넣는 데이터가 유효한 JSON이면 이벤트 필터링을 사용하여 `data` 키로 레코드를 필터링할 수 있습니다. 생산자가 다음 JSON 형식으로 레코드를 Kinesis 스트림에 넣고 있다고 가정해 보겠습니다.

```
{
    "record": 12345,
    "order": {
        "type": "buy",
        "stock": "ANYCO",
        "quantity": 1000
        }
}
```

주문 유형이 'buy'인 레코드만 필터링하려면 `FilterCriteria` 객체는 다음과 같습니다.

```
{
    "Filters": [
        {
            "Pattern": "{ \"data\" : { \"order\" : { \"type\" : [ \"buy\" ] } } }"
        }
    ]
}
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{
    "data": {
        "order": {
            "type": [ "buy" ]
            }
      }
}
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "data" : { "order" : { "type" : [ "buy" ] } } }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:kinesis:us-east-2:123456789012:stream/my-stream \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"order\" : { \"type\" : [ \"buy\" ] } } }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"order\" : { \"type\" : [ \"buy\" ] } } }"}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
  Filters:
    - Pattern: '{ "data" : { "order" : { "type" : [ "buy" ] } } }'
```

------

Kinesis 소스에서 이벤트를 올바르게 필터링하려면 데이터 필드와 데이터 필드의 필터 기준이 모두 유효한 JSON 형식이어야 합니다. 두 필드 중 하나가 유효한 JSON 형식이 아닌 경우 Lambda는 해당 메시지를 삭제하거나 예외를 발생시킵니다. 다음 표에는 특정 동작이 요약되어 있습니다.


| 수신 데이터 형식 | 데이터 속성에 대한 필터 패턴 형식 | 결과적 작업 | 
| --- | --- | --- | 
|  유효한 JSON  |  유효한 JSON  |  Lambda는 필터 기준에 따라 필터링합니다.  | 
|  유효한 JSON  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  유효한 JSON  |  JSON 외  |  이벤트 소스 매핑 생성 또는 업데이트 시 Lambda에서 예외가 발생합니다. 데이터 속성에 대한 필터 패턴은 유효한 JSON 형식이어야 합니다.  | 
|  JSON 외  |  유효한 JSON  |  Lambda는 해당 레코드를 삭제합니다.  | 
|  JSON 외  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  JSON 외  |  JSON 외  |  이벤트 소스 매핑 생성 또는 업데이트 시 Lambda에서 예외가 발생합니다. 데이터 속성에 대한 필터 패턴은 유효한 JSON 형식이어야 합니다.  | 

## Kinesis 집계 레코드 필터링
<a name="filtering-kinesis-efo"></a>

Kinesis를 사용하면 여러 레코드를 단일 Kinesis Data Streams 레코드로 집계하여 데이터 처리량을 늘릴 수 있습니다. Lambda는 Kinesis [향상된 팬아웃](https://docs.aws.amazon.com/streams/latest/dev/enhanced-consumers.html)을 사용할 때 집계 레코드에만 필터 기준을 적용할 수 있습니다. 표준 Kinesis를 사용하여 집계 레코드를 필터링하는 것은 지원되지 않습니다. 향상된 팬아웃을 사용하는 경우 Lambda 함수의 트리거 역할을 하도록 Kinesis 전용 처리량 소비자를 구성합니다. 그런 다음 Lambda는 집계 레코드를 필터링하고 필터 기준을 충족하는 레코드만 전달합니다.

Kinesis 레코드 집계에 대해 자세히 알아보려면 Kinesis Producer Library(KPL) 주요 개념 페이지의 [집계](https://docs.aws.amazon.com/streams/latest/dev/kinesis-kpl-concepts.html#kinesis-kpl-concepts-aggretation) 섹션을 참조하세요. Kinesis 향상된 팬아웃과 함께 Lambda를 사용하는 방법에 대해 자세히 알아보려면 AWS 컴퓨팅 블로그의 [Amazon Kinesis Data Streams 향상된 팬아웃 및 AWS Lambda로 실시간 스트림 처리 성능 향상](https://aws.amazon.com/blogs/compute/increasing-real-time-stream-processing-performance-with-amazon-kinesis-data-streams-enhanced-fan-out-and-aws-lambda/)을 참조하세요.

# 자습서: Kinesis Data Streams에서 Lambda 사용
<a name="with-kinesis-example"></a>

이 자습서에서는 Amazon Kinesis 데이터 스트림의 이벤트를 소비하기 위한 Lambda 함수를 생성합니다.

1. 사용자 지정 앱은 스트림에 레코드를 기록합니다.

1. AWS Lambda는 스트림에서 새로운 레코드가 감지될 때마다 스트림을 폴링하고 Lambda 함수를 간접 호출합니다.

1. AWS Lambda는 Lambda 함수를 생성할 때 지정한 실행 역할을 수임하여 Lambda 함수를 실행합니다.

## 사전 조건
<a name="with-kinesis-prepare"></a>

### AWS Command Line Interface 설치
<a name="install_aws_cli"></a>

아직 AWS Command Line Interface를 설치하지 않은 경우 [AWS CLI의 최신 버전 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)에서 설명하는 단계에 따라 설치하세요.

이 자습서에서는 명령을 실행할 셸 또는 명령줄 터미널이 필요합니다. Linux 및 macOS에서는 선호하는 셸과 패키지 관리자를 사용합니다.

**참고**  
Windows에서는 Lambda와 함께 일반적으로 사용하는 일부 Bash CLI 명령(예:`zip`)은 운영 체제의 기본 제공 터미널에서 지원되지 않습니다. Ubuntu와 Bash의 Windows 통합 버전을 가져오려면 [Linux용 Windows Subsystem을 설치](https://docs.microsoft.com/en-us/windows/wsl/install-win10)합니다.

## 실행 역할 생성
<a name="with-kinesis-example-create-iam-role"></a>

함수에 AWS 리소스에 액세스할 수 있는 권한을 제공하는 [실행 역할](lambda-intro-execution-role.md)을 만듭니다.

**실행 역할을 만들려면**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. **역할 생성**을 선택합니다.

1. 다음 속성을 사용하여 역할을 만듭니다.
   + **신뢰할 수 있는 엔터티** – **AWS Lambda**.
   + **권한** – **AWSLambdaKinesisExecutionRole**.
   + **역할 이름** – **lambda-kinesis-role**.

**AWSLambdaKinesisExecutionRole** 정책은 함수가 Kinesis에서 항목을 읽고 CloudWatch Logs에 로그를 쓰는 데 필요한 권한을 가집니다.

## 함수 생성
<a name="with-kinesis-example-create-function"></a>

Kinesis 메시지를 처리하는 Lambda 함수를 생성합니다. 함수 코드는 Kinesis 레코드의 이벤트 ID 및 이벤트 데이터를 CloudWatch 로그에 기록합니다.

이 자습서에서는 Node.js 24 런타임을 사용하지만 다른 런타임 언어의 예제 코드도 제공했습니다. 다음 상자에서 탭을 선택하여 관심 있는 런타임에 대한 코드를 볼 수 있습니다. 이 단계에서 사용할 JavaScript 코드는 **JavaScript** 탭에 표시된 첫 번째 예제입니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 Kinesis 이벤트 사용  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
﻿using System.Text;
using Amazon.Lambda.Core;
using Amazon.Lambda.KinesisEvents;
using AWS.Lambda.Powertools.Logging;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace KinesisIntegrationSampleCode;

public class Function
{
    // Powertools Logger requires an environment variables against your function
    // POWERTOOLS_SERVICE_NAME
    [Logging(LogEvent = true)]
    public async Task FunctionHandler(KinesisEvent evnt, ILambdaContext context)
    {
        if (evnt.Records.Count == 0)
        {
            Logger.LogInformation("Empty Kinesis Event received");
            return;
        }

        foreach (var record in evnt.Records)
        {
            try
            {
                Logger.LogInformation($"Processed Event with EventId: {record.EventId}");
                string data = await GetRecordDataAsync(record.Kinesis, context);
                Logger.LogInformation($"Data: {data}");
                // TODO: Do interesting work based on the new data
            }
            catch (Exception ex)
            {
                Logger.LogError($"An error occurred {ex.Message}");
                throw;
            }
        }
        Logger.LogInformation($"Successfully processed {evnt.Records.Count} records.");
    }

    private async Task<string> GetRecordDataAsync(KinesisEvent.Record record, ILambdaContext context)
    {
        byte[] bytes = record.Data.ToArray();
        string data = Encoding.UTF8.GetString(bytes);
        await Task.CompletedTask; //Placeholder for actual async work
        return data;
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 Kinesis 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"log"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(ctx context.Context, kinesisEvent events.KinesisEvent) error {
	if len(kinesisEvent.Records) == 0 {
		log.Printf("empty Kinesis event received")
		return nil
	}

	for _, record := range kinesisEvent.Records {
		log.Printf("processed Kinesis event with EventId: %v", record.EventID)
		recordDataBytes := record.Kinesis.Data
		recordDataText := string(recordDataBytes)
		log.Printf("record data: %v", recordDataText)
		// TODO: Do interesting work based on the new data
	}
	log.Printf("successfully processed %v records", len(kinesisEvent.Records))
	return nil
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda에서 Kinesis 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package example;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;

public class Handler implements RequestHandler<KinesisEvent, Void> {
    @Override
    public Void handleRequest(final KinesisEvent event, final Context context) {
        LambdaLogger logger = context.getLogger();
        if (event.getRecords().isEmpty()) {
            logger.log("Empty Kinesis Event received");
            return null;
        }
        for (KinesisEvent.KinesisEventRecord record : event.getRecords()) {
            try {
                logger.log("Processed Event with EventId: "+record.getEventID());
                String data = new String(record.getKinesis().getData().array());
                logger.log("Data:"+ data);
                // TODO: Do interesting work based on the new data
            }
            catch (Exception ex) {
                logger.log("An error occurred:"+ex.getMessage());
                throw ex;
            }
        }
        logger.log("Successfully processed:"+event.getRecords().size()+" records");
        return null;
    }

}
```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/blob/main/integration-kinesis-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda로 Kinesis 이벤트 사용  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
  for (const record of event.Records) {
    try {
      console.log(`Processed Kinesis Event - EventID: ${record.eventID}`);
      const recordData = await getRecordDataAsync(record.kinesis);
      console.log(`Record Data: ${recordData}`);
      // TODO: Do interesting work based on the new data
    } catch (err) {
      console.error(`An error occurred ${err}`);
      throw err;
    }
  }
  console.log(`Successfully processed ${event.Records.length} records.`);
};

async function getRecordDataAsync(payload) {
  var data = Buffer.from(payload.data, "base64").toString("utf-8");
  await Promise.resolve(1); //Placeholder for actual async work
  return data;
}
```
TypeScript를 사용하여 Lambda로 Kinesis 이벤트 사용  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import {
  KinesisStreamEvent,
  Context,
  KinesisStreamHandler,
  KinesisStreamRecordPayload,
} from "aws-lambda";
import { Buffer } from "buffer";
import { Logger } from "@aws-lambda-powertools/logger";

const logger = new Logger({
  logLevel: "INFO",
  serviceName: "kinesis-stream-handler-sample",
});

export const functionHandler: KinesisStreamHandler = async (
  event: KinesisStreamEvent,
  context: Context
): Promise<void> => {
  for (const record of event.Records) {
    try {
      logger.info(`Processed Kinesis Event - EventID: ${record.eventID}`);
      const recordData = await getRecordDataAsync(record.kinesis);
      logger.info(`Record Data: ${recordData}`);
      // TODO: Do interesting work based on the new data
    } catch (err) {
      logger.error(`An error occurred ${err}`);
      throw err;
    }
    logger.info(`Successfully processed ${event.Records.length} records.`);
  }
};

async function getRecordDataAsync(
  payload: KinesisStreamRecordPayload
): Promise<string> {
  var data = Buffer.from(payload.data, "base64").toString("utf-8");
  await Promise.resolve(1); //Placeholder for actual async work
  return data;
}
```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 Kinesis 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\Kinesis\KinesisEvent;
use Bref\Event\Kinesis\KinesisHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler extends KinesisHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws JsonException
     * @throws \Bref\Event\InvalidLambdaEvent
     */
    public function handleKinesis(KinesisEvent $event, Context $context): void
    {
        $this->logger->info("Processing records");
        $records = $event->getRecords();
        foreach ($records as $record) {
            $data = $record->getData();
            $this->logger->info(json_encode($data));
            // TODO: Do interesting work based on the new data

            // Any exception thrown will be logged and the invocation will be marked as failed
        }
        $totalRecords = count($records);
        $this->logger->info("Successfully processed $totalRecords records");
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 Kinesis 이벤트를 사용합니다.  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
import base64
def lambda_handler(event, context):

    for record in event['Records']:
        try:
            print(f"Processed Kinesis Event - EventID: {record['eventID']}")
            record_data = base64.b64decode(record['kinesis']['data']).decode('utf-8')
            print(f"Record Data: {record_data}")
            # TODO: Do interesting work based on the new data
        except Exception as e:
            print(f"An error occurred {e}")
            raise e
    print(f"Successfully processed {len(event['Records'])} records.")
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 Kinesis 이벤트를 사용합니다.  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
require 'aws-sdk'

def lambda_handler(event:, context:)
  event['Records'].each do |record|
    begin
      puts "Processed Kinesis Event - EventID: #{record['eventID']}"
      record_data = get_record_data_async(record['kinesis'])
      puts "Record Data: #{record_data}"
      # TODO: Do interesting work based on the new data
    rescue => err
      $stderr.puts "An error occurred #{err}"
      raise err
    end
  end
  puts "Successfully processed #{event['Records'].length} records."
end

def get_record_data_async(payload)
  data = Base64.decode64(payload['data']).force_encoding('UTF-8')
  # Placeholder for actual async work
  # You can use Ruby's asynchronous programming tools like async/await or fibers here.
  return data
end
```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-kinesis-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 Kinesis 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use aws_lambda_events::event::kinesis::KinesisEvent;
use lambda_runtime::{run, service_fn, Error, LambdaEvent};

async fn function_handler(event: LambdaEvent<KinesisEvent>) -> Result<(), Error> {
    if event.payload.records.is_empty() {
        tracing::info!("No records found. Exiting.");
        return Ok(());
    }

    event.payload.records.iter().for_each(|record| {
        tracing::info!("EventId: {}",record.event_id.as_deref().unwrap_or_default());

        let record_data = std::str::from_utf8(&record.kinesis.data);

        match record_data {
            Ok(data) => {
                // log the record data
                tracing::info!("Data: {}", data);
            }
            Err(e) => {
                tracing::error!("Error: {}", e);
            }
        }
    });

    tracing::info!(
        "Successfully processed {} records",
        event.payload.records.len()
    );

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        // disable printing the name of the module in every log line.
        .with_target(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

**함수를 만들려면**

1. 프로젝트에 대한 디렉터리를 생성하고 해당 디렉터리로 전환합니다.

   ```
   mkdir kinesis-tutorial
   cd kinesis-tutorial
   ```

1. 샘플 JavaScript 코드를 새로운 `index.js` 파일에 복사합니다.

1. 배포 패키지를 만듭니다.

   ```
   zip function.zip index.js
   ```

1. `create-function` 명령을 사용해 Lambda 함수를 만듭니다.

   ```
   aws lambda create-function --function-name ProcessKinesisRecords \
   --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
   --role arn:aws:iam::111122223333:role/lambda-kinesis-role
   ```

## Lambda 함수 테스트
<a name="walkthrough-kinesis-events-adminuser-create-test-function-upload-zip-test-manual-invoke"></a>

`invoke` AWS Lambda CLI 명령 및 샘플 Kinesis 이벤트를 사용하여 Lambda 함수를 수동으로 간접 호출합니다.

**Lambda 함수를 테스트하려면**

1. 다음 JSON을 파일에 복사하고 `input.txt`로 저장합니다.

   ```
   {
       "Records": [
           {
               "kinesis": {
                   "kinesisSchemaVersion": "1.0",
                   "partitionKey": "1",
                   "sequenceNumber": "49590338271490256608559692538361571095921575989136588898",
                   "data": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==",
                   "approximateArrivalTimestamp": 1545084650.987
               },
               "eventSource": "aws:kinesis",
               "eventVersion": "1.0",
               "eventID": "shardId-000000000006:49590338271490256608559692538361571095921575989136588898",
               "eventName": "aws:kinesis:record",
               "invokeIdentityArn": "arn:aws:iam::111122223333:role/lambda-kinesis-role",
               "awsRegion": "us-east-2",
               "eventSourceARN": "arn:aws:kinesis:us-east-2:111122223333:stream/lambda-stream"
           }
       ]
   }
   ```

1. `invoke` 명령을 사용하여 함수로 이벤트를 전송합니다.

   ```
   aws lambda invoke --function-name ProcessKinesisRecords \
   --cli-binary-format raw-in-base64-out \
   --payload file://input.txt outputfile.txt
   ```

   **cli-binary-format** 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 `aws configure set cli-binary-format raw-in-base64-out`을(를) 실행하세요. 자세한 내용은 [AWS CLI 지원되는 글로벌 명령줄 옵션](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)을 AWS Command Line Interface 사용 설명서 버전 2에서 참조하세요.

   응답이 `out.txt`로 저장됩니다.

## Kinesis 스트림 생성
<a name="with-kinesis-example-configure-event-source-create"></a>

`create-stream ` 명령을 사용하여 스트림을 만듭니다.

```
aws kinesis create-stream --stream-name lambda-stream --shard-count 1
```

다음 `describe-stream` 명령을 실행하여 스트림 ARN을 가져옵니다.

```
aws kinesis describe-stream --stream-name lambda-stream
```

다음 결과가 표시됩니다.

```
{
    "StreamDescription": {
        "Shards": [
            {
                "ShardId": "shardId-000000000000",
                "HashKeyRange": {
                    "StartingHashKey": "0",
                    "EndingHashKey": "340282366920746074317682119384634633455"
                },
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49591073947768692513481539594623130411957558361251844610"
                }
            }
        ],
        "StreamARN": "arn:aws:kinesis:us-east-1:111122223333:stream/lambda-stream",
        "StreamName": "lambda-stream",
        "StreamStatus": "ACTIVE",
        "RetentionPeriodHours": 24,
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "EncryptionType": "NONE",
        "KeyId": null,
        "StreamCreationTimestamp": 1544828156.0
    }
}
```

다음 단계에서 스트림 ARN을 사용하여 스트림을 Lambda 함수와 연결합니다.

## AWS Lambda에서 이벤트 소스 추가
<a name="with-kinesis-example-configure-event-source-add-event-source"></a>

다음 AWS CLI `add-event-source` 명령을 실행합니다.

```
aws lambda create-event-source-mapping --function-name ProcessKinesisRecords \
--event-source  arn:aws:kinesis:us-east-1:111122223333:stream/lambda-stream \
--batch-size 100 --starting-position LATEST
```

나중에 사용할 수 있도록 매핑 ID를 기록해 둡니다. `list-event-source-mappings` 명령을 실행하여 이벤트 소스 매핑 목록을 가져올 수 있습니다.

```
aws lambda list-event-source-mappings --function-name ProcessKinesisRecords \
--event-source arn:aws:kinesis:us-east-1:111122223333:stream/lambda-stream
```

응답에서 상태 값이 `enabled`인지 확인할 수 있습니다. 이벤트 소스 매핑을 비활성화하여 폴링을 일시적으로 중지시켜 레코드 손실을 방지할 수 있습니다.

## 설정 테스트
<a name="with-kinesis-example-configure-event-source-test-end-to-end"></a>

이벤트 소스 매핑을 테스트하려면 Kinesis 스트림에 이벤트 레코드를 추가합니다. `--data` 값은 Kinesis로 전송하기 전에 CLI가 base64로 인코딩하는 문자열입니다. 동일한 명령을 두 번 이상 실행하여 여러 레코드를 스트림에 추가할 수 있습니다.

```
aws kinesis put-record --stream-name lambda-stream --partition-key 1 \
--data "Hello, this is a test."
```

Lambda에서는 실행 역할을 사용하여 스트림에서 레코드를 읽습니다. 그런 다음 Lambda 함수를 간접 호출해 레코드 배치를 전달합니다. 함수는 각 레코드에서 데이터를 디코딩하고 로깅해 CloudWatch Logs에 출력을 전송합니다. 로그는 [CloudWatch 콘솔](https://console.aws.amazon.com/cloudwatch)에서 확인합니다.

## 리소스 정리
<a name="cleanup"></a>

이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.

**집행 역할 삭제**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. 생성한 실행 역할을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 역할의 이름을 입력하고 **Delete**(삭제)를 선택합니다.

**Lambda 함수를 삭제하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 생성한 함수를 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **confirm**를 입력하고 **Delete**(삭제)를 선택합니다.

**Kinesis 스트림을 삭제하려면**

1. AWS Management Console에 로그인하여 [https://console.aws.amazon.com/kinesis](https://console.aws.amazon.com/kinesis)에서 Kinesis 콘솔을 엽니다.

1. 생성한 스트림을 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **delete**을 입력합니다.

1. **삭제**를 선택합니다.

# Kubernetes와 함께 Lambda 사용
<a name="with-kubernetes"></a>

[AWS Controllers for Kubernetes(ACK)](https://aws-controllers-k8s.github.io/community/docs/community/overview/) 또는 [Crossplane](https://docs.crossplane.io/latest/packages/providers/)을 사용하여 Kubernetes API로 Lambda 함수를 배포하고 관리할 수 있습니다.

## AWS Controllers for Kubernetes(ACK)
<a name="kubernetes-ack"></a>

ACK를 사용하여 Kubernetes API에서 AWS 리소스를 배포하고 관리할 수 있습니다. AWS는 ACK를 통해 Lambda, Amazon Elastic Container Registry(Amazon ECR), Amazon Simple Storage Service(Amazon S3), Amazon SageMaker AI 등의 AWS 서비스용 오픈 소스 사용자 지정 컨트롤러를 제공합니다. 지원되는 각 AWS 서비스에는 자체 사용자 지정 컨트롤러가 있습니다. Kubernetes 클러스터에서 사용하려는 각 AWS 서비스에 대한 컨트롤러를 설치합니다. 그런 다음 [사용자 지정 리소스 정의(CRD)](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/)를 생성하여 AWS 리소스를 정의합니다.

ACK 컨트롤러를 설치하려면 [Helm 3.8 이상](https://helm.sh/docs/intro/install/)을 사용하는 것이 좋습니다. 모든 ACK 컨트롤러에는 컨트롤러, CRD 및 Kubernetes RBAC 규칙을 설치하는 자체 차트 Helm이 함께 제공됩니다. 자세한 내용은 ACK 설명서의 [Install an ACK Controller](https://aws-controllers-k8s.github.io/community/docs/user-docs/install/)를 참조하세요.

ACK 사용자 지정 리소스를 생성한 후에는 다른 기본 제공 Kubernetes 객체처럼 사용할 수 있습니다. 예를 들어, [kubectl](https://kubernetes.io/docs/reference/kubectl/) 등의 선호하는 Kubernetes 도구 체인을 사용하여 Lambda 함수를 배포하고 관리할 수 있습니다.

다음은 ACK를 통해 Lambda 함수를 프로비저닝하는 몇 가지 사용 사례입니다.
+ 조직에서는 [서비스 계정에 대한 IAM 역할](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)과 [역할 기반 액세스 제어(RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)를 사용하여 권한 경계를 생성합니다. ACK를 사용하면 새로운 사용자와 정책을 생성할 필요 없이 Lambda에 대해 이 보안 모델을 재사용할 수 있습니다.
+ 조직에는 Kubernetes 매니페스트를 사용하여 Amazon Elastic Kubernetes Service(Amazon EKS) 클러스터에 리소스를 배포하는 DevOps 프로세스가 있습니다. ACK를 사용하면 별도의 인프라를 코드 템플릿으로 생성하지 않고도 매니페스트를 사용하여 Lambda 함수를 프로비저닝할 수 있습니다.

ACK 사용에 대한 자세한 내용은 [ACK 설명서의 Lambda 자습서](https://aws-controllers-k8s.github.io/community/docs/tutorials/lambda-oci-example/)를 참조하세요.

## Crossplane
<a name="kubernetes-crossplane"></a>

[Crossplane](https://docs.crossplane.io/latest/packages/providers/)은 Kubernetes를 사용하여 클라우드 인프라 리소스를 관리하는 오픈 소스 CNCF(Cloud Native Computing Foundation) 프로젝트입니다. Crossplane로 개발자는 인프라의 복잡성을 이해할 필요 없이 인프라를 요청할 수 있습니다. 플랫폼 팀이 인프라 프로비저닝 및 관리 방법에 대한 통제권을 갖습니다.

Crossplane을 사용하면 [kubectl](https://kubernetes.io/docs/reference/kubectl/)과 같은 선호하는 Kubernetes 도구 체인과 Kubernetes에 매니페스트를 배포할 수 있는 모든 CI/CD 파이프라인을 사용하여 Lambda 함수를 배포하고 관리할 수 있습니다. 다음은 Crossplane을 통해 Lambda 함수를 프로비저닝하는 몇 가지 사용 사례입니다.
+ 조직에서 Lambda 함수에 올바른 [태그](configuration-tags.md)가 있는지 확인하여 규정 준수를 시행하려고 합니다. 플랫폼 팀이 [Crossplane Compositions](https://docs.crossplane.io/latest/get-started/get-started-with-composition/)를 사용하여 API 추상화를 통해 이 정책을 정의할 수 있습니다. 그러면 개발자가 이러한 추상화를 사용하여 태그가 있는 Lambda 함수를 배포할 수 있습니다.
+ 프로젝트에서는 Kubernetes와 함께 GitOps를 사용합니다. 이 모델에서 Kubernetes는 git 리포지토리(원하는 상태)를 클러스터 내에서 실행되는 리소스(현재 상태)와 지속적으로 조정합니다. 차이가 있는 경우 GitOps 프로세스가 클러스터를 자동으로 변경합니다. [CRDs](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/), [Controllers](https://kubernetes.io/docs/concepts/architecture/controller/) 등의 친숙한 Kubernetes 도구와 개념을 사용하여 Crossplane을 통해 Lambda 기능을 배포하고 관리하는 데 Kubernetes와 함께 GitOps를 사용할 수 있습니다.

Lambda와 함께 Crossplane을 사용하는 방법에 대해 자세히 알아보려면 다음을 참조하세요.
+ [AWS Blueprints for Crossplane](https://github.com/awslabs/crossplane-on-eks/blob/main/examples/upbound-aws-provider/README.md#deploy-the-examples): 이 리포지토리에는 Crossplane을 사용하여 Lambda 함수를 비롯한 AWS 리소스를 배포하는 방법에 대한 예제가 포함되어 있습니다.
**참고**  
AWS Blueprints for Crossplane는 현재 개발 중이므로 프로덕션에 사용해서는 안 됩니다.
+ [Deploying Lambda with Amazon EKS and Crossplane](https://www.youtube.com/watch?v=m-9KLq29K4k): 이 동영상에서는 개발자와 플랫폼 관점에서 설계를 살펴보면서 Crossplane을 사용하여 AWS 서버리스 아키텍처를 배포하는 고급 예제를 보여줍니다.

# Amazon MQ에서 Lambda 사용
<a name="with-mq"></a>

**참고**  
Lambda 함수 이외의 대상으로 데이터를 전송하거나 데이터를 전송하기 전에 데이터를 보강하려는 경우 [Amazon EventBridge 파이프](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes.html)를 참조하세요.

Amazon MQ는 [Apache ActiveMQ](https://activemq.apache.org/) 및 [RabbitMQ](https://www.rabbitmq.com)를 위한 관리형 메시지 브로커 서비스입니다. *메시지 브로커*를 사용하면 소프트웨어 애플리케이션 및 구성 요소가 토픽 또는 대기열 이벤트 대상을 통해 다양한 프로그래밍 언어, 운영 체제 및 공식 메시징 프로토콜을 사용하여 통신할 수 있습니다.

Amazon MQ는 ActiveMQ 또는 RabbitMQ 브로커를 설치하고 다른 네트워크 토폴로지 및 기타 인프라 요구 사항을 제공하여 사용자 대신 Amazon Elastic Compute Cloud(Amazon EC2) 인스턴스를 관리할 수도 있습니다.

Lambda 함수를 사용하여 Amazon MQ 메시지 브로커의 레코드를 처리할 수 있습니다. Lambda는 [이벤트 소스 매핑](invocation-eventsourcemapping.md)을 통해 함수를 간접 호출합니다. 이 매핑은 브로커로부터 메시지를 읽고 함수를 [동기식으로](invocation-sync.md) 간접 호출하는 Lambda 리소스입니다.

**주의**  
Lambda 이벤트 소스 매핑은 각 이벤트를 한 번 이상 처리하므로 레코드가 중복될 수 있습니다. 중복 이벤트와 관련된 잠재적 문제를 방지하려면 함수 코드를 멱등성으로 만드는 것이 좋습니다. 자세한 내용은 AWS 지식 센터의 [함수를 멱등성 Lambda 함수로 만들려면 어떻게 해야 하나요?](https://repost.aws/knowledge-center/lambda-function-idempotent)를 참조하세요.

Amazon MQ 이벤트 소스 매핑에는 다음과 같은 구성 제한 사항이 있습니다.
+ 동시성 — Amazon MQ 이벤트 소스 매핑을 사용하는 Lambda 함수에는 기본 최대 [동시성](lambda-concurrency.md) 설정이 있습니다. ActiveMQ의 경우, Lambda 서비스는 동시 실행 환경 수를 Amazon MQ 이벤트 소스 매핑당 5개로 제한합니다. RabbitMQ의 경우, 동시 실행 환경 수는 Amazon MQ 이벤트 소스 매핑당 1개로 제한됩니다. 함수의 예약되거나 프로비저닝된 동시성 설정을 변경하더라도 Lambda 서비스가 더 많은 실행 환경을 사용할 수 있게 해 주지는 않습니다. 단일 Amazon MQ 이벤트 소스 매핑에 대한 기본 최대 동시성의 증가를 요청하려면, 이벤트 소스 매핑 UUID 및 리전을 가지고 지원에 문의하세요. 증가는 계정 또는 리전 수준이 아닌 특정 이벤트 소스 매핑 수준에서 적용되므로, 각 이벤트 소스 매핑에 대한 규모 조정 증가를 수동으로 요청해야 합니다.
+ 교차 계정 - Lambda는 교차 계정 처리를 지원하지 않습니다. Lambda를 사용하여 다른 AWS 계정에 있는 Amazon MQ 메시지 브로커의 레코드를 처리할 수 없습니다.
+ 인증 - ActiveMQ의 경우 ActiveMQ [SimpleAuthenticationPlugin](https://activemq.apache.org/security#simple-authentication-plugin)만 지원됩니다. RabbitMQ의 경우 [PLAIN](https://www.rabbitmq.com/access-control.html#mechanisms) 인증 메커니즘만 지원됩니다. 사용자는 AWS Secrets Manager를 사용해 자신의 자격 증명을 관리해야 합니다. ActiveMQ 인증에 대한 자세한 내용은 *Amazon MQ 개발자 안내서*의 [ActiveMQ 브로커와 LDAP 통합](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/security-authentication-authorization.html)을 참조하세요.
+ 연결 할당량 - 브로커에는 와이어 레벨 프로토콜당 허용되는 최대 연결 수가 있습니다. 이 할당량은 브로커 인스턴스 유형에 따라 결정됩니다. 자세한 내용은 *Amazon MQ 개발자 안내서*에서 **Amazon MQ의 할당량**의 [브로커](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-limits.html#broker-limits) 단원을 참조하세요.
+ 연결성 - 퍼블릭 또는 프라이빗 Virtual Private Cloud(VPC)에서 브로커를 생성할 수 있습니다. 프라이빗 VPC의 경우 레코드와 상호 작용하려면 Lambda 함수에게 메시지를 수신하는 VPC에 대한 액세스 권한이 있어야 합니다. 자세한 내용은 이 [네트워크 보안 구성](process-mq-messages-with-lambda.md#process-mq-messages-with-lambda-networkconfiguration) 단원의 뒷부분을 참조하세요.
+ 이벤트 대상 - 대기열 대상만 지원됩니다. 그러나 Lambda와 상호 작용하는 동안 내부적으로 토픽으로 동작하는 가상 토픽을 대기열로 사용할 수 있습니다. 자세한 내용은 Apache ActiveMQ 웹사이트의 [가상 대상](https://activemq.apache.org/virtual-destinations)과 RabbitMQ의 [가상 호스트](https://www.rabbitmq.com/vhosts.html)를 참조하세요.
+ 네트워크 토폴로지 - ActiveMQ의 경우 이벤트 소스 매핑당 하나의 단일 인스턴스 또는 대기 브로커만 지원됩니다. RabbitMQ의 경우 이벤트 소스 매핑당 하나의 단일 인스턴스 브로커 또는 클러스터 배포만 지원됩니다. 단일 인스턴스 브로커에는 장애 조치 엔드포인트가 필요합니다. 이러한 브로커 배포 모드에 대한 자세한 내용은 *Amazon MQ 개발자 안내서*에서 [Active MQ 브로커 아키텍쳐](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-broker-architecture.html) 및 [Rabbit MQ 브로커 아키텍쳐](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/rabbitmq-broker-architecture.html)를 참조하세요.
+ 프로토콜 - 지원되는 프로토콜은 Amazon MQ 통합 유형에 따라 다릅니다.
  + ActiveMQ 통합의 경우 Lambda는 OpenWire/Java Message Service(JMS) 프로토콜을 사용하여 메시지를 소비합니다. 메시지 소비를 위한 다른 프로토콜은 지원되지 않습니다. JMS 프로토콜 내에서 [https://activemq.apache.org/components/cms/api_docs/activemqcpp-3.6.0/html/classactivemq_1_1commands_1_1_active_m_q_text_message.html](https://activemq.apache.org/components/cms/api_docs/activemqcpp-3.6.0/html/classactivemq_1_1commands_1_1_active_m_q_text_message.html) 및 [https://activemq.apache.org/components/cms/api_docs/activemqcpp-3.9.0/html/classactivemq_1_1commands_1_1_active_m_q_bytes_message.html](https://activemq.apache.org/components/cms/api_docs/activemqcpp-3.9.0/html/classactivemq_1_1commands_1_1_active_m_q_bytes_message.html)만 지원됩니다. Lambda는 JMS 사용자 지정 속성도 지원합니다. OpenWire 프로토콜에 대한 자세한 내용은 Apache ActiveMQ 웹 사이트에서 [OpenWire](https://activemq.apache.org/openwire.html)를 참조하세요.
  + RabbitMQ 통합의 경우 Lambda는 AMQP 0-9-1 프로토콜을 사용하여 메시지를 소비합니다. 메시지 소비를 위한 다른 프로토콜은 지원되지 않습니다. RabbitMQ의 AMQP 0-9-1 프로토콜 구현에 대한 자세한 내용은 RabbitMQ 웹사이트의 [AMQP 0-9-1 전체 참조 가이드](https://www.rabbitmq.com/amqp-0-9-1-reference.html)를 참조하세요.

Lambda는 Amazon MQ가 지원하는 최신 버전의 ActiveMQ 및 RabbitMQ를 자동으로 지원합니다. 지원되는 최신 버전은 *Amazon MQ 개발자 가이드*의 [Amazon MQ 릴리스 노트](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-release-notes.html)를 참조하세요 

**참고**  
기본적으로 Amazon MQ에는 브로커에 대한 주별 유지 관리 기간이 있습니다. 해당 기간 동안에는 브로커를 사용할 수 없습니다. 예비 인스턴스가 없는 브로커의 경우 Lambda가 해당 기간 동안 메시지를 처리할 수 없습니다.

**Topics**
+ [

## Amazon MQ의 Lambda 소비자 그룹에 대한 이해
](#services-mq-configure)
+ [

# Lambda용 Amazon MQ 이벤트 소스 구성
](process-mq-messages-with-lambda.md)
+ [

# 이벤트 소스 매핑 파라미터
](services-mq-params.md)
+ [

# Amazon MQ 이벤트 소스에서 이벤트 필터링
](with-mq-filtering.md)
+ [

# Amazon MQ 이벤트 소스 매핑 오류에 대한 문제 해결
](services-mq-errors.md)

## Amazon MQ의 Lambda 소비자 그룹에 대한 이해
<a name="services-mq-configure"></a>

Amazon MQ와 상호 작용하기 위해 Lambda는 Amazon MQ 브로커에서 읽을 수 있는 소비자 그룹을 생성합니다. 소비자 그룹은 이벤트 소스 매핑 UUID와 동일한 ID를 사용하여 생성됩니다.

Amazon MQ 이벤트 소스의 경우 Lambda에서 레코드를 일괄 처리하여 단일 페이로드로 함수에 전송합니다. 동작을 제어하려면 일괄 처리 기간 및 배치 크기를 구성할 수 있습니다. Lambda는 페이로드 크기 최댓값인 6MB이 처리되거나 일괄 처리 기간이 만료되거나 레코드 수가 전체 배치 크기에 도달할 때까지 메시지를 가져옵니다. 자세한 내용은 [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching) 섹션을 참조하세요.

소비자 그룹은 메시지를 바이트의 BLOB로 검색하고 단일 JSON 페이로드에 base64로 인코딩한 다음, 함수를 간접 호출합니다. 함수가 배치의 어떤 메시지에 대해 오류를 반환하면 Lambda는 처리가 성공하거나 메시지가 만료될 때까지 전체 메시지 배치를 다시 시도합니다.

**참고**  
Lambda 함수의 최대 제한 시간은 일반적으로 15분이지만 Amazon MSK, 자체 관리형 Apache Kafka, Amazon DocumentDB, ActiveMQ 및 RabbitMQ용 Amazon MQ에 대한 이벤트 소스 매핑은 최대 제한 시간이 14분인 함수만 지원합니다. 이 제약 조건에 따라 이벤트 소스 매핑에서 함수 오류 및 재시도를 적절히 처리할 수 있습니다.

Amazon CloudWatch의 `ConcurrentExecutions` 지표를 사용하여 지정된 함수의 동시성 사용량을 모니터링할 수 있습니다. 동시성에 대한 자세한 내용은 [함수에 대해 예약된 동시성 구성](configuration-concurrency.md) 단원을 참조하세요.

**Example Amazon MQ 레코드 이벤트**  

```
{
   "eventSource": "aws:mq",
   "eventSourceArn": "arn:aws:mq:us-east-2:111122223333:broker:test:b-9bcfa592-423a-4942-879d-eb284b418fc8",
   "messages": [
      { 
        "messageID": "ID:b-9bcfa592-423a-4942-879d-eb284b418fc8-1---mq---us-east-2.amazonaws.com.rproxy.goskope.com-37557-1234520418293-4:1:1:1:1", 
        "messageType": "jms/text-message",
        "deliveryMode": 1,
        "replyTo": null,
        "type": null,
        "expiration": "60000",
        "priority": 1,
        "correlationId": "myJMSCoID",
        "redelivered": false,
        "destination": { 
          "physicalName": "testQueue" 
        },
        "data":"QUJDOkFBQUE=",
        "timestamp": 1598827811958,
        "brokerInTime": 1598827811958, 
        "brokerOutTime": 1598827811959, 
        "properties": {
          "index": "1",
          "doAlarm": "false",
          "myCustomProperty": "value"
        }
      },
      { 
        "messageID": "ID:b-9bcfa592-423a-4942-879d-eb284b418fc8-1---mq---us-east-2.amazonaws.com.rproxy.goskope.com-37557-1234520418293-4:1:1:1:1",
        "messageType": "jms/bytes-message",
        "deliveryMode": 1,
        "replyTo": null,
        "type": null,
        "expiration": "60000",
        "priority": 2,
        "correlationId": "myJMSCoID1",
        "redelivered": false,
        "destination": { 
          "physicalName": "testQueue" 
        },
        "data":"LQaGQ82S48k=",
        "timestamp": 1598827811958,
        "brokerInTime": 1598827811958, 
        "brokerOutTime": 1598827811959, 
        "properties": {
          "index": "1",
          "doAlarm": "false",
          "myCustomProperty": "value"
        }
      }
   ]
}
```

```
{
  "eventSource": "aws:rmq",
  "eventSourceArn": "arn:aws:mq:us-east-2:111122223333:broker:pizzaBroker:b-9bcfa592-423a-4942-879d-eb284b418fc8",
  "rmqMessagesByQueue": {
    "pizzaQueue::/": [
      {
        "basicProperties": {
          "contentType": "text/plain",
          "contentEncoding": null,
          "headers": {
            "header1": {
              "bytes": [
                118,
                97,
                108,
                117,
                101,
                49
              ]
            },
            "header2": {
              "bytes": [
                118,
                97,
                108,
                117,
                101,
                50
              ]
            },
            "numberInHeader": 10
          },
          "deliveryMode": 1,
          "priority": 34,
          "correlationId": null,
          "replyTo": null,
          "expiration": "60000",
          "messageId": null,
          "timestamp": "Jan 1, 1970, 12:33:41 AM",
          "type": null,
          "userId": "AIDACKCEVSQ6C2EXAMPLE",
          "appId": null,
          "clusterId": null,
          "bodySize": 80
        },
        "redelivered": false,
        "data": "eyJ0aW1lb3V0IjowLCJkYXRhIjoiQ1pybWYwR3c4T3Y0YnFMUXhENEUifQ=="
      }
    ]
  }
}
```
RabbitMQ 예제에서 `pizzaQueue`는 RabbitMQ 대기열의 이름이고 `/`는 가상 호스트의 이름입니다. 메시지를 받을 때 이벤트 소스는 `pizzaQueue::/`에 메시지를 나열합니다.

# Lambda용 Amazon MQ 이벤트 소스 구성
<a name="process-mq-messages-with-lambda"></a>

**Topics**
+ [

## 네트워크 보안 구성
](#process-mq-messages-with-lambda-networkconfiguration)
+ [

## 이벤트 소스 매핑 생성
](#services-mq-eventsourcemapping)

## 네트워크 보안 구성
<a name="process-mq-messages-with-lambda-networkconfiguration"></a>

이벤트 소스 매핑을 통해 Lambda에 Amazon MQ에 대한 전체 액세스 권한을 부여하려면 브로커가 퍼블릭 엔드포인트(퍼블릭 IP 주소)를 사용하거나 브로커를 생성한 Amazon VPC에 대한 액세스 권한을 제공해야 합니다.

Lambda에서 Amazon MQ를 사용하는 경우 Amazon VPC의 리소스에 대한 액세스 권한을 제공하는 [AWS PrivateLink VPC 엔드포인트](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html)를 생성합니다.

**참고**  
이벤트 폴러에 기본(온디맨드) 모드를 사용하는 이벤트 소스 매핑을 포함하는 함수에 대해 AWS PrivateLink VPC 엔드포인트가 필요합니다. 이벤트 소스 매핑에서 [프로비저닝된 모드](invocation-eventsourcemapping.md#invocation-eventsourcemapping-provisioned-mode)를 사용하는 경우 AWS PrivateLink VPC 엔드포인트를 구성하지 않아도 됩니다.

다음 리소스에 대한 액세스를 제공하는 엔드포인트를 생성합니다.
+  Lambda - Lambda 서비스 위탁자에 대한 엔드포인트를 생성합니다.
+  AWS STS - 서비스 위탁자가 사용자를 대신하여 역할을 맡을 수 있도록 AWS STS에 대한 엔드포인트를 생성합니다.
+  Secrets Manager - 브로커에서 Secrets Manager를 사용하여 자격 증명을 저장하는 경우 Secrets Manager를 위한 엔드포인트를 생성합니다.

또는 Amazon VPC의 각 퍼블릭 서브넷에 NAT 게이트웨이를 구성합니다. 자세한 내용은 [VPC 연결 Lambda 함수에 대한 인터넷 액세스 활성화](configuration-vpc-internet.md) 섹션을 참조하세요.

Amazon MQ에 대한 이벤트 소스 매핑을 생성하면 Lambda는 Amazon VPC에 대해 구성된 서브넷과 보안 그룹을 위한 탄력적 네트워크 인터페이스(ENI)가 이미 존재하는지 확인합니다. Lambda가 기존 ENI를 찾으면 이를 재사용하려고 시도합니다. 그렇지 않으면 Lambda가 이벤트 소스에 연결하고 함수를 간접 호출하기 위해 새 ENI를 생성합니다.

**참고**  
Lambda 함수는 항상 Lambda 서비스가 소유한 VPC 내에서 실행됩니다. 함수의 VPC 구성은 이벤트 소스 매핑에 영향을 미치지 않습니다. 이벤트 소스의 네트워킹 구성에 따라 Lambda가 이벤트 소스에 연결하는 방식이 결정됩니다.

브로커가 포함된 Amazon VPC에 대한 보안 그룹을 구성합니다. 기본적으로 Amazon MQ는 `61617`(ActiveMQ용 Amazon MQ) 및 `5671`(RabbitMQ용 Amazon MQ) 포트를 사용합니다.
+ 인바운드 규칙 – 이벤트 소스와 연결된 보안 그룹에 대한 기본 브로커 포트의 모든 트래픽을 허용합니다. 또는 자체 참조 보안 그룹 규칙을 사용하여 동일한 보안 그룹 내의 인스턴스에서 액세스를 허용할 수 있습니다.
+ 아웃바운드 규칙 - 함수가 AWS 서비스와 통신해야 하는 경우 외부 대상에 대한 포트 `443`의 모든 트래픽을 허용합니다. 다른 AWS 서비스와 통신할 필요가 없는 경우 자체 참조 보안 그룹 규칙을 사용하여 브로커에 대한 액세스를 제한할 수도 있습니다.
+ Amazon VPC 엔드포인트 인바운드 규칙 - Amazon VPC 엔드포인트를 사용하는 경우 Amazon VPC 엔드포인트와 연결된 보안 그룹이 브로커 보안 그룹에서 `443` 포트의 인바운드 트래픽을 허용해야 합니다.

브로커가 인증을 사용하는 경우 Secrets Manager 엔드포인트에 대한 엔드포인트 정책을 제한할 수도 있습니다. Secrets Manager API를 직접 호출하기 위해 Lambda는 Lambda 서비스 위탁자가 아닌 함수 역할을 사용합니다.

**Example VPC 엔드포인트 정책 — Secrets Manager 엔드포인트**  

```
{
      "Statement": [
          {
              "Action": "secretsmanager:GetSecretValue",
              "Effect": "Allow",
              "Principal": {
                  "AWS": [
                      "arn:aws::iam::123456789012:role/my-role"
                  ]
              },
              "Resource": "arn:aws::secretsmanager:us-west-2:123456789012:secret:my-secret"
          }
      ]
  }
```

Amazon VPC 엔드포인트를 사용하는 경우 AWS에서는 엔드포인트의 탄력적 네트워크 인터페이스(ENI)를 사용하여 함수를 간접 호출하도록 API 직접 호출을 라우팅합니다. Lambda 서비스 위탁자는 해당 ENI를 사용하는 모든 역할과 함수에서 `lambda:InvokeFunction`을 직접 호출해야 합니다.

기본적으로 Amazon VPC 엔드포인트에는 리소스에 대한 광범위한 액세스를 허용하는 개방형 IAM 정책이 있습니다. 모범 사례는 해당 엔드포인트를 사용하여 필요한 작업을 수행하도록 이러한 정책을 제한하는 것입니다. 이벤트 소스 매핑이 Lambda 함수를 간접 호출할 수 있도록 하려면 VPC 엔드포인트 정책에서 Lambda 서비스 위탁자가 `sts:AssumeRole` 및 `lambda:InvokeFunction`을 직접 호출할 수 있도록 허용해야 합니다. 조직 내에서 발생하는 API 직접 호출만 허용하도록 VPC 엔드포인트 정책을 제한하면 이벤트 소스 매핑이 제대로 작동하지 않으므로 이 정책에는 `"Resource": "*"`가 필요합니다.

다음 예제 VPC 엔드포인트 정책은 AWS STS 및 Lambda 엔드포인트에 대해 Lambda 서비스 위탁자에 필요한 액세스 권한을 부여하는 방법을 안내합니다.

**Example VPC 엔드포인트 정책 - AWS STS 엔드포인트**  

```
{
      "Statement": [
          {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
    }
```

**Example VPC 엔드포인트 정책 - Lambda 엔드포인트**  

```
{
      "Statement": [
          {
              "Action": "lambda:InvokeFunction",
              "Effect": "Allow",
              "Principal": {
                  "Service": [
                      "lambda.amazonaws.com"
                  ]
              },
              "Resource": "*"
          }
      ]
  }
```

## 이벤트 소스 매핑 생성
<a name="services-mq-eventsourcemapping"></a>

[이벤트 소스 매핑](invocation-eventsourcemapping.md)을 생성하여 Lambda가 Amazon MQ 브로커의 레코드를 Lambda 함수로 전송하도록 지시합니다. 여러 이벤트 소스 매핑을 생성하여 여러 함수로 동일한 데이터를 처리하거나, 단일 함수로 여러 소스의 항목을 처리할 수 있습니다.

Amazon MQ에서 읽도록 함수를 구성하려면 필요한 권한을 추가하고 Lambda 콘솔에서 **MQ** 트리거를 생성합니다.

Amazon MQ 브로커에서 레코드를 읽으려면, Lambda 함수에는 다음 권한이 필요합니다. 함수 [실행 역할](lambda-intro-execution-role.md)에 권한 문을 추가함으로써 Amazon MQ 브로커 및 기본 리소스와 상호 작용할 수 있는 권한을 Lambda에 부여합니다.
+ [mq:DescribeBroker](https://docs.aws.amazon.com/amazon-mq/latest/api-reference/brokers-broker-id.html#brokers-broker-id-http-methods)
+ [secretsmanager:GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html)
+ [ec2:CreateNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html)
+ [ec2:DeleteNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkInterface.html)
+ [ec2:DescribeNetworkInterfaces](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html)
+ [ec2:DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)
+ [ec2:DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
+ [ec2:DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
+ [logs:CreateLogGroup](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html)
+ [logs:CreateLogStream](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogStream.html)
+ [logs:PutLogEvents](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html)

**참고**  
암호화된 고객 관리형 키를 사용하는 경우 `[kms:Decrypt](https://docs.aws.amazon.com/msk/1.0/apireference/clusters-clusterarn-bootstrap-brokers.html#clusters-clusterarn-bootstrap-brokersget)` 권한도 추가합니다.

**권한 추가 및 트리거 생성**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

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

1. **구성(Configuration)** 탭을 선택한 다음, **권한(Permissions)**을 선택합니다.

1. **역할 이름**에서 실행 역할에 대한 링크를 선택합니다. 이 링크를 클릭하면 IAM 콘솔에서 역할이 열립니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/execution-role.png)

1. **권한 추가**를 선택하고 **인라인 정책 생성**을 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/inline-policy.png)

1. **정책 편집기** 섹션에서 **JSON**을 선택합니다. 다음 정책을 입력합니다. 함수가 Amazon MQ 브로커에서 읽으려면 이러한 권한이 필요합니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
         {
           "Effect": "Allow",
           "Action": [
             "mq:DescribeBroker",
             "secretsmanager:GetSecretValue",
             "ec2:CreateNetworkInterface",
             "ec2:DeleteNetworkInterface",
             "ec2:DescribeNetworkInterfaces", 
             "ec2:DescribeSecurityGroups",
             "ec2:DescribeSubnets",
             "ec2:DescribeVpcs",
             "logs:CreateLogGroup",
             "logs:CreateLogStream", 
             "logs:PutLogEvents"		
           ],
           "Resource": "*"
         }
       ]
     }
   ```

------
**참고**  
암호화된 고객 관리형 키를 사용하는 경우 `kms:Decrypt` 권한도 추가해야 합니다.

1. **다음**을 선택합니다. 정책 이름을 입력한 후 **정책 생성**을 선택합니다.

1. Lambda 콘솔에서 함수로 돌아갑니다. **함수 개요(Function overview)**에서 **트리거 추가(Add trigger)**를 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/add-trigger.png)

1. **MQ** 트리거 유형을 선택합니다.

1. 필요한 옵션을 구성한 다음 **추가**를 선택합니다.

Lambda는 Amazon MQ 이벤트 소스에 대해 다음과 같은 옵션을 지원합니다.
+ **브로커** - Amazon MQ 브로커를 선택합니다.
+ **배치 크기(Batch size)** - 단일 배치에서 검색할 최대 메시지 수를 설정합니다.
+ **대기열 이름(Queue name)** - 사용할 Amazon MQ 대기열을 입력합니다.
+ **소스 액세스 구성** - 가상 호스트 정보 및 브로커 자격 증명을 저장하는 Secrets Manager 암호를 입력합니다.
+ **트리거 활성화** - 레코드 처리를 중지하려면 트리거를 비활성화합니다.

트리거를 활성화하거나 비활성화(또는 삭제)하려면 디자이너에서 **MQ** 트리거를 선택합니다. 트리거를 재구성하려면 이벤트 소스 매핑 API 작업을 사용합니다.

# 이벤트 소스 매핑 파라미터
<a name="services-mq-params"></a>

모든 Lambda 이벤트 소스 유형은 동일한 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 및 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 작업을 공유합니다. 그러나 일부 파라미터만 Amazon MQ 및 RabbitMQ에 적용됩니다.


| 파라미터 | 필수 | 기본값 | 참고 | 
| --- | --- | --- | --- | 
|  BatchSize  |  N  |  100  |  최대값: 10,000  | 
|  활성  |  N  |  true  | 없음 | 
|  FunctionName  |  Y  | N/A  | 없음 | 
|  FilterCriteria  |  N  |  N/A   |  [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)  | 
|  MaximumBatchingWindowInSeconds  |  N  |  500ms  |  [일괄 처리 동작](invocation-eventsourcemapping.md#invocation-eventsourcemapping-batching)  | 
|  대기열  |  N  | N/A |  소비할 Amazon MQ 브로커 대상 대기열의 이름입니다.  | 
|  SourceAccessConfigurations  |  N  | N/A  |  ActiveMQ의 BASIC\$1AUTH 자격 증명입니다. RabbitMQ는 BASIC\$1AUTH 자격 증명과 VIRTUAL\$1HOST 정보를 모두 포함할 수 있습니다.  | 

# Amazon MQ 이벤트 소스에서 이벤트 필터링
<a name="with-mq-filtering"></a>

이벤트 필터링을 사용하여 Lambda가 함수로 전송하는 스트림 또는 대기열의 레코드를 제어할 수 있습니다. 이벤트 필터링의 작동 방식에 대한 일반적인 내용은 [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)을 참조하세요.

이 섹션에서는 Amazon MQ 이벤트 소스에 대한 이벤트 필터링에 중점을 둡니다.

**참고**  
Amazon MQ 이벤트 소스 매핑은 `data` 키에 대한 필터링만 지원합니다.

**Topics**
+ [

## Amazon MQ 이벤트 필터링 기본 사항
](#filtering-AMQ)

## Amazon MQ 이벤트 필터링 기본 사항
<a name="filtering-AMQ"></a>

Amazon MQ 메시지 대기열에 유효한 JSON 형식 또는 일반 문자열의 메시지가 포함되어 있다고 가정해 보겠습니다. 예제 레코드는 다음과 같으며, 데이터는 `data` 필드에서 Base64로 인코딩된 문자열로 변환됩니다.

------
#### [ ActiveMQ ]

```
{ 
    "messageID": "ID:b-9bcfa592-423a-4942-879d-eb284b418fc8-1---mq---us-east-2.amazonaws.com.rproxy.goskope.com-37557-1234520418293-4:1:1:1:1", 
    "messageType": "jms/text-message",
    "deliveryMode": 1,
    "replyTo": null,
    "type": null,
    "expiration": "60000",
    "priority": 1,
    "correlationId": "myJMSCoID",
    "redelivered": false,
    "destination": { 
      "physicalName": "testQueue" 
    },
    "data":"QUJDOkFBQUE=",
    "timestamp": 1598827811958,
    "brokerInTime": 1598827811958, 
    "brokerOutTime": 1598827811959, 
    "properties": {
      "index": "1",
      "doAlarm": "false",
      "myCustomProperty": "value"
    }
}
```

------
#### [ RabbitMQ ]

```
{
    "basicProperties": {
        "contentType": "text/plain",
        "contentEncoding": null,
        "headers": {
            "header1": {
                "bytes": [
                  118,
                  97,
                  108,
                  117,
                  101,
                  49
                ]
            },
            "header2": {
                "bytes": [
                  118,
                  97,
                  108,
                  117,
                  101,
                  50
                ]
            },
            "numberInHeader": 10
        },
        "deliveryMode": 1,
        "priority": 34,
        "correlationId": null,
        "replyTo": null,
        "expiration": "60000",
        "messageId": null,
        "timestamp": "Jan 1, 1970, 12:33:41 AM",
        "type": null,
        "userId": "AIDACKCEVSQ6C2EXAMPLE",
        "appId": null,
        "clusterId": null,
        "bodySize": 80
        },
    "redelivered": false,
    "data": "eyJ0aW1lb3V0IjowLCJkYXRhIjoiQ1pybWYwR3c4T3Y0YnFMUXhENEUifQ=="
}
```

------

Active MQ 및 Rabbit MQ 브로커 모두에 이벤트 필터링을 사용하여 `data` 키로 레코드를 필터링할 수 있습니다. Amazon MQ 대기열에 다음 JSON 형식의 메시지가 포함되어 있다고 가정해 보겠습니다.

```
{
    "timeout": 0,
    "IPAddress": "203.0.113.254"
}
```

`timeout` 필드가 0보다 큰 레코드만 필터링하려는 경우 `FilterCriteria` 객체는 다음과 같습니다.

```
{
    "Filters": [
        {
            "Pattern": "{ \"data\" : { \"timeout\" : [ { \"numeric\": [ \">\", 0] } } ] } }"
        }
    ]
}
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{
    "data": {
        "timeout": [ { "numeric": [ ">", 0 ] } ]
        }
}
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "data" : { "timeout" : [ { "numeric": [ ">", 0 ] } ] } }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:mq:us-east-2:123456789012:broker:my-broker:b-8ac7cc01-5898-482d-be2f-a6b596050ea8 \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"timeout\" : [ { \"numeric\": [ \">\", 0 ] } ] } }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"timeout\" : [ { \"numeric\": [ \">\", 0 ] } ] } }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : { \"timeout\" : [ { \"numeric\": [ \">\", 0 ] } ] } }"}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
  Filters:
    - Pattern: '{ "data" : { "timeout" : [ { "numeric": [ ">", 0 ] } ] } }'
```

------

Amazon MQ를 사용하면 메시지가 일반 문자열인 레코드를 필터링할 수도 있습니다. 메시지가 'Result:'로 시작하는 레코드만 처리하려고 한다고 가정해 보겠습니다. `FilterCriteria` 객체는 다음과 같습니다.

```
{
    "Filters": [
        {
            "Pattern": "{ \"data\" : [ { \"prefix\": \"Result: \" } ] }"
        }
    ]
}
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{
    "data": [
        {
        "prefix": "Result: "
        }
    ]
}
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "data" : [ { "prefix": "Result: " } ] }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:mq:us-east-2:123456789012:broker:my-broker:b-8ac7cc01-5898-482d-be2f-a6b596050ea8 \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : [ { \"prefix\": \"Result: \" } ] }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"data\" : [ { \"prefix\": \"Result: \" } ] }"}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
  Filters:
    - Pattern: '{ "data" : [ { "prefix": "Result " } ] }'
```

------

Amazon MQ 메시지는 UTF-8 인코딩 문자열이어야 하며, 일반 문자열이거나 JSON 형식이어야 합니다. 이는 Lambda가 필터 기준을 적용하기 전에 Amazon MQ 바이트 배열을 UTF-8로 디코딩하기 때문입니다. 메시지가 UTF-16 또는 ASCII와 같은 다른 인코딩을 사용하거나 메시지 형식이 `FilterCriteria` 형식과 일치하지 않는 경우 Lambda는 메타데이터 필터만 처리합니다. 다음 표에는 특정 동작이 요약되어 있습니다.


| 수신 메시지 형식 | 메시지 속성에 대한 필터 패턴 형식 | 결과적 작업 | 
| --- | --- | --- | 
|  일반 문자열  |  일반 문자열  |  Lambda는 필터 기준에 따라 필터링합니다.  | 
|  일반 문자열  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  일반 문자열  |  유효한 JSON  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  유효한 JSON  |  일반 문자열  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  유효한 JSON  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  유효한 JSON  |  유효한 JSON  |  Lambda는 필터 기준에 따라 필터링합니다.  | 
|  UTF-8이 아닌 인코딩 문자열  |  JSON, 일반 문자열 또는 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 

# Amazon MQ 이벤트 소스 매핑 오류에 대한 문제 해결
<a name="services-mq-errors"></a>

Lambda 함수에 복구할 수 없는 오류가 발생하면 Amazon MQ 소비자가 레코드 처리를 중지합니다. 다른 소비자는 동일한 오류가 발생하지 않는 한 처리를 계속할 수 있습니다. 중지된 소비자의 잠재적 원인을 확인하려면 `StateTransitionReason`의 반환 세부 정보에서 다음 코드 중 하나에 대한 `EventSourceMapping` 필드를 확인하세요.

**`ESM_CONFIG_NOT_VALID`**  
이벤트 소스 매핑 구성이 잘못되었습니다.

**`EVENT_SOURCE_AUTHN_ERROR`**  
Lambda가 이벤트 소스를 인증하지 못했습니다.

**`EVENT_SOURCE_AUTHZ_ERROR`**  
Lambda에게 이벤트 소스에 액세스하는 데 필요한 권한이 없습니다.

**`FUNCTION_CONFIG_NOT_VALID`**  
함수의 구성이 유효하지 않습니다.

Lambda가 크기 때문에 레코드를 버리는 경우에도 레코드가 처리되지 않습니다. Lambda 레코드의 크기 제한은 6MB입니다. 함수 오류 시 메시지를 다시 전달하려면 배달 못한 편지 대기열(DLQ)을 사용할 수 있습니다. 자세한 내용은 Apache ActiveMQ 웹 사이트에서 [Message Redelivery and DLQ Handling](https://activemq.apache.org/message-redelivery-and-dlq-handling)을, RabbitMQ에서 [Reliability Guide](https://www.rabbitmq.com/reliability.html)를 참조하세요.

**참고**  
Lambda는 사용자 정의 재전달 정책을 지원하지 않습니다. 그 대신 Lambda는 Apache ActiveMQ 웹사이트의 [정책 재전달](https://activemq.apache.org/redelivery-policy) 페이지에 있는 기본값(`maximumRedeliveries`를 6으로 설정)을 사용한 정책을 사용합니다.

# Amazon RDS와 함께 AWS Lambda 사용
<a name="services-rds"></a>

Lambda 함수를 Amazon RDS Proxy를 통해 Amazon Relational Database Service(RDS) 데이터베이스에 직접 연결할 수 있습니다. 간단한 시나리오에서는 직접 연결이 유용하며 프로덕션에서는 프록시를 사용하는 것이 좋습니다. 데이터베이스 프록시는 함수가 데이터베이스 연결을 소진하지 않고 높은 동시성 레벨에 도달할 수 있도록 하는 공유 데이터베이스 연결 풀을 관리합니다.

짧게 데이터베이스를 연결하거나 다수의 데이터베이스 연결을 열고 닫는 Lambda 함수에는 Amazon RDS Proxy를 사용하는 것이 좋습니다. 자세한 내용은 Amazon Relational Database Service 개발자 안내서의 [Lambda 함수와 DB 인스턴스 자동 연결](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/lambda-rds-connect.html)을 참조하세요.

**작은 정보**  
Lambda 함수를 Amazon RDS 데이터베이스에 빠르게 연결하려면 콘솔 내 안내 마법사를 사용할 수 있습니다. 마법사에서 다음을 수행합니다.  
Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.
데이터베이스를 연결할 함수를 선택합니다.
**구성** 탭에서 **RDS 데이터베이스**를 선택합니다.
**RDS 데이터베이스에 연결**을 선택합니다.
함수를 데이터베이스에 연결한 후 **프록시 추가**를 선택하여 프록시를 생성할 수 있습니다.

## RDS 리소스와 함께 작동하도록 함수 구성
<a name="rds-configuration"></a>

Lambda 콘솔에서는 Amazon RDS 데이터베이스 인스턴스와 프록시 리소스를 프로비저닝하고 구성할 수 있습니다. **구성** 탭 아래의 **RDS 데이터베이스**로 이동하여 이 작업을 수행할 수 있습니다. 또는 Amazon RDS 콘솔에서 Lambda 함수에 대한 연결을 생성하고 구성할 수도 있습니다. Lambda와 함께 사용하도록 RDS 데이터베이스 인스턴스를 구성할 때는 다음 기준에 유의하세요.
+ 데이터베이스에 연결하려면 데이터베이스를 실행하는 동일한 Amazon VPC에 함수가 있어야 합니다.
+ MySQL, MariaDB, PostgreSQL 또는 Microsoft SQL Server 엔진과 함께 Amazon RDS 데이터베이스를 사용할 수 있습니다.
+ MySQL 또는 PostgreSQL 엔진과 함께 Aurora DB 클러스터를 사용할 수도 있습니다.
+ 데이터베이스 인증을 위해 Secrets Manager 보안 암호를 제공해야 합니다.
+ IAM 역할은 보안 암호를 사용할 권한을 제공해야 하며, 신뢰 정책에서는 Amazon RDS가 역할을 수임하도록 허용해야 합니다.
+  콘솔을 사용하여 Amazon RDS 리소스를 구성하고 이를 함수에 연결하는 IAM 위탁자에는 다음 권한이 있어야 합니다.

### 권한 정책 예
<a name="rds-lambda-permissions"></a>

**참고**  
 데이터베이스 연결 풀을 관리하기 위해 Amazon RDS Proxy를 구성하는 경우에만 Amazon RDS Proxy 권한이 필요합니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:CreateSecurityGroup",
        "ec2:DescribeSecurityGroups",
        "ec2:DescribeSubnets",
        "ec2:DescribeVpcs",
        "ec2:AuthorizeSecurityGroupIngress",
        "ec2:AuthorizeSecurityGroupEgress",
        "ec2:RevokeSecurityGroupEgress",
        "ec2:CreateNetworkInterface",
        "ec2:DeleteNetworkInterface",
        "ec2:DescribeNetworkInterfaces"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "rds-db:connect",
        "rds:CreateDBProxy",
        "rds:CreateDBInstance",
        "rds:CreateDBSubnetGroup",
        "rds:DescribeDBClusters",
        "rds:DescribeDBInstances",
        "rds:DescribeDBSubnetGroups",
        "rds:DescribeDBProxies",
        "rds:DescribeDBProxyTargets",
        "rds:DescribeDBProxyTargetGroups",
        "rds:RegisterDBProxyTargets",
        "rds:ModifyDBInstance",
        "rds:ModifyDBProxy"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "lambda:CreateFunction",
        "lambda:ListFunctions",
        "lambda:UpdateFunctionConfiguration"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:AttachRolePolicy",
        "iam:CreateRole",
        "iam:CreatePolicy"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecretVersionIds",
        "secretsmanager:CreateSecret"
      ],
      "Resource": "*"
    }
  ]
}
```

------

Amazon RDS는 데이터베이스 인스턴스 크기를 기준으로 프록시에 시간당 요금을 부과합니다. 자세한 내용은 [RDS 프록시 요금](https://aws.amazon.com/rds/proxy/pricing/)을 참조하세요. 일반적인 프록시 연결에 대한 자세한 내용은 Amazon RDS 사용 설명서에서 [Amazon RDS Proxy 사용](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html)을 참조하세요.

### Amazon RDS 연결에 대한 SSL/TLS 요구 사항
<a name="rds-lambda-certificates"></a>

Amazon RDS 데이터베이스 인스턴스에 대한 보안 SSL/TLS 연결을 설정하려면 Lambda 함수에서 신뢰할 수 있는 인증서를 사용하여 데이터베이스 서버의 ID를 확인해야 합니다. Lambda는 배포 패키지 유형에 따라 이러한 인증서를 다르게 처리합니다.
+ [.zip 파일 아카이브](configuration-function-zip.md): 인증서 처리는 런타임에 따라 다릅니다.
  + **Node.js 18 이하**: Lambda에 CA 인증서 및 RDS 인증서가 자동으로 포함됩니다.
  + **Node.js 20 이상**: Lambda는 더 이상 기본적으로 추가 CA 인증서를 로딩하지 않습니다. `NODE_EXTRA_CA_CERTS` 환경 변수를 `/var/runtime/ca-cert.pem`로 설정합니다.

  새 AWS 리전에 대한 Amazon RDS 인증서가 Lambda 관리형 런타임에 추가되는 데 최대 4주까지 소요될 수 있습니다.
+ [컨테이너 이미지](images-create.md): AWS 기본 이미지에는 CA 인증서만 포함됩니다. 함수가 Amazon RDS 데이터베이스 인스턴스에 연결하는 경우 컨테이너 이미지에 적절한 인증서를 포함해야 합니다. Dockerfile에서 [데이터베이스를 호스팅하는 AWS 리전에 해당하는 인증서 번들](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.CertificatesDownload)을 다운로드하세요. 예제:

  ```
  RUN curl https://truststore.pki.rds.amazonaws.com/us-east-1/us-east-1-bundle.pem -o /us-east-1-bundle.pem
  ```

이 명령은 Amazon RDS 인증서 번들을 다운로드하여 컨테이너 루트 디렉터리의 절대 경로 `/us-east-1-bundle.pem`에 저장합니다. 함수 코드에서 데이터베이스 연결을 구성할 때 이 정확한 경로를 참조해야 합니다. 예제:

------
#### [ Node.js ]

Node.js 데이터베이스 클라이언트는 인증서 파일의 경로뿐만 아니라 메모리에 실제 인증서 내용이 필요하기 때문에 `readFileSync` 함수가 필요합니다. `readFileSync`가 없으면 클라이언트가 경로 문자열을 인증서 내용으로 해석하여 ‘인증서 체인에서 자체 서명된 인증서’ 오류가 발생합니다.

**Example OCI 함수에 대한 Node.js 연결 구성**  

```
import { readFileSync } from 'fs';

// ...

let connectionConfig = {
    host: process.env.ProxyHostName,
    user: process.env.DBUserName,
    password: token,
    database: process.env.DBName,
    ssl: {
        ca: readFileSync('/us-east-1-bundle.pem') // Load RDS certificate content from file into memory
    }
};
```

------
#### [ Python ]

**Example OCI 함수에 대한 Python 연결 구성**  

```
connection = pymysql.connect(
    host=proxy_host_name,
    user=db_username,
    password=token,
    db=db_name,
    port=port,
    ssl={'ca': '/us-east-1-bundle.pem'}  #Path to the certificate in container
)
```

------
#### [ Java ]

JDBC 연결을 사용하는 Java 함수의 경우 연결 문자열에 다음이 포함되어야 합니다.
+ `useSSL=true`
+ `requireSSL=true`
+ 컨테이너 이미지에서 Amazon RDS 인증서의 위치를 가리키는 `sslCA` 파라미터

**Example OCI 함수에 대한 Java 연결 문자열**  

```
// Define connection string
String connectionString = String.format("jdbc:mysql://%s:%s/%s?useSSL=true&requireSSL=true&sslCA=/us-east-1-bundle.pem", // Path to the certificate in container
        System.getenv("ProxyHostName"),
        System.getenv("Port"),
        System.getenv("DBName"));
```

------
#### [ .NET ]

**Example OCI 함수의 MySQL 연결에 대한 .NET 연결 문자열**  

```
/// Build the Connection String with the Token 
string connectionString = $"Server={Environment.GetEnvironmentVariable("RDS_ENDPOINT")};" +
                         $"Port={Environment.GetEnvironmentVariable("RDS_PORT")};" +
                         $"Uid={Environment.GetEnvironmentVariable("RDS_USERNAME")};" +
                         $"Pwd={authToken};" +
                         "SslMode=Required;" +
                         "SslCa=/us-east-1-bundle.pem";  // Path to the certificate in container
```

------
#### [ Go ]

MySQL 연결을 사용하는 Go 함수의 경우 Amazon RDS 인증서를 인증서 풀에 로드하고 MySQL 드라이버에 등록합니다. 그런 다음 연결 문자열은 `tls` 파라미터를 사용하여 이 구성을 참조해야 합니다.

**Example OCI 함수의 MySQL 연결에 대한 Go 코드**  

```
import (
    "crypto/tls"
    "crypto/x509"
    "os"
    "github.com/go-sql-driver/mysql"
)

...

// Create certificate pool and register TLS config
rootCertPool := x509.NewCertPool()
pem, err := os.ReadFile("/us-east-1-bundle.pem")  // Path to the certificate in container
if err != nil {
    panic("failed to read certificate file: " + err.Error())
}
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
    panic("failed to append PEM")
}

mysql.RegisterTLSConfig("custom", &tls.Config{
    RootCAs: rootCertPool,
})

dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?allowCleartextPasswords=true&tls=custom",
    dbUser, authenticationToken, dbEndpoint, dbName,
)
```

------
#### [ Ruby ]

**Example OCI 함수에 대한 Ruby 연결 구성**  

```
conn = Mysql2::Client.new(
    host: endpoint,
    username: user,
    password: token,
    port: port,
    database: db_name,
    sslca: '/us-east-1-bundle.pem',  # Path to the certificate in container
    sslverify: true
)
```

------

## Lambda 함수를 사용하여 Amazon RDS 데이터베이스에 연결
<a name="rds-connection"></a>

다음 코드 예제는 Amazon RDS 데이터베이스에 연결하는 Lambda 함수를 구현하는 방법을 보여줍니다. 이 함수는 간단한 데이터베이스 요청을 하고 결과를 반환합니다.

**참고**  
이 코드 예제는 [.zip 배포 패키지](configuration-function-zip.md)에만 유효합니다. [컨테이너 이미지를](images-create.md) 사용하여 함수를 배포하는 경우 [이전 섹션](#oci-certificate)에 설명된 대로 함수 코드에 Amazon RDS 인증서 파일을 지정해야 합니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda 함수에서 Amazon RDS 데이터베이스에 연결  

```
using System.Data;
using System.Text.Json;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using MySql.Data.MySqlClient;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace aws_rds;

public class InputModel
{
    public string key1 { get; set; }
    public string key2 { get; set; }
}

public class Function
{
    /// <summary>
    // Handles the Lambda function execution for connecting to RDS using IAM authentication.
    /// </summary>
    /// <param name="input">The input event data passed to the Lambda function</param>
    /// <param name="context">The Lambda execution context that provides runtime information</param>
    /// <returns>A response object containing the execution result</returns>

    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        // Sample Input: {"body": "{\"key1\":\"20\", \"key2\":\"25\"}"}
        var input = JsonSerializer.Deserialize<InputModel>(request.Body);

        /// Obtain authentication token
        var authToken = RDSAuthTokenGenerator.GenerateAuthToken(
            Environment.GetEnvironmentVariable("RDS_ENDPOINT"),
            Convert.ToInt32(Environment.GetEnvironmentVariable("RDS_PORT")),
            Environment.GetEnvironmentVariable("RDS_USERNAME")
        );

        /// Build the Connection String with the Token 
        string connectionString = $"Server={Environment.GetEnvironmentVariable("RDS_ENDPOINT")};" +
                                  $"Port={Environment.GetEnvironmentVariable("RDS_PORT")};" +
                                  $"Uid={Environment.GetEnvironmentVariable("RDS_USERNAME")};" +
                                  $"Pwd={authToken};";


        try
        {
            await using var connection = new MySqlConnection(connectionString);
            await connection.OpenAsync();

            const string sql = "SELECT @param1 + @param2 AS Sum";

            await using var command = new MySqlCommand(sql, connection);
            command.Parameters.AddWithValue("@param1", int.Parse(input.key1 ?? "0"));
            command.Parameters.AddWithValue("@param2", int.Parse(input.key2 ?? "0"));

            await using var reader = await command.ExecuteReaderAsync();
            if (await reader.ReadAsync())
            {
                int result = reader.GetInt32("Sum");

                //Sample Response: {"statusCode":200,"body":"{\"message\":\"The sum is: 45\"}","isBase64Encoded":false}
                return new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = JsonSerializer.Serialize(new { message = $"The sum is: {result}" })
                };
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }

        return new APIGatewayProxyResponse
        {
            StatusCode = 500,
            Body = JsonSerializer.Serialize(new { error = "Internal server error" })
        };
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda 함수에서 Amazon RDS 데이터베이스에 연결  

```
/*
Golang v2 code here.
*/

package main

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"os"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/feature/rds/auth"
	_ "github.com/go-sql-driver/mysql"
)

type MyEvent struct {
	Name string `json:"name"`
}

func HandleRequest(event *MyEvent) (map[string]interface{}, error) {

	var dbName string = os.Getenv("DatabaseName")
	var dbUser string = os.Getenv("DatabaseUser")
	var dbHost string = os.Getenv("DBHost") // Add hostname without https
	var dbPort int = os.Getenv("Port")      // Add port number
	var dbEndpoint string = fmt.Sprintf("%s:%d", dbHost, dbPort)
	var region string = os.Getenv("AWS_REGION")

	cfg, err := config.LoadDefaultConfig(context.TODO())
	if err != nil {
		panic("configuration error: " + err.Error())
	}

	authenticationToken, err := auth.BuildAuthToken(
		context.TODO(), dbEndpoint, region, dbUser, cfg.Credentials)
	if err != nil {
		panic("failed to create authentication token: " + err.Error())
	}

	dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=true&allowCleartextPasswords=true",
		dbUser, authenticationToken, dbEndpoint, dbName,
	)

	db, err := sql.Open("mysql", dsn)
	if err != nil {
		panic(err)
	}

	defer db.Close()

	var sum int
	err = db.QueryRow("SELECT ?+? AS sum", 3, 2).Scan(&sum)
	if err != nil {
		panic(err)
	}
	s := fmt.Sprint(sum)
	message := fmt.Sprintf("The selected sum is: %s", s)

	messageBytes, err := json.Marshal(message)
	if err != nil {
		return nil, err
	}

	messageString := string(messageBytes)
	return map[string]interface{}{
		"statusCode": 200,
		"headers":    map[string]string{"Content-Type": "application/json"},
		"body":       messageString,
	}, nil
}

func main() {
	lambda.Start(HandleRequest)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda 함수에서 Amazon RDS 데이터베이스에 연결  

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.rdsdata.RdsDataClient;
import software.amazon.awssdk.services.rdsdata.model.ExecuteStatementRequest;
import software.amazon.awssdk.services.rdsdata.model.ExecuteStatementResponse;
import software.amazon.awssdk.services.rdsdata.model.Field;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class RdsLambdaHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Override
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) {
        APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();

        try {
            // Obtain auth token
            String token = createAuthToken();

            // Define connection configuration
            String connectionString = String.format("jdbc:mysql://%s:%s/%s?useSSL=true&requireSSL=true",
                    System.getenv("ProxyHostName"),
                    System.getenv("Port"),
                    System.getenv("DBName"));

            // Establish a connection to the database
            try (Connection connection = DriverManager.getConnection(connectionString, System.getenv("DBUserName"), token);
                 PreparedStatement statement = connection.prepareStatement("SELECT ? + ? AS sum")) {

                statement.setInt(1, 3);
                statement.setInt(2, 2);

                try (ResultSet resultSet = statement.executeQuery()) {
                    if (resultSet.next()) {
                        int sum = resultSet.getInt("sum");
                        response.setStatusCode(200);
                        response.setBody("The selected sum is: " + sum);
                    }
                }
            }

        } catch (Exception e) {
            response.setStatusCode(500);
            response.setBody("Error: " + e.getMessage());
        }

        return response;
    }

    private String createAuthToken() {
        // Create RDS Data Service client
        RdsDataClient rdsDataClient = RdsDataClient.builder()
                .region(Region.of(System.getenv("AWS_REGION")))
                .credentialsProvider(DefaultCredentialsProvider.create())
                .build();

        // Define authentication request
        ExecuteStatementRequest request = ExecuteStatementRequest.builder()
                .resourceArn(System.getenv("ProxyHostName"))
                .secretArn(System.getenv("DBUserName"))
                .database(System.getenv("DBName"))
                .sql("SELECT 'RDS IAM Authentication'")
                .build();

        // Execute request and obtain authentication token
        ExecuteStatementResponse response = rdsDataClient.executeStatement(request);
        Field tokenField = response.records().get(0).get(0);

        return tokenField.stringValue();
    }
}
```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda 함수에서 Amazon RDS 데이터베이스에 연결  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
/* 
Node.js code here.
*/
// ES6+ example
import { Signer } from "@aws-sdk/rds-signer";
import mysql from 'mysql2/promise';

async function createAuthToken() {
  // Define connection authentication parameters
  const dbinfo = {

    hostname: process.env.ProxyHostName,
    port: process.env.Port,
    username: process.env.DBUserName,
    region: process.env.AWS_REGION,

  }

  // Create RDS Signer object
  const signer = new Signer(dbinfo);

  // Request authorization token from RDS, specifying the username
  const token = await signer.getAuthToken();
  return token;
}

async function dbOps() {

  // Obtain auth token
  const token = await createAuthToken();
  // Define connection configuration
  let connectionConfig = {
    host: process.env.ProxyHostName,
    user: process.env.DBUserName,
    password: token,
    database: process.env.DBName,
    ssl: 'Amazon RDS'
  }
  // Create the connection to the DB
  const conn = await mysql.createConnection(connectionConfig);
  // Obtain the result of the query
  const [res,] = await conn.execute('select ?+? as sum', [3, 2]);
  return res;

}

export const handler = async (event) => {
  // Execute database flow
  const result = await dbOps();
  // Return result
  return {
    statusCode: 200,
    body: JSON.stringify("The selected sum is: " + result[0].sum)
  }
};
```
TypeScript를 사용하여 Lambda 함수에서 Amazon RDS 데이터베이스에 연결  

```
import { Signer } from "@aws-sdk/rds-signer";
import mysql from 'mysql2/promise';

// RDS settings
// Using '!' (non-null assertion operator) to tell the TypeScript compiler that the DB settings are not null or undefined,
const proxy_host_name = process.env.PROXY_HOST_NAME!
const port = parseInt(process.env.PORT!)
const db_name = process.env.DB_NAME!
const db_user_name = process.env.DB_USER_NAME!
const aws_region = process.env.AWS_REGION!


async function createAuthToken(): Promise<string> {

    // Create RDS Signer object
    const signer = new Signer({
        hostname: proxy_host_name,
        port: port,
        region: aws_region,
        username: db_user_name
    });

    // Request authorization token from RDS, specifying the username
    const token = await signer.getAuthToken();
    return token;
}

async function dbOps(): Promise<mysql.QueryResult | undefined> {
    try {
        // Obtain auth token
        const token = await createAuthToken();
        const conn = await mysql.createConnection({
            host: proxy_host_name,
            user: db_user_name,
            password: token,
            database: db_name,
            ssl: 'Amazon RDS' // Ensure you have the CA bundle for SSL connection
        });
        const [rows, fields] = await conn.execute('SELECT ? + ? AS sum', [3, 2]);
        console.log('result:', rows);
        return rows;
    }
    catch (err) {
        console.log(err);
    }
}

export const lambdaHandler = async (event: any): Promise<{ statusCode: number; body: string }> => {
    // Execute database flow
    const result = await dbOps();

    // Return error is result is undefined
    if (result == undefined)
        return {
            statusCode: 500,
            body: JSON.stringify(`Error with connection to DB host`)
        }

    // Return result
    return {
        statusCode: 200,
        body: JSON.stringify(`The selected sum is: ${result[0].sum}`)
    };
};
```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda 함수에서 Amazon RDS 데이터베이스에 연결  

```
<?php
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\Handler as StdHandler;
use Bref\Logger\StderrLogger;
use Aws\Rds\AuthTokenGenerator;
use Aws\Credentials\CredentialProvider;

require __DIR__ . '/vendor/autoload.php';

class Handler implements StdHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }


    private function getAuthToken(): string {
        // Define connection authentication parameters
        $dbConnection = [
            'hostname' => getenv('DB_HOSTNAME'),
            'port' => getenv('DB_PORT'),
            'username' => getenv('DB_USERNAME'),
            'region' => getenv('AWS_REGION'),
        ];

        // Create RDS AuthTokenGenerator object
        $generator = new AuthTokenGenerator(CredentialProvider::defaultProvider());

        // Request authorization token from RDS, specifying the username
        return $generator->createToken(
            $dbConnection['hostname'] . ':' . $dbConnection['port'],
            $dbConnection['region'],
            $dbConnection['username']
        );
    }

    private function getQueryResults() {
        // Obtain auth token
        $token = $this->getAuthToken();

        // Define connection configuration
        $connectionConfig = [
            'host' => getenv('DB_HOSTNAME'),
            'user' => getenv('DB_USERNAME'),
            'password' => $token,
            'database' => getenv('DB_NAME'),
        ];

        // Create the connection to the DB
        $conn = new PDO(
            "mysql:host={$connectionConfig['host']};dbname={$connectionConfig['database']}",
            $connectionConfig['user'],
            $connectionConfig['password'],
            [
                PDO::MYSQL_ATTR_SSL_CA => '/path/to/rds-ca-2019-root.pem',
                PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
            ]
        );

        // Obtain the result of the query
        $stmt = $conn->prepare('SELECT ?+? AS sum');
        $stmt->execute([3, 2]);

        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    /**
     * @param mixed $event
     * @param Context $context
     * @return array
     */
    public function handle(mixed $event, Context $context): array
    {
        $this->logger->info("Processing query");

        // Execute database flow
        $result = $this->getQueryResults();

        return [
            'sum' => $result['sum']
        ];
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda 함수에서 Amazon RDS 데이터베이스에 연결  

```
import json
import os
import boto3
import pymysql

# RDS settings
proxy_host_name = os.environ['PROXY_HOST_NAME']
port = int(os.environ['PORT'])
db_name = os.environ['DB_NAME']
db_user_name = os.environ['DB_USER_NAME']
aws_region = os.environ['AWS_REGION']


# Fetch RDS Auth Token
def get_auth_token():
    client = boto3.client('rds')
    token = client.generate_db_auth_token(
        DBHostname=proxy_host_name,
        Port=port
        DBUsername=db_user_name
        Region=aws_region
    )
    return token

def lambda_handler(event, context):
    token = get_auth_token()
    try:
        connection = pymysql.connect(
            host=proxy_host_name,
            user=db_user_name,
            password=token,
            db=db_name,
            port=port,
            ssl={'ca': 'Amazon RDS'}  # Ensure you have the CA bundle for SSL connection
        )
        
        with connection.cursor() as cursor:
            cursor.execute('SELECT %s + %s AS sum', (3, 2))
            result = cursor.fetchone()

        return result
        
    except Exception as e:
        return (f"Error: {str(e)}")  # Return an error message if an exception occurs
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda 함수에서 Amazon RDS 데이터베이스에 연결  

```
# Ruby code here.

require 'aws-sdk-rds'
require 'json'
require 'mysql2'

def lambda_handler(event:, context:)
  endpoint = ENV['DBEndpoint'] # Add the endpoint without https"
  port = ENV['Port']           # 3306
  user = ENV['DBUser']
  region = ENV['DBRegion']     # 'us-east-1'
  db_name = ENV['DBName']

  credentials = Aws::Credentials.new(
    ENV['AWS_ACCESS_KEY_ID'],
    ENV['AWS_SECRET_ACCESS_KEY'],
    ENV['AWS_SESSION_TOKEN']
  )
  rds_client = Aws::RDS::AuthTokenGenerator.new(
    region: region, 
    credentials: credentials
  )

  token = rds_client.auth_token(
    endpoint: endpoint+ ':' + port,
    user_name: user,
    region: region
  )

  begin
    conn = Mysql2::Client.new(
      host: endpoint,
      username: user,
      password: token,
      port: port,
      database: db_name,
      sslca: '/var/task/global-bundle.pem', 
      sslverify: true,
      enable_cleartext_plugin: true
    )
    a = 3
    b = 2
    result = conn.query("SELECT #{a} + #{b} AS sum").first['sum']
    puts result
    conn.close
    {
      statusCode: 200,
      body: result.to_json
    }
  rescue => e
    puts "Database connection failed due to #{e}"
  end
end
```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-connect-rds-iam) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda 함수에서 Amazon RDS 데이터베이스에 연결  

```
use aws_config::BehaviorVersion;
use aws_credential_types::provider::ProvideCredentials;
use aws_sigv4::{
    http_request::{sign, SignableBody, SignableRequest, SigningSettings},
    sign::v4,
};
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use serde_json::{json, Value};
use sqlx::postgres::PgConnectOptions;
use std::env;
use std::time::{Duration, SystemTime};

const RDS_CERTS: &[u8] = include_bytes!("global-bundle.pem");

async fn generate_rds_iam_token(
    db_hostname: &str,
    port: u16,
    db_username: &str,
) -> Result<String, Error> {
    let config = aws_config::load_defaults(BehaviorVersion::v2024_03_28()).await;

    let credentials = config
        .credentials_provider()
        .expect("no credentials provider found")
        .provide_credentials()
        .await
        .expect("unable to load credentials");
    let identity = credentials.into();
    let region = config.region().unwrap().to_string();

    let mut signing_settings = SigningSettings::default();
    signing_settings.expires_in = Some(Duration::from_secs(900));
    signing_settings.signature_location = aws_sigv4::http_request::SignatureLocation::QueryParams;

    let signing_params = v4::SigningParams::builder()
        .identity(&identity)
        .region(&region)
        .name("rds-db")
        .time(SystemTime::now())
        .settings(signing_settings)
        .build()?;

    let url = format!(
        "https://{db_hostname}:{port}/?Action=connect&DBUser={db_user}",
        db_hostname = db_hostname,
        port = port,
        db_user = db_username
    );

    let signable_request =
        SignableRequest::new("GET", &url, std::iter::empty(), SignableBody::Bytes(&[]))
            .expect("signable request");

    let (signing_instructions, _signature) =
        sign(signable_request, &signing_params.into())?.into_parts();

    let mut url = url::Url::parse(&url).unwrap();
    for (name, value) in signing_instructions.params() {
        url.query_pairs_mut().append_pair(name, &value);
    }

    let response = url.to_string().split_off("https://".len());

    Ok(response)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    run(service_fn(handler)).await
}

async fn handler(_event: LambdaEvent<Value>) -> Result<Value, Error> {
    let db_host = env::var("DB_HOSTNAME").expect("DB_HOSTNAME must be set");
    let db_port = env::var("DB_PORT")
        .expect("DB_PORT must be set")
        .parse::<u16>()
        .expect("PORT must be a valid number");
    let db_name = env::var("DB_NAME").expect("DB_NAME must be set");
    let db_user_name = env::var("DB_USERNAME").expect("DB_USERNAME must be set");

    let token = generate_rds_iam_token(&db_host, db_port, &db_user_name).await?;

    let opts = PgConnectOptions::new()
        .host(&db_host)
        .port(db_port)
        .username(&db_user_name)
        .password(&token)
        .database(&db_name)
        .ssl_root_cert_from_pem(RDS_CERTS.to_vec())
        .ssl_mode(sqlx::postgres::PgSslMode::Require);

    let pool = sqlx::postgres::PgPoolOptions::new()
        .connect_with(opts)
        .await?;

    let result: i32 = sqlx::query_scalar("SELECT $1 + $2")
        .bind(3)
        .bind(2)
        .fetch_one(&pool)
        .await?;

    println!("Result: {:?}", result);

    Ok(json!({
        "statusCode": 200,
        "content-type": "text/plain",
        "body": format!("The selected sum is: {result}")
    }))
}
```

------

## Amazon RDS의 이벤트 알림 처리
<a name="rds-events"></a>

Lambda를 사용하여 Amazon RDS 데이터베이스의 이벤트 알림을 처리할 수 있습니다. Amazon RDS는 Amazon Simple Notification Service(Amazon SNS) 주제에 알림을 전송합니다. 이 알림이 Lambda 함수를 간접 호출하도록 구성할 수 있습니다. Amazon SNS는 Amazon RDS의 메시지를 자체 이벤트 문서로 래핑하여 함수에 이를 전송합니다.

알림 전송을 위한 Amazon RDS 데이터베이스 구성에 대한 자세한 내용은 [Amazon RDS 이벤트 알림 사용](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Events.html)을 참조하세요.

**Example Amazon SNS 이벤트의 Amazon RDS 메시지**  

```
{
        "Records": [
          {
            "EventVersion": "1.0",
            "EventSubscriptionArn": "arn:aws:sns:us-east-2:123456789012:rds-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
            "EventSource": "aws:sns",
            "Sns": {
              "SignatureVersion": "1",
              "Timestamp": "2023-01-02T12:45:07.000Z",
              "Signature": "tcc6faL2yUC6dgZdmrwh1Y4cGa/ebXEkAi6RibDsvpi+tE/1+82j...65r==",
              "SigningCertUrl": "https://sns.us-east-2.amazonaws.com/SimpleNotificationService-ac565b8b1a6c5d002d285f9598aa1d9b.pem",
              "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
              "Message": "{\"Event Source\":\"db-instance\",\"Event Time\":\"2023-01-02 12:45:06.000\",\"Identifier Link\":\"https://console.aws.amazon.com/rds/home?region=eu-west-1#dbinstance:id=dbinstanceid\",\"Source ID\":\"dbinstanceid\",\"Event ID\":\"http://docs.amazonwebservices.com/AmazonRDS/latest/UserGuide/USER_Events.html#RDS-EVENT-0002\",\"Event Message\":\"Finished DB Instance backup\"}",
              "MessageAttributes": {},
              "Type": "Notification",
              "UnsubscribeUrl": "https://sns.us-east-2.amazonaws.com/?Action=Unsubscribe&amp;SubscriptionArn=arn:aws:sns:us-east-2:123456789012:test-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
              "TopicArn":"arn:aws:sns:us-east-2:123456789012:sns-lambda",
              "Subject": "RDS Notification Message"
            }
          }
        ]
      }
```

## Lambda 및 Amazon RDS 자습서 완료
<a name="rds-database-samples"></a>
+ [Amazon RDS 데이터베이스에 액세스하기 위해 Lambda 함수 사용](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-lambda-tutorial.html) – Amazon RDS 사용자 설명서에서, Lambda 함수를 사용하여 Amazon RDS Proxy를 통해 Amazon RDS 데이터베이스에 데이터를 쓰는 방법을 알아보세요. Lambda 함수는 메시지가 추가될 때마다 Amazon SQS 대기열에서 레코드를 읽고 데이터베이스의 테이블에 새 항목을 기록합니다.

# Lambda 기반 애플리케이션에 대한 데이터베이스 서비스 선택
<a name="ddb-rds-database-decision"></a>

많은 서버리스 애플리케이션은 데이터를 저장하고 검색해야 합니다. AWS는 Lambda 함수에서 작동하는 여러 가지 데이터베이스 옵션을 제공합니다. 가장 인기 있는 두 가지 옵션은 NoSQL 데이터베이스 서비스인 Amazon DynamoDB와 기존 관계형 데이터베이스 솔루션인 Amazon RDS입니다. 다음 섹션에서는 이러한 서비스를 Lambda와 함께 사용할 때 이러한 서비스의 주요 차이점을 설명하며, 서버리스 애플리케이션에 적합한 데이터베이스 서비스를 선택할 수 있도록 지원합니다.

AWS에서 제공하는 다른 데이터베이스 서비스에 대해 자세히 알아보고, 사용 사례 및 장단점을 더욱 종합적으로 이해하려면 [Choosing an AWS database service](https://docs.aws.amazon.com/decision-guides/latest/databases-on-aws-how-to-choose/databases-on-aws-how-to-choose.html) 섹션을 참조하세요. 모든 AWS 데이터베이스 서비스는 Lambda와 호환되지만, 모든 데이터베이스 서비스가 특정 사용 사례에 적합한 것은 아닙니다.

## Lambda를 사용하여 데이터베이스 서비스를 선택할 때 고를 수 있는 옵션
<a name="w2aad101d101c19b9"></a>

AWS는 여러 가지 데이터베이스 서비스를 제공합니다. 서버리스 애플리케이션의 경우 가장 많이 사용되는 두 가지 옵션은 DynamoDB 및 Amazon RDS입니다.
+ **DynamoDB**는 서버리스 애플리케이션에 최적화된 완전 관리형 NoSQL 데이터베이스 서비스입니다. 모든 규모에서 원활한 규모 조정 및 일관된 한 자릿수 밀리초 성능을 제공합니다.
+ **Amazon RDS**는 MySQL 및 PostgreSQL을 비롯한 여러 데이터베이스 엔진을 지원하는 관리형 관계형 데이터베이스 서비스입니다. 관리형 인프라를 통해 익숙한 SQL 기능을 제공합니다.

## 권장 사항(요구 사항을 이미 알고 있는 경우)
<a name="w2aad101d101c19c11"></a>

요구 사항을 이미 명확히 알고 있는 경우 기본 권장 사항은 다음과 같습니다.

지연 시간이 짧은 일관된 성능, 자동 규모 조정이 필요하고 복잡한 조인 또는 트랜잭션을 요구하지 않는 서버리스 애플리케이션에 [DynamoDB](with-ddb.md)를 사용하는 것이 좋습니다. 이는 서버리스의 특성상 Lambda 기반 애플리케이션에 특히 적합합니다.

[Amazon RDS](services-rds.md)는 복잡한 SQL 쿼리, 조인이 필요하거나 관계형 데이터베이스를 사용하는 기존 애플리케이션이 있는 경우에 더 적합한 옵션입니다. 그러나 Lambda 함수를 Amazon RDS에 연결하려면 추가 구성이 필요하며, 콜드 스타트 시간에 영향을 미칠 수 있습니다.

## 데이터베이스 서비스를 선택할 때 고려해야 할 사항
<a name="w2aad101d101c19c13"></a>

Lambda 애플리케이션에 DynamoDB 및 Amazon RDS 중 어떤 걸 사용할지 선택할 경우 다음 요소를 고려하세요.
+ 연결 관리 및 콜드 스타트
+ 데이터 액세스 패턴
+ 쿼리 복잡성
+ 데이터 일관성 요구 사항
+ 규모 조정 특성
+ 비용 모델

이러한 요소를 이해하면 특정한 사용 사례의 요구 사항에 가장 적합한 옵션을 선택할 수 있습니다.

### 연결 관리 및 콜드 스타트
<a name="w2aad101d101c19c13b9b1"></a>
+ DynamoDB는 모든 작업에 HTTP API를 사용합니다. Lambda 함수는 연결을 유지하지 않고도 즉시 요청할 수 있으므로 콜드 스타트 성능이 향상됩니다. 각 요청은 연결 오버헤드 없이 AWS 자격 증명을 사용하여 인증됩니다.
+ Amazon RDS는 기존 데이터베이스 연결을 사용하기 때문에 연결 풀을 관리해야 합니다. 이 경우 새 Lambda 인스턴스가 연결을 설정해야 하므로 콜드 스타트에 영향을 미칠 수 있습니다. 연결 풀링 전략을 구현해야 하며 [Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html)를 사용하여 연결을 효과적으로 관리해야 할 수 있습니다. Amazon RDS Proxy를 사용하면 추가 비용이 발생합니다.

### 데이터 액세스 패턴
<a name="w2aad101d101c19c13b9b3"></a>
+ DynamoDB는 알려진 액세스 패턴 및 단일 테이블 설계에 가장 적합합니다. 프라이머리 키 또는 보조 인덱스를 토대로 데이터에 대해 지연 시간이 짧은 일관된 액세스가 필요한 Lambda 애플리케이션에 적합합니다.
+ Amazon RDS는 복잡한 쿼리 및 변경되는 액세스 패턴을 위한 유연성을 제공합니다. Lambda 함수가 여러 테이블에서 고유한 맞춤형 쿼리 또는 복잡한 조인을 수행해야 하는 경우에 더 적합합니다.

### 쿼리 복잡성
<a name="w2aad101d101c19c13b9b5"></a>
+ DynamoDB는 간단한 키 기반 작업 및 사전 정의된 액세스 패턴에서 우수한 기능을 발휘합니다. 복잡한 쿼리는 인덱스 구조를 중심으로 설계되어야 하며, 조인은 애플리케이션 코드에서 처리되어야 합니다.
+ Amazon RDS는 조인, 하위 쿼리, 집계를 통해 복잡한 SQL 쿼리를 지원합니다. 이렇게 하면 복잡한 데이터 작업이 필요할 때 Lambda 함수 코드를 간소화할 수 있습니다.

### 데이터 일관성 요구 사항
<a name="w2aad101d101c19c13b9b7"></a>
+ DynamoDB는 단일 항목 읽기에 사용할 수 있는 강력한 일관성과 함께 최종 일관성 및 강력한 일관성 옵션을 모두 제공합니다. 트랜잭션이 지원되지만 몇 가지 제한 사항이 있습니다.
+ Amazon RDS는 완전한 원자성, 일관성, 격리, 내구성(ACID) 규정 준수 및 복잡한 트랜잭션 지원을 제공합니다. Lambda 함수에 복잡한 트랜잭션이 필요하거나 여러 레코드에 강력한 일관성이 필요한 경우 Amazon RDS가 더 적합할 수 있습니다.

### 규모 조정 특성
<a name="w2aad101d101c19c13b9b9"></a>
+ DynamoDB는 워크로드에 따라 자동으로 확장됩니다. 사전 프로비저닝 없이 Lambda 함수의 갑작스러운 트래픽 스파이크를 처리할 수 있습니다. 온디맨드 용량 모드를 사용하면 Lambda의 규모 조정 모델과 완벽하게 일치하는 사용량에 대해서만 비용을 지불할 수 있습니다.
+ Amazon RDS는 선택한 인스턴스 크기에 따라 용량이 고정됩니다. 여러 Lambda 함수가 동시에 연결을 시도할 경우 연결 할당량을 초과할 수 있습니다. 연결 풀을 꼼꼼하게 관리하고 재시도 로직을 구현해야 합니다.

### 비용 모델
<a name="w2aad101d101c19c13b9c11"></a>
+ DynamoDB의 요금은 서버리스 애플리케이션과 잘 맞습니다. 온디맨드 용량을 사용하면 Lambda 함수에서 수행한 실제 읽기 및 쓰기에 대해서만 비용을 지불합니다. 유휴 시간에는 요금이 부과되지 않습니다.
+ Amazon RDS는 사용량과 관계없이 실행 중인 인스턴스에 대해 요금을 청구합니다. 이렇게 되면 서버리스 애플리케이션에서 일반적으로 일어날 수 있는 산발적인 워크로드의 경우 비용 효율성이 떨어질 수 있습니다. 그러나 사용량이 일관되면서 처리량이 많은 워크로드의 경우에는 더 경제적일 수 있습니다.

## 선택한 데이터베이스 서비스 시작하기
<a name="w2aad101d101c19c15"></a>

이제 DynamoDB 및 Amazon RDS 중 하나를 선택하는 기준과 이들 간의 주요 차이에 대해 알아보았으니, 요구 사항과 가장 일치하는 옵션을 선택하고 다음 리소스를 사용하여 사용을 시작할 수 있습니다.

------
#### [ DynamoDB ]

**다음 리소스를 사용하여 DynamoDB 시작하기**
+ DynamoDB 서비스에 대한 소개는 **Amazon DynamoDB 개발자 가이드의 [What is DynamoDB?](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) 섹션을 참조하세요.
+ [API Gateway에서 Lambda 사용](services-apigateway-tutorial.md) 자습서를 따라 API 요청에 대한 응답으로 Lambda 함수를 사용하여 DynamoDB 테이블에서 CRUD 작업을 수행하는 예제를 확인합니다.
+ **Amazon DynamoDB 개발자 안내서의 [DynamoDB 및 AWS SDK를 사용한 프로그래밍](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.html) 섹션을 읽고 AWS SDK 중 하나를 사용하여 Lambda 함수 내에서 DynamoDB에 액세스하는 방법을 자세히 알아봅니다.

------
#### [ Amazon RDS ]

**다음 리소스를 사용하여 Amazon RDS 시작하기**
+ Amazon RDS 서비스에 대한 소개는 **Amazon Relational Database Service 사용 설명서의 [Amazon Relational Database Service(Amazon RDS)란 무엇입니까?](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html) 섹션을 참조하세요.
+ *Amazon Relational Database 사용 설명서*의 [Amazon RDS에 액세스하기 위해 Lambda 함수 사용](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-lambda-tutorial.html) 자습서를 따릅니다.
+ [Amazon RDS와 함께 AWS Lambda 사용](services-rds.md) 섹션을 읽고 Amazon RDS와 함께 Lambda를 사용하는 방법을 자세히 알아봅니다.

------

# Lambda를 사용하여 Amazon S3 이벤트 알림 처리
<a name="with-s3"></a>

Lambda를 사용하여 Amazon Simple Storage Service의 [이벤트 알림](https://docs.aws.amazon.com/AmazonS3/latest/userguide/NotificationHowTo.html)을 처리할 수 있습니다. Amazon S3는 객체가 생성되거나 삭제될 때 이벤트를 Lambda 함수에 전송할 수 있습니다. 버킷에 알림 설정을 구성하고 Amazon S3에 함수의 리소스 기반 권한 정책에 따라 함수를 간접 호출할 수 있는 권한을 부여합니다.

**주의**  
Lambda 함수가 해당 함수를 트리거하는 동일한 버킷을 사용하는 경우 함수가 루프에서 실행될 수 있습니다. 예를 들어 객체가 업로드될 때마다 버킷이 함수를 트리거하고 그 함수가 객체를 버킷에 업로드하는 경우, 함수는 간접적으로 자신을 트리거합니다 이렇게 되지 않도록 하려면 두 개의 버킷을 사용하거나, 수신 객체에 사용되는 접두사에만 적용되도록 트리거를 구성합니다.

Amazon S3는 객체에 대한 세부 정보를 포함하는 이벤트와 [비동기적으로](invocation-async.md) 함수를 간접 호출합니다. 다음 예제에서는 배포 패키지가 Amazon S3에 업로드될 때 Amazon S3에서 전송한 이벤트를 보여줍니다.

**Example Amazon S3 알림 이벤트**  

```
{
  "Records": [
    {
      "eventVersion": "2.1",
      "eventSource": "aws:s3",
      "awsRegion": "us-east-2",
      "eventTime": "2019-09-03T19:37:27.192Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "AWS:AIDAINPONIXQXHT3IKHL2"
      },
      "requestParameters": {
        "sourceIPAddress": "205.255.255.255"
      },
      "responseElements": {
        "x-amz-request-id": "D82B88E5F771F645",
        "x-amz-id-2": "vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo="
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "828aa6fc-f7b5-4305-8584-487c791949c1",
        "bucket": {
          "name": "amzn-s3-demo-bucket",
          "ownerIdentity": {
            "principalId": "A3I5XTEXAMAI3E"
          },
          "arn": "arn:aws:s3:::lambda-artifacts-deafc19498e3f2df"
        },
        "object": {
          "key": "b21b84d653bb07b05b1e6b33684dc11b",
          "size": 1305107,
          "eTag": "b21b84d653bb07b05b1e6b33684dc11b",
          "sequencer": "0C0F6F405D6ED209E1"
        }
      }
    }
  ]
}
```

함수를 간접 호출하려면 Amazon S3는 함수의 [리소스 기반 정책](access-control-resource-based.md)의 권한이 필요합니다. Lambda 콘솔에서 Amazon S3 트리거를 구성할 때, 콘솔은 버킷 이름과 계정 ID가 일치할 경우 Amazon S3에서 함수를 간접 호출할 수 있도록 리소스 기반 정책을 수정합니다. Amazon S3에서 알림을 구성할 경우, Lambda API를 사용하여 정책을 업데이트합니다. 또한 Lambda API를 사용하여 다른 계정에 권한을 부여하거나 지정된 별칭으로 권한을 제한할 수도 있습니다.

함수에서 AWS SDK를 사용하여 Amazon S3 리소스를 관리하는 경우, [실행 역할](lambda-intro-execution-role.md)에 Amazon S3 권한이 있어야 합니다.

**Topics**
+ [

# 자습서: Amazon S3 트리거를 사용하여 Lambda 함수 간접 호출
](with-s3-example.md)
+ [

# 자습서: Amazon S3 트리거를 사용하여 썸네일 이미지 생성
](with-s3-tutorial.md)

# 자습서: Amazon S3 트리거를 사용하여 Lambda 함수 간접 호출
<a name="with-s3-example"></a>

이 자습서에서는 콘솔을 사용하여 Lambda 함수를 생성하고 Amazon Simple Storage Service(Amazon S3) 버킷에 대한 트리거를 구성합니다. Amazon S3 버킷에 객체를 추가할 때마다 함수가 실행되고 Amazon CloudWatch Logs에 객체 유형을 출력합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3_tut_config.png)


이 자습서에서는 다음을 수행하는 방법을 설명합니다.

1. Amazon S3 버킷을 생성합니다.

1. Amazon S3 버킷에 있는 객체의 유형을 반환하는 Lambda 함수를 생성합니다.

1. 객체가 버킷에 업로드될 때 함수를 간접 호출하는 Lambda 트리거를 구성합니다.

1. 먼저 더미 이벤트로 함수를 테스트한 다음 트리거를 사용하여 함수를 테스트합니다.

이 단계를 완료하면 Amazon S3 버킷에서 객체가 추가되거나 삭제될 때마다 실행되도록 Lambda 함수를 구성하는 방법을 알게 됩니다. AWS Management Console만 사용하여 이 자습서를 완료할 수 있습니다.

## Amazon S3 버킷 생성
<a name="with-s3-example-create-bucket"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps1.png)


**Amazon S3 버킷을 생성하려면**

1. [Amazon S3 콘솔](https://console.aws.amazon.com/s3)을 열고 **범용 버킷** 페이지를 선택합니다.

1. 지리적 위치와 가장 가까운 AWS 리전을 선택합니다. 화면 상단의 드롭다운 목록을 사용하여 리전을 변경할 수 있습니다. 자습서 뒷부분에서 동일한 리전에 Lambda 함수를 생성해야 합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/console_region_select.png)

1. **버킷 생성**을 선택합니다.

1. [**일반 구성(General configuration)**]에서 다음을 수행합니다.

   1. **버킷 유형**에서 **범용**을 선택했는지 확인합니다.

   1. **버킷 이름**에 Amazon S3 [버킷 이름 지정 규칙](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)을 충족하는 전역적으로 고유한 이름을 입력합니다. 버킷 이름은 소문자, 숫자, 점(.) 및 하이픈(-)만 포함할 수 있습니다.

1. 다른 모든 옵션을 기본값으로 두고 **버킷 생성**을 선택합니다.

## 버킷에 테스트 객체 업로드
<a name="with-s3-example-upload-test-object"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps2.png)


**테스트 객체 업로드**

1. Amazon S3 콘솔의 [버킷](https://console.aws.amazon.com/s3/buckets) 페이지를 열고 이전 단계 중 생성한 버킷을 선택합니다.

1. **업로드**를 선택합니다.

1. **파일 추가**를 선택하고 업로드하려는 객체를 선택합니다. 모든 파일을 선택할 수 있습니다(예: `HappyFace.jpg`).

1. **열기**를 선택한 후 **업로드**를 선택합니다.

자습서의 뒷부분에서 이 객체를 사용하여 Lambda 함수를 테스트합니다.

## 권한 정책 생성
<a name="with-s3-example-create-policy"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps3.png)


Lambda가 Amazon S3 버킷에서 객체를 가져오고 Amazon CloudWatch Logs에 쓸 수 있도록 허용하는 권한 정책을 생성합니다.

**정책 생성**

1. IAM 콘솔에서 [정책 페이지](https://console.aws.amazon.com/iam/home#/policies)를 엽니다.

1. **정책 생성**을 선택하세요.

1. **JSON** 탭에서 다음과 같은 사용자 지정 정책을 JSON 편집기에 붙여 넣습니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "logs:PutLogEvents",
                   "logs:CreateLogGroup",
                   "logs:CreateLogStream"
               ],
               "Resource": "arn:aws:logs:*:*:*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:GetObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           }
       ]
   }
   ```

------

1. **다음: 태그**를 선택합니다.

1. **다음: 검토(Next: Review)**를 선택합니다.

1. **정책 검토**의 **이름**에 **s3-trigger-tutorial**를 입력합니다.

1. **정책 생성**을 선택합니다.

## 실행 역할 만들기
<a name="with-s3-example-create-role"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps4.png)


[실행 역할](lambda-intro-execution-role.md)은 AWS 서비스 및 리소스에 액세스할 수 있는 권한을 Lambda 함수에 부여하는 AWS Identity and Access Management(IAM) 역할입니다. 이 단계에서는 이전 단계에서 생성한 권한 정책을 사용하여 실행 역할을 생성하세요.

**실행 역할을 생성하고 사용자 지정 권한 정책을 연결하려면**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. **역할 생성**을 선택합니다.

1. 신뢰할 수 있는 엔터티의 유형으로 **AWS 서비스**를 선택한 다음 사용 사례로 **Lambda**를 선택합니다.

1. **다음**을 선택합니다.

1. 정책 검색 상자에 **s3-trigger-tutorial**를 입력합니다.

1. 검색 결과에서 생성한 정책(`s3-trigger-tutorial`)을 선택한 후, **다음(Next)**을 선택합니다.

1. **Role details**(역할 세부 정보)에서 **Role name**(역할 이름)에 **lambda-s3-trigger-role**을 입력한 다음 **Create role**(역할 생성)을 선택합니다.

## Lambda 함수 생성
<a name="with-s3-example-create-function"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps5.png)


Python 3.14 런타임을 사용하여 콘솔에서 Lambda 함수를 생성하세요.

**Lambda 함수를 만들려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. Amazon S3 버킷을 생성한 동일한 AWS 리전에서 작업 중인지 확인합니다. 화면 상단의 드롭다운 목록을 사용하여 리전을 변경할 수 있습니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/console_region_select.png)

1. **함수 생성**을 선택합니다.

1. **새로 작성**을 선택합니다.

1. **기본 정보**에서 다음과 같이 합니다.

   1. **함수 이름**에 `s3-trigger-tutorial`을 입력합니다.

   1. **런타임**에서 **Python 3.14**를 선택합니다.

   1. **아키텍처**에서는 **x86\$164**를 선택합니다.

1. **기본 실행 역할 변경** 탭에서 다음을 수행합니다.

   1. 탭을 확장한 다음 **기존 역할 사용**을 선택합니다.

   1. 이전에 생성한 `lambda-s3-trigger-role`을 선택합니다.

1. **함수 생성**을 선택합니다.

## 함수 코드 배포
<a name="with-s3-example-deploy-code"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps6.png)


이 자습서에서는 Python 3.14 런타임을 사용하지만 다른 런타임의 예제 코드 파일도 제공했습니다. 다음 상자에서 탭을 선택하여 관심 있는 런타임에 대한 코드를 볼 수 있습니다.

Lambda 함수는 Amazon S3에서 수신한 `event` 파라미터에서 업로드된 객체의 키 이름과 버킷 이름을 검색합니다. 그런 다음 함수는 AWS SDK for Python (Boto3)의 [get\$1object](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3/client/get_object.html) 메서드를 사용하여 업로드된 객체의 콘텐츠 유형(MIME 유형)을 비롯한 객체의 메타데이터를 검색합니다.

**함수 코드 배포**

1. 다음 상자에서 **Python** 탭을 선택하고 코드를 복사합니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 S3 이벤트를 사용합니다.  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   ﻿using System.Threading.Tasks;
   using Amazon.Lambda.Core;
   using Amazon.S3;
   using System;
   using Amazon.Lambda.S3Events;
   using System.Web;
   
   // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
   [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
   
   namespace S3Integration
   {
       public class Function
       {
           private static AmazonS3Client _s3Client;
           public Function() : this(null)
           {
           }
   
           internal Function(AmazonS3Client s3Client)
           {
               _s3Client = s3Client ?? new AmazonS3Client();
           }
   
           public async Task<string> Handler(S3Event evt, ILambdaContext context)
           {
               try
               {
                   if (evt.Records.Count <= 0)
                   {
                       context.Logger.LogLine("Empty S3 Event received");
                       return string.Empty;
                   }
   
                   var bucket = evt.Records[0].S3.Bucket.Name;
                   var key = HttpUtility.UrlDecode(evt.Records[0].S3.Object.Key);
   
                   context.Logger.LogLine($"Request is for {bucket} and {key}");
   
                   var objectResult = await _s3Client.GetObjectAsync(bucket, key);
   
                   context.Logger.LogLine($"Returning {objectResult.Key}");
   
                   return objectResult.Key;
               }
               catch (Exception e)
               {
                   context.Logger.LogLine($"Error processing request - {e.Message}");
   
                   return string.Empty;
               }
           }
       }
   }
   ```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 S3 이벤트를 사용합니다.  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   package main
   
   import (
   	"context"
   	"log"
   
   	"github.com/aws/aws-lambda-go/events"
   	"github.com/aws/aws-lambda-go/lambda"
   	"github.com/aws/aws-sdk-go-v2/config"
   	"github.com/aws/aws-sdk-go-v2/service/s3"
   )
   
   func handler(ctx context.Context, s3Event events.S3Event) error {
   	sdkConfig, err := config.LoadDefaultConfig(ctx)
   	if err != nil {
   		log.Printf("failed to load default config: %s", err)
   		return err
   	}
   	s3Client := s3.NewFromConfig(sdkConfig)
   
   	for _, record := range s3Event.Records {
   		bucket := record.S3.Bucket.Name
   		key := record.S3.Object.URLDecodedKey
   		headOutput, err := s3Client.HeadObject(ctx, &s3.HeadObjectInput{
   			Bucket: &bucket,
   			Key:    &key,
   		})
   		if err != nil {
   			log.Printf("error getting head of object %s/%s: %s", bucket, key, err)
   			return err
   		}
   		log.Printf("successfully retrieved %s/%s of type %s", bucket, key, *headOutput.ContentType)
   	}
   
   	return nil
   }
   
   func main() {
   	lambda.Start(handler)
   }
   ```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda로 S3 이벤트를 사용합니다.  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   package example;
   
   import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
   import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
   import software.amazon.awssdk.services.s3.S3Client;
   
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   import com.amazonaws.services.lambda.runtime.events.S3Event;
   import com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3EventNotificationRecord;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   public class Handler implements RequestHandler<S3Event, String> {
       private static final Logger logger = LoggerFactory.getLogger(Handler.class);
       @Override
       public String handleRequest(S3Event s3event, Context context) {
           try {
             S3EventNotificationRecord record = s3event.getRecords().get(0);
             String srcBucket = record.getS3().getBucket().getName();
             String srcKey = record.getS3().getObject().getUrlDecodedKey();
   
             S3Client s3Client = S3Client.builder().build();
             HeadObjectResponse headObject = getHeadObject(s3Client, srcBucket, srcKey);
   
             logger.info("Successfully retrieved " + srcBucket + "/" + srcKey + " of type " + headObject.contentType());
   
             return "Ok";
           } catch (Exception e) {
             throw new RuntimeException(e);
           }
       }
   
       private HeadObjectResponse getHeadObject(S3Client s3Client, String bucket, String key) {
           HeadObjectRequest headObjectRequest = HeadObjectRequest.builder()
                   .bucket(bucket)
                   .key(key)
                   .build();
           return s3Client.headObject(headObjectRequest);
       }
   }
   ```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda로 S3 이벤트를 사용합니다.  

   ```
   import { S3Client, HeadObjectCommand } from "@aws-sdk/client-s3";
   
   const client = new S3Client();
   
   export const handler = async (event, context) => {
   
       // Get the object from the event and show its content type
       const bucket = event.Records[0].s3.bucket.name;
       const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
   
       try {
           const { ContentType } = await client.send(new HeadObjectCommand({
               Bucket: bucket,
               Key: key,
           }));
   
           console.log('CONTENT TYPE:', ContentType);
           return ContentType;
   
       } catch (err) {
           console.log(err);
           const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
           console.log(message);
           throw new Error(message);
       }
   };
   ```
TypeScript를 사용하여 Lambda로 S3 이벤트를 사용합니다.  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   import { S3Event } from 'aws-lambda';
   import { S3Client, HeadObjectCommand } from '@aws-sdk/client-s3';
   
   const s3 = new S3Client({ region: process.env.AWS_REGION });
   
   export const handler = async (event: S3Event): Promise<string | undefined> => {
     // Get the object from the event and show its content type
     const bucket = event.Records[0].s3.bucket.name;
     const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
     const params = {
       Bucket: bucket,
       Key: key,
     };
     try {
       const { ContentType } = await s3.send(new HeadObjectCommand(params));
       console.log('CONTENT TYPE:', ContentType);
       return ContentType;
     } catch (err) {
       console.log(err);
       const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
       console.log(message);
       throw new Error(message);
     }
   };
   ```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 S3 이벤트 사용.  

   ```
   <?php
   
   use Bref\Context\Context;
   use Bref\Event\S3\S3Event;
   use Bref\Event\S3\S3Handler;
   use Bref\Logger\StderrLogger;
   
   require __DIR__ . '/vendor/autoload.php';
   
   
   class Handler extends S3Handler 
   {
       private StderrLogger $logger;
       public function __construct(StderrLogger $logger)
       {
           $this->logger = $logger;
       }
       
       public function handleS3(S3Event $event, Context $context) : void
       {
           $this->logger->info("Processing S3 records");
   
           // Get the object from the event and show its content type
           $records = $event->getRecords();
           
           foreach ($records as $record) 
           {
               $bucket = $record->getBucket()->getName();
               $key = urldecode($record->getObject()->getKey());
   
               try {
                   $fileSize = urldecode($record->getObject()->getSize());
                   echo "File Size: " . $fileSize . "\n";
                   // TODO: Implement your custom processing logic here
               } catch (Exception $e) {
                   echo $e->getMessage() . "\n";
                   echo 'Error getting object ' . $key . ' from bucket ' . $bucket . '. Make sure they exist and your bucket is in the same region as this function.' . "\n";
                   throw $e;
               }
           }
       }
   }
   
   $logger = new StderrLogger();
   return new Handler($logger);
   ```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 S3 이벤트를 사용합니다.  

   ```
   # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   # SPDX-License-Identifier: Apache-2.0
   import json
   import urllib.parse
   import boto3
   
   print('Loading function')
   
   s3 = boto3.client('s3')
   
   
   def lambda_handler(event, context):
       #print("Received event: " + json.dumps(event, indent=2))
   
       # Get the object from the event and show its content type
       bucket = event['Records'][0]['s3']['bucket']['name']
       key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
       try:
           response = s3.get_object(Bucket=bucket, Key=key)
           print("CONTENT TYPE: " + response['ContentType'])
           return response['ContentType']
       except Exception as e:
           print(e)
           print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
           raise e
   ```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 S3 이벤트 사용.  

   ```
   require 'json'
   require 'uri'
   require 'aws-sdk'
   
   puts 'Loading function'
   
   def lambda_handler(event:, context:)
     s3 = Aws::S3::Client.new(region: 'region') # Your AWS region
     # puts "Received event: #{JSON.dump(event)}"
   
     # Get the object from the event and show its content type
     bucket = event['Records'][0]['s3']['bucket']['name']
     key = URI.decode_www_form_component(event['Records'][0]['s3']['object']['key'], Encoding::UTF_8)
     begin
       response = s3.get_object(bucket: bucket, key: key)
       puts "CONTENT TYPE: #{response.content_type}"
       return response.content_type
     rescue StandardError => e
       puts e.message
       puts "Error getting object #{key} from bucket #{bucket}. Make sure they exist and your bucket is in the same region as this function."
       raise e
     end
   end
   ```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-s3-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 S3 이벤트를 사용합니다.  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   use aws_lambda_events::event::s3::S3Event;
   use aws_sdk_s3::{Client};
   use lambda_runtime::{run, service_fn, Error, LambdaEvent};
   
   
   /// Main function
   #[tokio::main]
   async fn main() -> Result<(), Error> {
       tracing_subscriber::fmt()
           .with_max_level(tracing::Level::INFO)
           .with_target(false)
           .without_time()
           .init();
   
       // Initialize the AWS SDK for Rust
       let config = aws_config::load_from_env().await;
       let s3_client = Client::new(&config);
   
       let res = run(service_fn(|request: LambdaEvent<S3Event>| {
           function_handler(&s3_client, request)
       })).await;
   
       res
   }
   
   async fn function_handler(
       s3_client: &Client,
       evt: LambdaEvent<S3Event>
   ) -> Result<(), Error> {
       tracing::info!(records = ?evt.payload.records.len(), "Received request from SQS");
   
       if evt.payload.records.len() == 0 {
           tracing::info!("Empty S3 event received");
       }
   
       let bucket = evt.payload.records[0].s3.bucket.name.as_ref().expect("Bucket name to exist");
       let key = evt.payload.records[0].s3.object.key.as_ref().expect("Object key to exist");
   
       tracing::info!("Request is for {} and object {}", bucket, key);
   
       let s3_get_object_result = s3_client
           .get_object()
           .bucket(bucket)
           .key(key)
           .send()
           .await;
   
       match s3_get_object_result {
           Ok(_) => tracing::info!("S3 Get Object success, the s3GetObjectResult contains a 'body' property of type ByteStream"),
           Err(_) => tracing::info!("Failure with S3 Get Object request")
       }
   
       Ok(())
   }
   ```

------

1. Lambda 콘솔의 **코드 소스** 창에서 Code Editor에 코드를 붙여넣고 Lambda가 생성한 코드를 바꿉니다.

1. **배포** 섹션에서 **배포**를 선택하여 함수의 코드를 업데이트하세요.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

## Amazon S3 트리거를 생성합니다
<a name="with-s3-example-create-trigger"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps7.png)


**Amazon S3 트리거 생성 방법**

1. **함수 개요** 창에서 **트리거 추가**를 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/overview-trigger.png)

1. **S3**를 선택합니다.

1. **버킷**에서 자습서 앞부분에서 생성한 버킷을 선택합니다.

1. **이벤트 유형**에서 **모든 객체 생성 이벤트**를 선택합니다.

1. **재귀 호출**에서 확인란을 선택하여 입력 및 출력에 동일한 Amazon S3 버킷 사용이 권장되지 않음을 확인합니다.

1. **추가**를 선택합니다.

**참고**  
Lambda 콘솔을 사용하여 Lambda 함수에 대한 Amazon S3 트리거를 생성하면 Amazon S3는 사용자가 지정한 버킷에 대한 [이벤트 알림](https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventNotifications.html)을 구성합니다. Amazon S3는 이 이벤트 알림을 구성하기 전에 일련의 검사를 수행하여 이벤트 대상이 존재하고 필수 IAM 정책을 갖추고 있는지 확인합니다. Amazon S3는 해당 버킷에 대해 구성된 다른 모든 이벤트 알림에 대해서도 이러한 테스트를 수행합니다.  
이 검사 때문에 버킷이 이전에 더 이상 존재하지 않는 리소스나 필요한 권한 정책이 없는 리소스에 대한 이벤트 대상을 구성한 경우 Amazon S3는 새 이벤트 알림을 생성할 수 없습니다. 트리거를 생성할 수 없음을 나타내는 다음 오류 메시지가 나타납니다.  

```
An error occurred when creating the trigger: Unable to validate the following destination configurations.
```
이전에 동일한 버킷을 사용하여 다른 Lambda 함수에 대한 트리거를 구성한 후 함수를 삭제하거나 해당 권한 정책을 수정한 경우 이 오류가 나타날 수 있습니다.

## 더미 이벤트로 Lambda 함수 테스트
<a name="with-s3-example-test-dummy-event"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps8.png)


**더미 이벤트로 Lambda 함수 테스트**

1. 함수의 Lambda 콘솔 페이지에서 **테스트** 탭을 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/test-tab.png)

1. **이벤트 이름**에 `MyTestEvent`를 입력합니다.

1. **이벤트 JSON**에서 다음 테스트 이벤트를 붙여넣습니다. 해당 값을 바꿉니다.
   + `us-east-1`을 Amazon S3 버킷을 생성한 리전으로 바꿉니다.
   + `amzn-s3-demo-bucket`의 두 인스턴스를 모두 자체 Amazon S3 버킷의 이름으로 바꿉니다.
   + `test%2FKey`를 이전에 버킷에 업로드한 테스트 객체의 이름(예: `HappyFace.jpg`)으로 바꿉니다.

   ```
   {
     "Records": [
       {
         "eventVersion": "2.0",
         "eventSource": "aws:s3",
         "awsRegion": "us-east-1",
         "eventTime": "1970-01-01T00:00:00.000Z",
         "eventName": "ObjectCreated:Put",
         "userIdentity": {
           "principalId": "EXAMPLE"
         },
         "requestParameters": {
           "sourceIPAddress": "127.0.0.1"
         },
         "responseElements": {
           "x-amz-request-id": "EXAMPLE123456789",
           "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
         },
         "s3": {
           "s3SchemaVersion": "1.0",
           "configurationId": "testConfigRule",
           "bucket": {
             "name": "amzn-s3-demo-bucket",
             "ownerIdentity": {
               "principalId": "EXAMPLE"
             },
             "arn": "arn:aws:s3:::amzn-s3-demo-bucket"
           },
           "object": {
             "key": "test%2Fkey",
             "size": 1024,
             "eTag": "0123456789abcdef0123456789abcdef",
             "sequencer": "0A1B2C3D4E5F678901"
           }
         }
       }
     ]
   }
   ```

1. **저장**을 선택합니다.

1. **테스트**를 선택합니다.

1. 함수가 성공적으로 실행되면 **실행 결과** 탭에 다음과 비슷한 출력이 표시됩니다.

   ```
   Response
   "image/jpeg"
   
   Function Logs
   START RequestId: 12b3cae7-5f4e-415e-93e6-416b8f8b66e6 Version: $LATEST
   2021-02-18T21:40:59.280Z    12b3cae7-5f4e-415e-93e6-416b8f8b66e6    INFO    INPUT BUCKET AND KEY:  { Bucket: 'amzn-s3-demo-bucket', Key: 'HappyFace.jpg' }
   2021-02-18T21:41:00.215Z    12b3cae7-5f4e-415e-93e6-416b8f8b66e6    INFO    CONTENT TYPE: image/jpeg
   END RequestId: 12b3cae7-5f4e-415e-93e6-416b8f8b66e6
   REPORT RequestId: 12b3cae7-5f4e-415e-93e6-416b8f8b66e6    Duration: 976.25 ms    Billed Duration: 977 ms    Memory Size: 128 MB    Max Memory Used: 90 MB    Init Duration: 430.47 ms        
   
   Request ID
   12b3cae7-5f4e-415e-93e6-416b8f8b66e6
   ```

### Amazon S3 트리거로 Lambda 함수 테스트
<a name="with-s3-example-test-s3-trigger"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-example/s3trigger_tut_steps9.png)


구성된 트리거로 함수를 테스트하려면 콘솔을 사용하여 Amazon S3 버킷에 객체를 업로드합니다. Lambda 함수가 예상대로 실행되었는지 확인하려면 CloudWatch 로그를 사용하여 함수의 출력을 확인합니다.

**Amazon S3 버킷에 객체 업로드**

1. Amazon S3 콘솔의 [버킷](https://console.aws.amazon.com/s3/buckets) 페이지를 열고 앞서 생성한 버킷을 선택합니다.

1. **업로드**를 선택합니다.

1. **파일 추가**를 선택하고 파일 선택기를 사용하여 업로드할 객체를 선택합니다. 이 객체는 사용자가 선택한 임의의 파일이 될 수 있습니다.

1. **열기**를 선택한 후 **업로드**를 선택합니다.

**CloudWatch Logs를 사용하여 함수 간접 호출을 확인하려면 다음을 수행합니다.**

1. [CloudWatch 콘솔](https://console.aws.amazon.com/cloudwatch/home)을 엽니다.

1. Lambda 함수를 생성한 동일한 AWS 리전에서 작업 중인지 확인합니다. 화면 상단의 드롭다운 목록을 사용하여 리전을 변경할 수 있습니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/console_region_select.png)

1. **로그**를 선택한 후 **로그 그룹**을 선택합니다.

1. 함수에 대한 로그 그룹(`/aws/lambda/s3-trigger-tutorial`)을 선택합니다.

1. **로그 스트림**에서 가장 최근의 로그 스트림을 선택합니다.

1. Amazon S3 트리거에 대한 응답으로 함수가 제대로 간접적으로 간접 호출된 경우 다음과 유사한 출력이 표시됩니다. 표시되는 `CONTENT TYPE`은 버킷에 업로드한 파일 유형에 따라 달라집니다.

   ```
   2022-05-09T23:17:28.702Z	0cae7f5a-b0af-4c73-8563-a3430333cc10	INFO	CONTENT TYPE: image/jpeg
   ```

## 리소스 정리
<a name="cleanup"></a>

이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.

**Lambda 함수를 삭제하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 생성한 함수를 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **confirm**를 입력하고 **Delete**(삭제)를 선택합니다.

**집행 역할 삭제**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. 생성한 실행 역할을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 역할의 이름을 입력하고 **Delete**(삭제)를 선택합니다.

**S3 버킷을 삭제하려면**

1. [Amazon S3 콘솔](https://console.aws.amazon.com//s3/home#)을 엽니다.

1. 생성한 버킷을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 버킷 이름을 입력합니다.

1. **버킷 삭제(Delete bucket)**를 선택합니다.

## 다음 단계
<a name="next-steps"></a>

[자습서: Amazon S3 트리거를 사용하여 썸네일 이미지 생성](with-s3-tutorial.md)에서는 Amazon S3 트리거가 함수를 간접적으로 간접 호출하여 버킷에 업로드된 각 이미지 파일에 대해 썸네일 이미지를 생성합니다. 이 자습서를 진행하려면 중급 수준의 AWS 및 Lambda 분야 지식이 필요합니다. AWS Command Line Interface(AWS CLI)를 사용하여 리소스를 생성하는 방법과 함수 및 해당 종속성에 대한 .zip 파일 아카이브 배포 패키지를 생성하는 방법을 설명합니다.

# 자습서: Amazon S3 트리거를 사용하여 썸네일 이미지 생성
<a name="with-s3-tutorial"></a>

이 자습서에서는 Amazon Simple Storage Service(Amazon S3) 버킷에 추가된 이미지의 크기를 조정하는 Lambda 함수를 생성하고 구성합니다. 버킷에 이미지 파일을 추가하면 Amazon S3가 Lambda 함수를 간접적으로 간접 호출합니다. 그런 다음 함수는 이미지의 썸네일 버전을 생성하고 이를 다른 Amazon S3 버킷으로 출력합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_resources.png)


이 자습서를 완료하려면 다음 단계를 수행하세요.

1. 원본 및 대상 Amazon S3 버킷을 생성하고 샘플 이미지를 업로드합니다.

1. 이미지 크기를 조정하고 Amazon S3 버킷에 썸네일을 출력하는 Lambda 함수를 생성합니다.

1. 객체가 원본 버킷에 업로드될 때 함수를 간접적으로 간접 호출하는 Lambda 트리거를 구성합니다.

1. 먼저 더미 이벤트를 사용한 다음 원본 버킷에 이미지를 업로드하여 함수를 테스트하세요.

이 단계를 완료하면 Lambda를 사용하여 Amazon S3 버킷에 추가된 객체에 대한 파일 처리 작업을 수행하는 방법을 배우게 됩니다. AWS Command Line Interface 또는 AWS CLI(AWS Management Console)를 사용하여 이 자습서를 완료할 수 있습니다.

Lambda를 위한 Amazon S3 트리거를 구성하는 방법을 배울 수 있는 더 간단한 예제를 찾고 있다면 [자습서: Amazon S3 트리거를 사용하여 Lambda 함수 간접 호출](https://docs.aws.amazon.com/lambda/latest/dg/with-s3-example.html)을 살펴보세요.

**Topics**
+ [

## 사전 조건
](#with-s3-example-prereqs)
+ [

## 두 개의 Amazon S3 버킷 생성
](#with-s3-tutorial-prepare-create-buckets)
+ [

## 원본 버킷에 테스트 이미지 업로드
](#with-s3-tutorial-test-image)
+ [

## 권한 정책 생성
](#with-s3-tutorial-create-policy)
+ [

## 실행 역할 만들기
](#with-s3-tutorial-create-execution-role)
+ [

## 함수 배포 패키지 생성
](#with-s3-tutorial-create-function-package)
+ [

## Lambda 함수 생성
](#with-s3-tutorial-create-function-createfunction)
+ [

## 함수를 간접적으로 간접 호출하도록 Amazon S3 구성
](#with-s3-tutorial-configure-s3-trigger)
+ [

## 더미 이벤트로 Lambda 함수 테스트
](#with-s3-tutorial-dummy-test)
+ [

## Amazon S3 트리거를 사용하여 함수 테스트
](#with-s3-tutorial-test-s3)
+ [

## 리소스 정리
](#s3-tutorial-cleanup)

## 사전 조건
<a name="with-s3-example-prereqs"></a>

AWS CLI를 사용하여 튜토리얼을 완료하려면 [AWS Command Line Interface의 최신 버전]()을 설치하세요.

Lambda 함수 코드의 경우 Python 또는 Node.js를 사용할 수 있습니다. 사용하려는 언어의 언어 지원 도구 및 패키지 관리자를 설치합니다.

### AWS Command Line Interface 설치
<a name="install_aws_cli"></a>

아직 AWS Command Line Interface를 설치하지 않은 경우 [AWS CLI의 최신 버전 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)에서 설명하는 단계에 따라 설치하세요.

이 자습서에서는 명령을 실행할 셸 또는 명령줄 터미널이 필요합니다. Linux 및 macOS에서는 선호하는 셸과 패키지 관리자를 사용합니다.

**참고**  
Windows에서는 Lambda와 함께 일반적으로 사용하는 일부 Bash CLI 명령(예:`zip`)은 운영 체제의 기본 제공 터미널에서 지원되지 않습니다. Ubuntu와 Bash의 Windows 통합 버전을 가져오려면 [Linux용 Windows Subsystem을 설치](https://docs.microsoft.com/en-us/windows/wsl/install-win10)합니다.

## 두 개의 Amazon S3 버킷 생성
<a name="with-s3-tutorial-prepare-create-buckets"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps1.png)


먼저 두 개의 Amazon S3 버킷을 생성합니다. 첫 번째 버킷은 이미지를 업로드할 원본 버킷입니다. 두 번째 버킷은 Lambda에서 함수를 간접적으로 간접 호출할 때 크기 조정된 의 썸네일을 저장하는 데 사용됩니다.

------
#### [ AWS Management Console ]

**Amazon S3 버킷을 생성하려면(콘솔)**

1. [Amazon S3 콘솔](https://console.aws.amazon.com/s3)을 열고 **범용 버킷** 페이지를 선택합니다.

1. 지리적 위치와 가장 가까운 AWS 리전을 선택합니다. 화면 상단의 드롭다운 목록을 사용하여 리전을 변경할 수 있습니다. 자습서 뒷부분에서 동일한 리전에 Lambda 함수를 생성해야 합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/console_region_select.png)

1. **버킷 생성**을 선택합니다.

1. [**일반 구성(General configuration)**]에서 다음을 수행합니다.

   1. **버킷 유형**에서 **범용**을 선택했는지 확인합니다.

   1. **버킷 이름**에 Amazon S3 [버킷 이름 지정 규칙](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)을 충족하는 전역적으로 고유한 이름을 입력합니다. 버킷 이름은 소문자, 숫자, 점(.) 및 하이픈(-)만 포함할 수 있습니다.

1. 다른 모든 옵션을 기본값으로 두고 **버킷 생성**을 선택합니다.

1. 1\$15단계를 반복하여 대상 버킷을 생성합니다. **버킷 이름**에 `amzn-s3-demo-source-bucket-resized`를 입력합니다. 여기서 `amzn-s3-demo-source-bucket`은 방금 생성한 원본 버킷의 이름입니다.

------
#### [ AWS CLI ]

**Amazon S3 버킷을 생성하려면(AWS CLI)**

1. 다음 CLI 명령을 실행하여 원본 버킷을 생성합니다. 버킷에 대해 선택하는 이름은 전역적으로 고유해야 하며 Amazon S3 [버킷 이름 지정 규칙](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html)을 따라야 합니다. 이름에는 소문자, 숫자, 점(.), 하이픈(-)만 사용할 수 있습니다. `region` 및 `LocationConstraint`의 경우 지리적 위치와 가장 가까운 [AWS 리전](https://docs.aws.amazon.com/general/latest/gr/lambda-service.html)을 선택하세요.

   ```
   aws s3api create-bucket --bucket amzn-s3-demo-source-bucket --region us-east-1 \
   --create-bucket-configuration LocationConstraint=us-east-1
   ```

   자습서의 뒷부분에서 원본 버킷과 동일한 AWS 리전에 Lambda 함수를 생성해야 하므로 선택한 리전을 기록해 둡니다.

1. 다음 명령을 실행하여 대상 버킷을 생성합니다. 버킷 이름에는 `amzn-s3-demo-source-bucket-resized`를 사용해야 합니다. 여기서 `amzn-s3-demo-source-bucket`은 1단계에서 생성한 원본 버킷의 이름입니다. `region` 및 `LocationConstraint`의 경우 원본 버킷을 만들 때 사용한 것과 동일한 AWS 리전을 선택합니다.

   ```
   aws s3api create-bucket --bucket amzn-s3-demo-source-bucket-resized --region us-east-1 \
   --create-bucket-configuration LocationConstraint=us-east-1
   ```

------

## 원본 버킷에 테스트 이미지 업로드
<a name="with-s3-tutorial-test-image"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps2.png)


자습서의 뒷부분에서 AWS CLI 또는 Lambda 콘솔을 사용해 Lambda 함수를 호출하여 테스트합니다. 함수가 올바르게 작동하는지 확인하려면 원본 버킷에 테스트 이미지가 포함되어 있어야 합니다. 이 이미지는 선택한 JPG 또는 PNG 파일일 수 있습니다.

------
#### [ AWS Management Console ]

**원본 버킷에 테스트 이미지를 업로드하려면(콘솔)**

1. Amazon S3 콘솔의 [버킷](https://console.aws.amazon.com/s3/buckets) 페이지를 엽니다.

1. 이전 단계에서 생성한 소스 버킷을 선택합니다.

1. **업로드**를 선택합니다.

1. **파일 추가**를 선택하고 파일 선택기를 사용하여 업로드할 객체를 선택합니다.

1. **열기**를 선택한 후 **업로드**를 선택합니다.

------
#### [ AWS CLI ]

**원본 버킷에 테스트 이미지를 업로드하려면(AWS CLI)**
+ 업로드하려는 이미지가 포함된 디렉터리에서 다음 CLI 명령을 실행합니다. `--bucket` 파라미터를 원본 버킷의 이름으로 바꿉니다. `--key` 및 `--body` 파라미터에는 테스트 이미지의 파일 이름을 사용합니다.

  ```
  aws s3api put-object --bucket amzn-s3-demo-source-bucket --key HappyFace.jpg --body ./HappyFace.jpg
  ```

------

## 권한 정책 생성
<a name="with-s3-tutorial-create-policy"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps3.png)


Lambda 함수를 생성하는 첫 번째 단계는 권한 정책의 생성입니다. 이 정책은 함수에 다른 AWS 리소스에 액세스하는 데 필요한 권한을 부여합니다. 이 자습서에서 정책을 통해 Amazon S3 버킷에 대한 읽기 및 쓰기 권한을 Lambda에 부여하고 Amazon CloudWatch Logs에 쓸 수 있습니다.

------
#### [ AWS Management Console ]

**정책을 생성하려면(콘솔)**

1. AWS Identity and Access Management(IAM) 콘솔의 [정책 페이지](https://console.aws.amazon.com/iamv2/home#policies)를 엽니다.

1. **정책 생성**을 선택합니다.

1. **JSON** 탭에서 다음과 같은 사용자 지정 정책을 JSON 편집기에 붙여 넣습니다.  
****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "logs:PutLogEvents",
                   "logs:CreateLogGroup",
                   "logs:CreateLogStream"
               ],
               "Resource": "arn:aws:logs:*:*:*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:GetObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:PutObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           }
       ]
   }
   ```

1. **다음**을 선택합니다.

1. **정책 세부 정보**의 **정책 이름**에 `LambdaS3Policy`를 입력합니다.

1. **정책 생성**을 선택합니다.

------
#### [ AWS CLI ]

**정책을 생성하려면(AWS CLI)**

1. 다음 JSON을 `policy.json`이라는 파일로 저장합니다.  
****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "logs:PutLogEvents",
                   "logs:CreateLogGroup",
                   "logs:CreateLogStream"
               ],
               "Resource": "arn:aws:logs:*:*:*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:GetObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "s3:PutObject"
               ],
               "Resource": "arn:aws:s3:::*/*"
           }
       ]
   }
   ```

1. JSON 정책 문서를 저장한 디렉터리에서 다음 CLI 명령을 실행합니다.

   ```
   aws iam create-policy --policy-name LambdaS3Policy --policy-document file://policy.json
   ```

------

## 실행 역할 만들기
<a name="with-s3-tutorial-create-execution-role"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps4.png)


실행 역할은 AWS 서비스 및 리소스에 액세스할 수 있는 권한을 Lambda 함수에 부여하는 IAM 역할입니다. 함수에 Amazon S3 버킷에 대한 읽기 및 쓰기 액세스 권한을 부여하려면 이전 단계에서 생성한 권한 정책을 연결합니다.

------
#### [ AWS Management Console ]

**실행 역할을 생성하고 권한 정책을 연결하려면(콘솔)**

1. (IAM) 콘솔의 [역할](https://console.aws.amazon.com/iamv2/home#roles) 페이지를 엽니다.

1. **역할 생성**을 선택합니다.

1. **신뢰할 수 있는 엔터티 유형**으로 **AWS 서비스**를 선택하고 **사용 사례**로 **Lambda**를 선택합니다.

1. **다음**을 선택합니다.

1. 다음을 수행하여 이전 단계에서 생성한 권한 정책을 추가합니다.

   1. 정책 검색 상자에 `LambdaS3Policy`를 입력합니다.

   1. 검색 결과에서 `LambdaS3Policy`에 대한 확인란을 선택합니다.

   1. **다음**을 선택합니다.

1. **역할 세부 정보**의 **역할 이름**에 `LambdaS3Role`을 입력합니다.

1. **역할 생성**을 선택합니다.

------
#### [ AWS CLI ]

**실행 역할을 생성하고 권한 정책을 연결하려면(AWS CLI)**

1. 다음 JSON을 `trust-policy.json`이라는 파일로 저장합니다. 이 신뢰 정책을 통해 Lambda는 서비스 보안 주체에 `lambda.amazonaws.com` 권한을 제공하여 AWS Security Token Service(AWS STS) `AssumeRole` 작업을 호출하기 위해 역할의 권한을 사용할 수 있습니다.  
****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "lambda.amazonaws.com"
         },
         "Action": "sts:AssumeRole"
       }
     ]
   }
   ```

1. JSON 신뢰 정책 문서를 저장한 디렉터리에서 다음 CLI 명령을 실행하여 실행 역할을 생성합니다.

   ```
   aws iam create-role --role-name LambdaS3Role --assume-role-policy-document file://trust-policy.json
   ```

1. 이전 단계에서 생성한 권한 정책을 연결하려면 다음 CLI 명령을 실행합니다. 정책의 ARN에 있는 AWS 계정 번호를 자신의 계정 번호로 바꿉니다.

   ```
   aws iam attach-role-policy --role-name LambdaS3Role --policy-arn arn:aws:iam::123456789012:policy/LambdaS3Policy
   ```

------

## 함수 배포 패키지 생성
<a name="with-s3-tutorial-create-function-package"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps5.png)


함수를 생성하려면 함수 코드와 해당 종속 항목을 포함하는 *배포 패키지*를 생성합니다. 이 `CreateThumbnail` 함수의 경우 함수 코드는 이미지 크기 조정을 위해 별도의 라이브러리를 사용합니다. 선택한 언어의 지침에 따라 필요한 라이브러리가 포함된 배포 패키지를 생성합니다.

------
#### [ Node.js ]

**배포 패키지를 생성하려면(Node.js)**

1. 함수 코드 및 종속 항목에 대해 `lambda-s3`라는 디렉터리를 생성하고 해당 디렉터리로 이동합니다.

   ```
   mkdir lambda-s3
   cd lambda-s3
   ```

1. `npm`을 사용하여 새 Node.js 프로젝트를 생성합니다. 대화형 환경에서 제공되는 기본 옵션을 수락하려면 `Enter`을 누릅니다.

   ```
   npm init
   ```

1. 다음 함수 코드를 `index.mjs`라는 파일에 저장합니다. `us-east-1`를 소스 및 대상 버킷을 직접 만든 AWS 리전으로 바꿔야 합니다.

   ```
   // dependencies
   import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
   
   import { Readable } from 'stream';
   
   import sharp from 'sharp';
   import util from 'util';
   
   
   // create S3 client
   const s3 = new S3Client({region: 'us-east-1'});
   
   // define the handler function
   export const handler = async (event, context) => {
   
   // Read options from the event parameter and get the source bucket
   console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
     const srcBucket = event.Records[0].s3.bucket.name;
     
   // Object key may have spaces or unicode non-ASCII characters
   const srcKey    = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
   const dstBucket = srcBucket + "-resized";
   const dstKey    = "resized-" + srcKey;
   
   // Infer the image type from the file suffix
   const typeMatch = srcKey.match(/\.([^.]*)$/);
   if (!typeMatch) {
     console.log("Could not determine the image type.");
     return;
   }
   
   // Check that the image type is supported
   const imageType = typeMatch[1].toLowerCase();
   if (imageType != "jpg" && imageType != "png") {
     console.log(`Unsupported image type: ${imageType}`);
     return;
   }
   
   // Get the image from the source bucket. GetObjectCommand returns a stream.
   try {
     const params = {
       Bucket: srcBucket,
       Key: srcKey
     };
     var response = await s3.send(new GetObjectCommand(params));
     var stream = response.Body;
     
   // Convert stream to buffer to pass to sharp resize function.
     if (stream instanceof Readable) {
       var content_buffer = Buffer.concat(await stream.toArray());
       
     } else {
       throw new Error('Unknown object stream type');
     }
   
   
   } catch (error) {
     console.log(error);
     return;
   }
   
     
   // set thumbnail width. Resize will set the height automatically to maintain aspect ratio.
   const width  = 200;
   
   // Use the sharp module to resize the image and save in a buffer.
   try {    
     var output_buffer = await sharp(content_buffer).resize(width).toBuffer();
   
   } catch (error) {
     console.log(error);
     return;
   }
   
   // Upload the thumbnail image to the destination bucket
   try {
     const destparams = {
       Bucket: dstBucket,
       Key: dstKey,
       Body: output_buffer,
       ContentType: "image"
     };
   
     const putResult = await s3.send(new PutObjectCommand(destparams));
   
     } catch (error) {
       console.log(error);
       return;
     }
   
     console.log('Successfully resized ' + srcBucket + '/' + srcKey +
       ' and uploaded to ' + dstBucket + '/' + dstKey);
     };
   ```

1. `lambda-s3` 디렉터리에서 npm을 사용하여 sharp 라이브러리를 설치합니다. 최신 버전의 sharp(0.33)는 Lambda와 호환되지 않습니다. 이 자습서를 완료하려면 버전 0.32.6을 설치합니다.

   ```
   npm install sharp@0.32.6
   ```

   npm `install` 명령은 모듈을 위한 `node_modules` 디렉터리를 생성합니다. 이 단계 후에 디렉터리 구조는 다음과 같아야 합니다.

   ```
   lambda-s3
   |- index.mjs
   |- node_modules
   |  |- base64js
   |  |- bl
   |  |- buffer
   ...
   |- package-lock.json
   |- package.json
   ```

1. 함수 코드와 해당 종속 항목을 포함하는 .zip 배포 패키지를 생성합니다. MacOS 및 Linux에서 다음 명령을 실행합니다.

   ```
   zip -r function.zip .
   ```

   Windows에서 선호하는 zip 유틸리티를 사용하여 .zip 파일을 생성합니다. `index.mjs`, `package.json`, `package-lock.json` 파일과 `node_modules` 디렉터리가 모두 .zip 파일의 루트에 있는지 확인합니다.

------
#### [ Python ]

**배포 패키지를 생성하려면(Python)**

1. 예제 코드를 `lambda_function.py`라는 파일로 저장합니다.

   ```
   import boto3
   import os
   import sys
   import uuid
   from urllib.parse import unquote_plus
   from PIL import Image
   import PIL.Image
               
   s3_client = boto3.client('s3')
               
   def resize_image(image_path, resized_path):
     with Image.open(image_path) as image:
       image.thumbnail(tuple(x / 2 for x in image.size))
       image.save(resized_path)
               
   def lambda_handler(event, context):
     for record in event['Records']:
       bucket = record['s3']['bucket']['name']
       key = unquote_plus(record['s3']['object']['key'])
       tmpkey = key.replace('/', '')
       download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey)
       upload_path = '/tmp/resized-{}'.format(tmpkey)
       s3_client.download_file(bucket, key, download_path)
       resize_image(download_path, upload_path)
       s3_client.upload_file(upload_path, '{}-resized'.format(bucket), 'resized-{}'.format(key))
   ```

1. `lambda_function.py` 파일을 생성한 디렉터리에서 `package`라는 새 디렉터리를 생성하고 [Pillow(PIL)](https://pypi.org/project/Pillow/) 라이브러리와 AWS SDK for Python (Boto3)을 설치합니다. Lambda Python 런타임에는 Boto3 SDK 버전이 포함되어 있지만 런타임에 포함된 경우에도 함수의 모든 종속 항목을 배포 패키지에 추가하는 것이 좋습니다. 자세한 내용은 [Python의 런타임 종속 항목](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html#python-package-dependencies)을 참조하세요.

   ```
   mkdir package
   pip install \
   --platform manylinux2014_x86_64 \
   --target=package \
   --implementation cp \
   --python-version 3.12 \
   --only-binary=:all: --upgrade \
   pillow boto3
   ```

   Pillow 라이브러리에는 C/C\$1\$1 코드가 포함되어 있습니다. pip는 `--platform manylinux_2014_x86_64` 및 `--only-binary=:all:` 옵션을 사용하여 Amazon Linux 2 운영 체제와 호환되는 미리 컴파일된 바이너리가 포함된 Pillow 버전을 다운로드하고 설치합니다. 이렇게 하면 로컬 빌드 시스템의 운영 체제 및 아키텍처에 관계없이 배포 패키지가 Lambda 실행 환경에서 작동합니다.

1. 애플리케이션 코드와 Pillow 및 Boto3 라이브러리가 포함된 .zip 파일을 생성합니다. Linux 또는 MacOS에서 명령줄 인터페이스에서 다음 명령을 실행합니다.

   ```
   cd package
   zip -r ../lambda_function.zip .
   cd ..
   zip lambda_function.zip lambda_function.py
   ```

    Windows에서는 선호하는 zip 도구를 사용하여 `lambda_function.zip` 파일을 생성합니다. `lambda_function.py` 파일과 종속 항목이 포함된 폴더가 모두 .zip 파일의 루트에 있는지 확인합니다.

Python 가상 환경을 사용하여 배포 패키지를 생성할 수도 있습니다. [Python Lambda 함수에 대한 .zip 파일 아카이브 작업](python-package.md) 섹션을 참조하세요

------

## Lambda 함수 생성
<a name="with-s3-tutorial-create-function-createfunction"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps6.png)


AWS CLI 또는 Lambda 콘솔을 사용하여 Lambda 함수를 생성할 수 있습니다. 선택한 언어의 지침에 따라 함수를 생성합니다.

------
#### [ AWS Management Console ]

**Lambda 함수 생성(콘솔)**

콘솔을 사용하여 Lambda 함수를 생성하려면 먼저 일부 ‘Hello world’ 코드가 포함된 기본 함수를 생성합니다. 그런 다음 이전 단계에서 만든 .zip 또는 JAR 파일을 업로드하여 이 코드를 고유한 함수 코드로 바꿉니다.

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. Amazon S3 버킷을 생성한 동일한 AWS 리전에서 작업 중인지 확인합니다. 화면 상단의 드롭다운 목록을 사용하여 리전을 변경할 수 있습니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/console_region_select.png)

1. **함수 생성**을 선택합니다.

1. **새로 작성**을 선택합니다.

1. **기본 정보**에서 다음과 같이 합니다.

   1. [**함수 이름(Function name)**]에 `CreateThumbnail`을 입력합니다.

   1. **런타임**에서 선택한 함수 언어에 따라 **Node.js 22.x** 또는 **Python 3.12**를 선택하세요.

   1. **아키텍처**에서는 **x86\$164**를 선택합니다.

1. **기본 실행 역할 변경** 탭에서 다음을 수행합니다.

   1. 탭을 확장한 다음 **기존 역할 사용**을 선택합니다.

   1. 이전에 생성한 `LambdaS3Role`을 선택합니다.

1. **함수 생성**을 선택합니다.

**함수 코드를 업로드하려면(콘솔)**

1. **코드 소스** 창에서 **에서 업로드**를 선택합니다.

1. **.zip 파일**을 선택합니다.

1. **업로드**를 선택합니다.

1. 파일 선택기에서 .zip 파일을 선택하고 **열기**를 선택합니다.

1. **저장**을 선택합니다.

------
#### [ AWS CLI ]

**함수를 생성하려면(AWS CLI)**
+ 선택한 언어의 CLI 명령을 실행합니다. `role` 파라미터의 경우 `123456789012`를 자신의 AWS 계정 ID로 바꿉니다. `region` 파라미터의 경우 `us-east-1`를 Amazon S3 버킷을 생성한 리전으로 바꿉니다.
  + **Node.js**의 경우 `function.zip` 파일이 포함된 디렉터리에서 다음 명령을 실행합니다.

    ```
    aws lambda create-function --function-name CreateThumbnail \
    --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
    --timeout 10 --memory-size 1024 \
    --role arn:aws:iam::123456789012:role/LambdaS3Role --region us-east-1
    ```
  + **Python**의 경우 `lambda_function.zip` 파일이 포함된 디렉터리에서 다음 명령을 실행합니다.

    ```
    aws lambda create-function --function-name CreateThumbnail \
    --zip-file fileb://lambda_function.zip --handler lambda_function.lambda_handler \
    --runtime python3.14 --timeout 10 --memory-size 1024 \
    --role arn:aws:iam::123456789012:role/LambdaS3Role --region us-east-1
    ```

------

## 함수를 간접적으로 간접 호출하도록 Amazon S3 구성
<a name="with-s3-tutorial-configure-s3-trigger"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps7.png)


원본 버킷에 이미지를 업로드할 때 Lambda 함수를 실행하려면 함수에 대한 트리거를 구성해야 합니다. 콘솔 또는 AWS CLI를 사용하여 Amazon S3 트리거를 구성할 수 있습니다.

**중요**  
이 절차는 버킷에서 객체가 생성될 때마다 함수를 간접적으로 간접 호출하도록 Amazon S3 버킷을 구성합니다. 원본 버킷에서만 이를 구성해야 합니다. Lambda 함수가 함수를 간접적으로 간접 호출하는 동일한 버킷에 객체를 생성하는 경우 함수를 [루프에서 연속적으로 간접 호출](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/recursive-runaway)할 수 있습니다. 이로 인해 예상치 못한 요금이 AWS 계정에 청구될 수 있습니다.

------
#### [ AWS Management Console ]

**Amazon S3 트리거를 구성하려면(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 열고 함수(`CreateThumbnail`)를 선택합니다.

1. **트리거 추가**를 선택합니다.

1. **S3**를 선택합니다.

1. **버킷**에서 원본 버킷을 선택합니다.

1. **이벤트 유형**에서 **모든 객체 생성 이벤트**를 선택합니다.

1. **재귀 호출**에서 확인란을 선택하여 입력 및 출력에 동일한 Amazon S3 버킷 사용이 권장되지 않음을 확인합니다. Serverless Land의 [Recursive patterns that cause run-away Lambda functions](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/recursive-runaway)를 읽고 Lambda의 재귀 호출 패턴에 대해 자세히 알아볼 수 있습니다.

1. **추가**를 선택합니다.

   Lambda 콘솔을 사용하여 트리거를 생성하면 Lambda는 선택한 서비스에 함수 간접 호출 권한을 부여하는 [리소스 기반 정책](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html)을 자동으로 생성합니다.

------
#### [ AWS CLI ]

**Amazon S3 트리거를 구성하려면(AWS CLI)**

1. 이미지 파일을 추가할 때 Amazon S3 소스 버킷이 함수를 간접적으로 간접 호출하려면 먼저 [리소스 기반 정책](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html)을 사용하여 함수에 대한 권한을 구성해야 합니다. 리소스 기반 정책 설명은 함수를 간접적으로 간접 호출할 수 있는 다른 AWS 서비스 권한을 부여합니다. Amazon S3에 함수 간접 호출 권한을 부여하려면 다음 CLI 명령을 실행합니다. `source-account` 파라미터를 자신의 AWS 계정 ID로 바꾸고 고유한 원본 버킷 이름을 사용해야 합니다.

   ```
   aws lambda add-permission --function-name CreateThumbnail \
   --principal s3.amazonaws.com --statement-id s3invoke --action "lambda:InvokeFunction" \
   --source-arn arn:aws:s3:::amzn-s3-demo-source-bucket \
   --source-account 123456789012
   ```

   이 명령으로 정의하는 정책은 원본 버킷에서 작업이 발생할 때만 Amazon S3가 함수를 간접적으로 간접 호출하도록 허용합니다.
**참고**  
Amazon S3 버킷 이름은 전역적으로 고유하지만 리소스 기반 정책을 사용할 때는 버킷이 반드시 계정에 속하도록 지정하는 것이 가장 좋습니다. 버킷을 삭제하면 다른 AWS 계정가 동일한 Amazon 리소스 이름(ARN)으로 버킷을 생성할 수 있기 때문입니다.

1. 다음 JSON을 `notification.json`이라는 파일로 저장합니다. 이 JSON을 원본 버킷에 적용하면 JSON이 새 객체가 추가될 때마다 Lambda 함수에 알림을 보내도록 버킷을 구성합니다. Lambda 함수 ARN의 AWS 계정 번호와 AWS 리전을 자신의 계정 번호와 리전으로 바꿉니다.

   ```
   {
   "LambdaFunctionConfigurations": [
       {
         "Id": "CreateThumbnailEventConfiguration",
         "LambdaFunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:CreateThumbnail",
         "Events": [ "s3:ObjectCreated:Put" ]
       }
     ]
   }
   ```

1. 다음 CLI 명령을 실행하여 원본 버킷에 생성한 JSON 파일의 알림 설정을 적용합니다. `amzn-s3-demo-source-bucket`을 원본 버킷의 이름으로 바꿉니다.

   ```
   aws s3api put-bucket-notification-configuration --bucket amzn-s3-demo-source-bucket \
   --notification-configuration file://notification.json
   ```

   `put-bucket-notification-configuration` 명령 및 `notification-configuration` 옵션에 대한 자세한 내용은 *AWS CLI 명령 참조*의 [put-bucket-notification-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/put-bucket-notification-configuration.html)을 참조하세요.

------

## 더미 이벤트로 Lambda 함수 테스트
<a name="with-s3-tutorial-dummy-test"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps8.png)


Amazon S3 원본 버킷에 이미지 파일을 추가하여 전체 설정을 테스트하기 전에 더미 이벤트로 호출하여 Lambda 함수가 올바르게 작동하는지 테스트합니다. Lambda의 이벤트는 함수가 처리할 데이터가 포함된 JSON 형식의 문서입니다. 함수가 Amazon S3에 의해 간접적으로 간접 호출되면 함수로 전송된 이벤트에는 버킷 이름, 버킷 ARN, 객체 키와 같은 정보가 포함됩니다.

------
#### [ AWS Management Console ]

**더미 이벤트로 Lambda 함수를 테스트하려면(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 열고 함수(`CreateThumbnail`)를 선택합니다.

1. **테스트** 탭을 선택합니다.

1. 테스트 이벤트를 생성하려면 **테스트 이벤트** 창에서 다음을 수행합니다.

   1. **테스트 이벤트 작업**에서 **새 이벤트 생성**을 선택합니다.

   1. **이벤트 이름**에 **myTestEvent**를 입력합니다.

   1. **템플릿**에서 **S3 Put**을 선택합니다.

   1. 다음 파라미터의 값을 사용자 고유의 값으로 바꿉니다.
      + `awsRegion`의 경우 `us-east-1`을 Amazon S3 버킷을 생성한 AWS 리전으로 바꿉니다.
      + `name`의 경우 `amzn-s3-demo-bucket`을 사용자 고유의 Amazon S3 원본 버킷 이름으로 바꿉니다.
      + `key`의 경우 `test%2Fkey`를 [원본 버킷에 테스트 이미지 업로드](#with-s3-tutorial-test-image) 단계에서 원본 버킷에 업로드한 테스트 객체의 파일 이름으로 바꿉니다.

      ```
      {
        "Records": [
          {
            "eventVersion": "2.0",
            "eventSource": "aws:s3",
            "awsRegion": "us-east-1",
            "eventTime": "1970-01-01T00:00:00.000Z",
            "eventName": "ObjectCreated:Put",
            "userIdentity": {
              "principalId": "EXAMPLE"
            },
            "requestParameters": {
              "sourceIPAddress": "127.0.0.1"
            },
            "responseElements": {
              "x-amz-request-id": "EXAMPLE123456789",
              "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
            },
            "s3": {
              "s3SchemaVersion": "1.0",
              "configurationId": "testConfigRule",
              "bucket": {
                "name": "amzn-s3-demo-bucket",
                "ownerIdentity": {
                  "principalId": "EXAMPLE"
                },
                "arn": "arn:aws:s3:::amzn-s3-demo-bucket"
              },
              "object": {
                "key": "test%2Fkey",
                "size": 1024,
                "eTag": "0123456789abcdef0123456789abcdef",
                "sequencer": "0A1B2C3D4E5F678901"
              }
            }
          }
        ]
      }
      ```

   1. **저장**을 선택합니다.

1. **테스트 이벤트** 창에서 **테스트**를 선택합니다.

1. 함수가 이미지의 크기 조정된 버전을 생성하여 대상 Amazon S3 버킷에 저장했는지 확인하려면 다음을 수행합니다.

   1. Amazon S3 콘솔의 [버킷 페이지](https://console.aws.amazon.com/s3/buckets)를 엽니다.

   1. 대상 버킷을 선택하고 크기 조정된 파일이 **객체** 창에 나열되는지 확인합니다.

------
#### [ AWS CLI ]

**더미 이벤트로 Lambda 함수를 테스트하려면(AWS CLI)**

1. 다음 JSON을 `dummyS3Event.json`이라는 파일로 저장합니다. 다음 파라미터의 값을 고유한 값으로 바꿉니다.
   + `awsRegion`의 경우 `us-east-1`를 Amazon S3 버킷을 생성한 AWS 리전으로 바꿉니다.
   + `name`의 경우 `amzn-s3-demo-bucket`을 사용자 고유의 Amazon S3 원본 버킷 이름으로 바꿉니다.
   + `key`의 경우 `test%2Fkey`를 [원본 버킷에 테스트 이미지 업로드](#with-s3-tutorial-test-image) 단계에서 원본 버킷에 업로드한 테스트 객체의 파일 이름으로 바꿉니다.

   ```
   {
     "Records": [
       {
         "eventVersion": "2.0",
         "eventSource": "aws:s3",
         "awsRegion": "us-east-1",
         "eventTime": "1970-01-01T00:00:00.000Z",
         "eventName": "ObjectCreated:Put",
         "userIdentity": {
           "principalId": "EXAMPLE"
         },
         "requestParameters": {
           "sourceIPAddress": "127.0.0.1"
         },
         "responseElements": {
           "x-amz-request-id": "EXAMPLE123456789",
           "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
         },
         "s3": {
           "s3SchemaVersion": "1.0",
           "configurationId": "testConfigRule",
           "bucket": {
             "name": "amzn-s3-demo-bucket",
             "ownerIdentity": {
               "principalId": "EXAMPLE"
             },
             "arn": "arn:aws:s3:::amzn-s3-demo-bucket"
           },
           "object": {
             "key": "test%2Fkey",
             "size": 1024,
             "eTag": "0123456789abcdef0123456789abcdef",
             "sequencer": "0A1B2C3D4E5F678901"
           }
         }
       }
     ]
   }
   ```

1. `dummyS3Event.json` 파일을 저장한 디렉터리에서 다음 CLI 명령을 실행하여 함수를 간접적으로 간접 호출합니다. 이 명령은 간접 호출 유형 파라미터의 값으로 `RequestResponse`를 지정하여 Lambda 함수를 동기식으로 간접 호출합니다. 동기 및 비동기 호출에 대한 자세한 내용은 [Lambda 함수 호출](https://docs.aws.amazon.com/lambda/latest/dg/lambda-invocation.html)을 참조하세요.

   ```
   aws lambda invoke --function-name CreateThumbnail \
   --invocation-type RequestResponse --cli-binary-format raw-in-base64-out \
   --payload file://dummyS3Event.json outputfile.txt
   ```

   AWS CLI의 버전 2를 사용하는 경우 cli-binary-format 옵션이 필요합니다. 이 설정을 기본 설정으로 지정하려면 `aws configure set cli-binary-format raw-in-base64-out`을(를) 실행하세요. 자세한 내용은 [AWS CLI 지원 대상 전역적 명령줄 옵션](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)을 참조하세요.

1. 함수가 이미지의 썸네일 버전을 생성하여 대상 Amazon S3 버킷에 저장했는지 확인합니다. 다음 CLI 명령을 실행하여 `amzn-s3-demo-source-bucket-resized`를 대상 버킷 이름으로 바꿉니다.

   ```
   aws s3api list-objects-v2 --bucket amzn-s3-demo-source-bucket-resized
   ```

   다음과 유사한 출력 화면이 표시되어야 합니다. `Key` 파라미터는 크기 조정된 이미지의 파일 이름을 보여줍니다.

   ```
   {
       "Contents": [
           {
               "Key": "resized-HappyFace.jpg",
               "LastModified": "2023-06-06T21:40:07+00:00",
               "ETag": "\"d8ca652ffe83ba6b721ffc20d9d7174a\"",
               "Size": 2633,
               "StorageClass": "STANDARD"
           }
       ]
   }
   ```

------

## Amazon S3 트리거를 사용하여 함수 테스트
<a name="with-s3-tutorial-test-s3"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-s3-tutorial/s3thumb_tut_steps9.png)


Lambda 함수가 올바르게 작동하는지 확인했으니 Amazon S3 원본 버킷에 이미지 파일을 추가하여 전체 설정을 테스트할 준비가 되었습니다. 원본 버킷에 이미지를 추가하면 Lambda 함수가 자동으로 간접적으로 간접 호출됩니다. 함수는 파일의 크기 조정된 버전을 생성하여 대상 버킷에 저장합니다.

------
#### [ AWS Management Console ]

**Amazon S3 트리거를 사용하여 Lambda 함수를 테스트하려면(콘솔)**

1. Amazon S3 버킷에 이미지를 업로드하려면 다음을 수행합니다.

   1. Amazon S3 콘솔의 [버킷](https://console.aws.amazon.com/s3/buckets) 페이지를 열고 원본 버킷을 선택합니다.

   1. **업로드**를 선택합니다.

   1. **파일 추가**를 선택하고 파일 선택기를 사용하여 업로드하려는 이미지 파일을 선택합니다. 이미지 객체는 .jpg 또는 .png 파일일 수 있습니다.

   1. **열기**를 선택한 후 **업로드**를 선택합니다.

1. 다음을 수행하여 Lambda가 이미지 파일의 크기 조정된 버전을 대상 버킷에 저장했는지 확인합니다.

   1. Amazon S3 콘솔의 [버킷](https://console.aws.amazon.com/s3/buckets) 페이지로 돌아가서 대상 버킷을 선택합니다.

   1. 이제 **객체** 창에 크기 조정된 이미지 파일 두 개가 표시됩니다. 이는 Lambda 함수의 각 테스트에서 가져온 것입니다. 크기 조정된 이미지를 다운로드하려면 파일을 선택한 다음 **다운로드**를 선택합니다.

------
#### [ AWS CLI ]

**Amazon S3 트리거를 사용하여 Lambda 함수를 테스트하려면(AWS CLI)**

1. 업로드하려는 이미지가 포함된 디렉터리에서 다음 CLI 명령을 실행합니다. `--bucket` 파라미터를 원본 버킷의 이름으로 바꿉니다. `--key` 및 `--body` 파라미터에는 테스트 이미지의 파일 이름을 사용합니다. 테스트 이미지는 .jpg 또는 .png 파일일 수 있습니다.

   ```
   aws s3api put-object --bucket amzn-s3-demo-source-bucket --key SmileyFace.jpg --body ./SmileyFace.jpg
   ```

1. 함수가 이미지의 썸네일 버전을 생성하여 대상 Amazon S3 버킷에 저장했는지 확인합니다. 다음 CLI 명령을 실행하여 `amzn-s3-demo-source-bucket-resized`를 대상 버킷 이름으로 바꿉니다.

   ```
   aws s3api list-objects-v2 --bucket amzn-s3-demo-source-bucket-resized
   ```

   함수가 성공적으로 실행되면 다음과 유사한 출력이 표시됩니다. 이제 대상 버킷에는 크기 조정된 파일 두 개가 포함됩니다.

   ```
   {
       "Contents": [
           {
               "Key": "resized-HappyFace.jpg",
               "LastModified": "2023-06-07T00:15:50+00:00",
               "ETag": "\"7781a43e765a8301713f533d70968a1e\"",
               "Size": 2763,
               "StorageClass": "STANDARD"
           },
           {
               "Key": "resized-SmileyFace.jpg",
               "LastModified": "2023-06-07T00:13:18+00:00",
               "ETag": "\"ca536e5a1b9e32b22cd549e18792cdbc\"",
               "Size": 1245,
               "StorageClass": "STANDARD"
           }
       ]
   }
   ```

------

## 리소스 정리
<a name="s3-tutorial-cleanup"></a>

이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.

**Lambda 함수를 삭제하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 생성한 함수를 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **confirm**를 입력하고 **Delete**(삭제)를 선택합니다.

**생성한 정책을 삭제하려면**

1. IAM 콘솔에서 [정책 페이지](https://console.aws.amazon.com/iam/home#/policies)를 엽니다.

1. 생성한 정책(**AWSLambdaS3Policy**)을 선택합니다.

1. [**정책 작업(Policy actions)**], [**삭제(Delete)**]를 선택합니다.

1. **삭제**를 선택합니다.

**실행 역할을 삭제하려면**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. 생성한 실행 역할을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 역할의 이름을 입력하고 **Delete**(삭제)를 선택합니다.

**S3 버킷을 삭제하려면**

1. [Amazon S3 콘솔](https://console.aws.amazon.com//s3/home#)을 엽니다.

1. 생성한 버킷을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 버킷 이름을 입력합니다.

1. **버킷 삭제(Delete bucket)**를 선택합니다.

# Lambda 함수에서 Secrets Manager 보안 암호 사용
<a name="with-secrets-manager"></a>

AWS Secrets Manager를 사용하면 Lambda 함수에 필요한 자격 증명, API 키 및 기타 보안 암호를 관리할 수 있습니다. Lambda 함수에서 보안 암호 검색에 사용하는 두 가지 접근 방식이 있으며, 둘 다 AWS SDK를 사용하여 직접 보안 암호를 검색하는 것에 비해 성능이 향상되고 비용이 절감됩니다.
+ **AWS 파라미터 및 보안 암호 Lambda 확장** - 보안 암호 검색용으로 간단한 HTTP 인터페이스를 제공하는 런타임에 구애받지 않는 솔루션
+ **Powertools for AWS Lambda 파라미터 유틸리티** - 내장 변환을 통해 여러 공급자(Secrets Manager, Parameter Store, AppConfig)를 지원하는 코드 통합 솔루션

두 접근 방식 모두 보안 암호의 로컬 캐시를 유지하므로 모든 간접 호출에 대해 함수가 Secrets Manager를 직접 호출하도록 만들 필요가 없습니다. 함수가 보안 암호를 요청하면 먼저 캐시를 확인합니다. 보안 암호가 사용 가능하고 만료되지 않은 경우 즉시 반환됩니다. 캐시에 없으면 Secrets Manager에서 검색하여 캐시되고 반환됩니다. 이 캐싱 메커니즘은 API 직접 호출을 최소화하여 응답 시간을 단축하고 비용을 절감합니다.

## 접근 방식 선택
<a name="lambda-secrets-manager-choosing-approach"></a>

다음 요소를 고려하여 확장과 PowerTools 중에서 선택하세요.

AWS 파라미터 및 보안 암호 Lambda 확장 사용이 적합한 상황:  
+ Lambda 런타임에서 작동하는 런타임에 구애받지 않는 솔루션을 원하는 경우
+ 함수에 코드 종속성을 추가하지 않으려는 경우
+ Secrets Manager 또는 파라미터 스토어에서만 보안 암호를 검색하는 경우

Powertools for AWS Lambda 파라미터 유틸리티 사용이 적합한 상황:  
+ 애플리케이션 코드와 통합된 개발 환경을 원할 경우
+ 여러 공급자(Secrets Manager, Parameter Store, AppConfig)에 대한 지원이 필요한 경우
+ 내장 데이터 변환(JSON 구문 분석, base64 디코딩)을 원하는 경우
+ Python, TypeScript, Java 또는 .NET 런타임을 사용하는 경우

## Lambda에서 Secrets Manager를 사용해야 하는 경우
<a name="lambda-secrets-manager-when-to-use"></a>

Lambda에서 Secrets Manager를 사용하는 일반적인 시나리오는 다음과 같습니다.
+ 함수가 Amazon RDS 또는 기타 데이터베이스에 연결하는 데 사용하는 데이터베이스 자격 증명 저장
+ 함수가 직접적으로 호출하는 외부 서비스에 대한 API 키 관리
+ 암호화 키 또는 기타 민감한 구성 데이터 저장
+ 함수 코드를 업데이트할 필요 없이 자동으로 자격 증명 교체

## AWS 파라미터 및 보안 암호 Lambda 확장 사용
<a name="lambda-secrets-manager-extension-approach"></a>

AWS 파라미터 및 보안 암호 Lambda 확장은 모든 Lambda 런타임과 호환되는 간단한 HTTP 인터페이스를 사용합니다. 기본적으로 300초(5분) 동안 보안 암호를 캐싱하고 최대 1,000개의 보안 암호를 보관할 수 있습니다. [환경 변수를 사용하여 이러한 설정을 사용자 지정](#lambda-secrets-manager-env-vars)할 수 있습니다.

### Lambda 함수에서 Secrets Manager 사용
<a name="lambda-secrets-manager-setup"></a>

이 섹션에서는 Secrets Manager 보안 암호가 이미 있다고 가정합니다. 보안 암호를 생성하려면 [AWS Secrets Manager 보안 암호 생성](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)을 참조하세요.

#### 배포 패키지 생성
<a name="lambda-secrets-manager-function-code"></a>

원하는 런타임을 선택하고 단계에 따라 Secrets Manager에서 보안 암호를 검색하는 함수를 생성합니다. 예제 함수는 Secrets Manager에서 보안 암호를 검색하며, 애플리케이션의 데이터베이스 자격 증명, API 키 또는 기타 민감한 구성 데이터에 액세스하는 데 사용 가능합니다.

------
#### [ Python ]

**Python 함수를 만들려면**

1. 새 프로젝트 디렉터리를 생성하고 해당 디렉터리로 이동합니다. 예제:

   ```
   mkdir my_function
   cd my_function
   ```

1. 다음 코드가 포함된 `lambda_function.py`라는 파일을 생성합니다. `secret_name`으로 보안 암호의 이름 또는 Amazon 리소스 이름(ARN)을 사용합니다.

   ```
   import json
   import os
   import requests
   
   def lambda_handler(event, context):
       try:
           # Replace with the name or ARN of your secret
           secret_name = "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME"
           
           secrets_extension_endpoint = f"http://localhost:2773/secretsmanager/get?secretId={secret_name}"
           headers = {"X-Aws-Parameters-Secrets-Token": os.environ.get('AWS_SESSION_TOKEN')}
           
           response = requests.get(secrets_extension_endpoint, headers=headers)
           print(f"Response status code: {response.status_code}")
           
           secret = json.loads(response.text)["SecretString"]
           print(f"Retrieved secret: {secret}")
           
           return {
               'statusCode': response.status_code,
               'body': json.dumps({
                   'message': 'Successfully retrieved secret',
                   'secretRetrieved': True
               })
           }
       
       except Exception as e:
           print(f"Error: {str(e)}")
           return {
               'statusCode': 500,
               'body': json.dumps({
                   'message': 'Error retrieving secret',
                   'error': str(e)
               })
           }
   ```

1. 이 내용으로 `requirements.txt`라는 파일을 생성합니다.

   ```
   requests
   ```

1. 종속성을 설치합니다.

   ```
   pip install -r requirements.txt -t .
   ```

1. 모든 파일이 포함된 .zip 파일을 생성합니다.

   ```
   zip -r function.zip .
   ```

------
#### [ Node.js ]

**Node.js 함수를 만들려면**

1. 새 프로젝트 디렉터리를 생성하고 해당 디렉터리로 이동합니다. 예제:

   ```
   mkdir my_function
   cd my_function
   ```

1. 다음 코드가 포함된 `index.mjs`라는 파일을 생성합니다. `secret_name`으로 보안 암호의 이름 또는 Amazon 리소스 이름(ARN)을 사용합니다.

   ```
   import http from 'http';
   
   export const handler = async (event) => {
       try {
           // Replace with the name or ARN of your secret
           const secretName = "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME";
           const options = {
               hostname: 'localhost',
               port: 2773,
               path: `/secretsmanager/get?secretId=${secretName}`,
               headers: {
                   'X-Aws-Parameters-Secrets-Token': process.env.AWS_SESSION_TOKEN
               }
           };
   
           const response = await new Promise((resolve, reject) => {
               http.get(options, (res) => {
                   let data = '';
                   res.on('data', (chunk) => { data += chunk; });
                   res.on('end', () => {
                       resolve({ 
                           statusCode: res.statusCode, 
                           body: data 
                       });
                   });
               }).on('error', reject);
           });
   
           const secret = JSON.parse(response.body).SecretString;
           console.log('Retrieved secret:', secret);
   
           return {
               statusCode: response.statusCode,
               body: JSON.stringify({
                   message: 'Successfully retrieved secret',
                   secretRetrieved: true
               })
           };
       } catch (error) {
           console.error('Error:', error);
           return {
               statusCode: 500,
               body: JSON.stringify({
                   message: 'Error retrieving secret',
                   error: error.message
               })
           };
       }
   };
   ```

1. `index.mjs` 파일을 포함하는 .zip 파일을 생성합니다.

   ```
   zip -r function.zip index.mjs
   ```

------
#### [ Java ]

**Java 함수를 만들려면**

1. Maven 프로젝트를 생성합니다.

   ```
   mvn archetype:generate \
       -DgroupId=example \
       -DartifactId=lambda-secrets-demo \
       -DarchetypeArtifactId=maven-archetype-quickstart \
       -DarchetypeVersion=1.4 \
       -DinteractiveMode=false
   ```

1. 프로젝트 디렉터리로 이동합니다.

   ```
   cd lambda-secrets-demo
   ```

1. `pom.xml`을 열고 내용을 다음으로 바꿉니다.

   ```
   <project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
   
       <groupId>example</groupId>
       <artifactId>lambda-secrets-demo</artifactId>
       <version>1.0-SNAPSHOT</version>
   
       <properties>
           <maven.compiler.source>11</maven.compiler.source>
           <maven.compiler.target>11</maven.compiler.target>
       </properties>
   
       <dependencies>
           <dependency>
               <groupId>com.amazonaws</groupId>
               <artifactId>aws-lambda-java-core</artifactId>
               <version>1.2.1</version>
           </dependency>
       </dependencies>
   
       <build>
           <plugins>
               <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-shade-plugin</artifactId>
                   <version>3.2.4</version>
                   <executions>
                       <execution>
                           <phase>package</phase>
                           <goals>
                               <goal>shade</goal>
                           </goals>
                           <configuration>
                               <createDependencyReducedPom>false</createDependencyReducedPom>
                               <finalName>function</finalName>
                           </configuration>
                       </execution>
                   </executions>
               </plugin>
           </plugins>
       </build>
   </project>
   ```

1. Lambda의 기본 Java 핸들러 이름(`example.Hello::handleRequest`)과 일치하도록 `/lambda-secrets-demo/src/main/java/example/App.java`의 이름을 `Hello.java`로 바꿉니다.

   ```
   mv src/main/java/example/App.java src/main/java/example/Hello.java
   ```

1. `Hello.java` 파일을 열고 내용을 다음으로 바꿉니다. `secretName`으로 보안 암호의 이름 또는 Amazon 리소스 이름(ARN)을 사용합니다.

   ```
   package example;
   
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   import java.net.URI;
   import java.net.http.HttpClient;
   import java.net.http.HttpRequest;
   import java.net.http.HttpResponse;
   
   public class Hello implements RequestHandler<Object, String> {
       private final HttpClient client = HttpClient.newHttpClient();
   
       @Override
       public String handleRequest(Object input, Context context) {
           try {
               // Replace with the name or ARN of your secret
               String secretName = "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME";
               String endpoint = "http://localhost:2773/secretsmanager/get?secretId=" + secretName;
   
               HttpRequest request = HttpRequest.newBuilder()
                   .uri(URI.create(endpoint))
                   .header("X-Aws-Parameters-Secrets-Token", System.getenv("AWS_SESSION_TOKEN"))
                   .GET()
                   .build();
   
               HttpResponse<String> response = client.send(request, 
                   HttpResponse.BodyHandlers.ofString());
   
               String secret = response.body();
               secret = secret.substring(secret.indexOf("SecretString") + 15);
               secret = secret.substring(0, secret.indexOf("\""));
   
               System.out.println("Retrieved secret: " + secret);
               return String.format(
                   "{\"statusCode\": %d, \"body\": \"%s\"}",
                   response.statusCode(), "Successfully retrieved secret"
               );
   
           } catch (Exception e) {
               e.printStackTrace();
               return String.format(
                   "{\"body\": \"Error retrieving secret: %s\"}", 
                   e.getMessage()
               );
           }
       }
   }
   ```

1. 테스트 디렉터리를 제거합니다. Maven은 기본적으로 이 디렉터리를 생성하지만 이 예제에서는 필요 없습니다.

   ```
   rm -rf src/test
   ```

1. 프로젝트 빌드:

   ```
   mvn package
   ```

1. 나중에 사용할 수 있도록 JAR 파일(`target/function.jar`)을 다운로드합니다.

------

#### 함수 생성
<a name="lambda-secrets-manager-create"></a>

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. **함수 생성**을 선택합니다.

1. **새로 작성**을 선택합니다.

1. [**함수 이름**]에 **secret-retrieval-demo**을 입력합니다.

1. 원하는 **런타임**을 선택합니다.

1. **함수 생성**을 선택합니다.

**배포 패키지를 업로드하려면 다음을 수행하세요.**

1. 함수의 **코드** 탭에서 **에서 업로드**를 선택하고 **.zip 파일**(Python 및 Node.js의 경우) 또는 **.jar 파일**(Java의 경우)을 선택합니다.

1. 이전에 생성한 배포 패키지를 업로드합니다.

1. **저장**을 선택합니다.

#### 확장 추가
<a name="lambda-secrets-manager-extension"></a>

**AWS 파라미터 및 보안 암호 Lambda 확장을 계층으로 추가하려면 다음을 수행하세요.**

1. 함수의 **코드** 탭에서 **계층**까지 아래로 스크롤합니다.

1. **계층 추가**를 선택합니다.

1. **AWS 계층**을 선택합니다.

1. **AWS-Parameters-and-Secrets-Lambda-Extension**을 선택합니다.

1. 최신 버전을 선택합니다.

1. **추가**를 선택합니다.

#### 권한 추가
<a name="lambda-secrets-manager-permissions"></a>

**실행 역할에 Secrets Manager 권한을 추가하려면 다음을 수행하세요.**

1. **구성(Configuration)** 탭을 선택한 다음, **권한(Permissions)**을 선택합니다.

1. **역할 이름**에서 실행 역할에 대한 링크를 선택합니다. 이 링크를 클릭하면 IAM 콘솔에서 역할이 열립니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/execution-role-console.png)

1. **권한 추가**를 선택하고 **인라인 정책 생성**을 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/create-inline-policy.png)

1. **JSON** 탭을 선택하고 다음 정책을 추가합니다. `Resource`로 보안 암호의 ARN을 입력합니다.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "secretsmanager:GetSecretValue",
               "Resource": "arn:aws:secretsmanager:us-east-1:111122223333:secret:SECRET_NAME"
           }
       ]
   }
   ```

------

1. **다음**을 선택합니다.

1. 정책의 이름을 입력합니다.

1. **정책 생성**을 선택합니다.

#### 함수 테스트
<a name="lambda-secrets-manager-test"></a>

**함수를 테스트하려면**

1. Lambda 콘솔로 돌아갑니다.

1. **테스트** 탭을 선택합니다.

1. **테스트**를 선택합니다. 다음과 같은 응답이 표시되어야 합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/execution-results-secret.png)

### 환경 변수
<a name="lambda-secrets-manager-env-vars"></a>

AWS Parameters and Secrets Lambda 확장은 다음 기본 설정을 사용합니다. 해당 [환경 변수](configuration-envvars.md#create-environment-variables)를 생성하여 이러한 설정을 재정의할 수 있습니다. 함수의 현재 설정을 보려면를 `PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL`을 `DEBUG`로 설정합니다. 확장은 각 함수 간접 호출이 시작될 때 CloudWatch Logs에 구성 정보를 로깅합니다.


| 설정 | 기본값  | 유효값 | 환경 변수 | 세부 정보 | 
| --- | --- | --- | --- | --- | 
| HTTP 포트 | 2773 | 1\$165535 | PARAMETERS\$1SECRETS\$1EXTENSION\$1HTTP\$1PORT | 로컬 HTTP 서버의 포트 | 
| 캐시 활성화됨 | TRUE | TRUE \$1 FALSE | PARAMETERS\$1SECRETS\$1EXTENSION\$1CACHE\$1ENABLED | 캐시 활성화 또는 비활성화 | 
| 캐시 크기 | 1000 | 0\$11,000 | PARAMETERS\$1SECRETS\$1EXTENSION\$1CACHE\$1SIZE | 캐싱을 비활성화하려면 0으로 설정 | 
| Secrets Manager TTL | 300초 | 0\$1300초 | SECRETS\$1MANAGER\$1TTL | 캐시된 보안 암호의 time-to-live. 캐싱을 비활성화하려면 0으로 설정. PARAMETERS\$1SECRETS\$1EXTENSION\$1CACHE\$1SIZE 값이 0인 경우 이 변수는 무시됩니다. | 
| Parameter Store TTL | 300초 | 0\$1300초 | SSM\$1PARAMETER\$1STORE\$1TTL | 캐시된 파라미터의 time-to-live. 캐싱을 비활성화하려면 0으로 설정. PARAMETERS\$1SECRETS\$1EXTENSION\$1CACHE\$1SIZE 값이 0인 경우 이 변수는 무시됩니다. | 
| 로그 수준 | INFO | DEBUG \$1 INFO \$1 WARN \$1 ERROR \$1 NONE | PARAMETERS\$1SECRETS\$1EXTENSION\$1LOG\$1LEVEL | 확장에 대해 로그에 보고되는 세부 정보 수준 | 
| 최대 연결 수 | 3 | 1 이상 | PARAMETERS\$1SECRETS\$1EXTENSION\$1MAX\$1CONNECTIONS | Parameter Store 또는 Secrets Manager에 대한 요청을 위한 최대 HTTP 연결 수 | 
| Secrets Manager 제한 시간 | 0(제한 시간 없음) | 모든 정수 | SECRETS\$1MANAGER\$1TIMEOUT\$1MILLIS | Secrets Manager에 대한 요청 제한 시간(밀리초) | 
| 파라미터 스토어 제한 시간 | 0(제한 시간 없음) | 모든 정수 | SSM\$1PARAMETER\$1STORE\$1TIMEOUT\$1MILLIS | Parameter Store에 대한 요청 제한 시간(밀리초) | 

### 보안 암호 교체 작업
<a name="lambda-secrets-manager-rotation"></a>

보안 암호를 자주 교체하는 경우 기본 300초 캐시 기간으로 인해 함수가 오래된 보안 암호를 사용할 수 있습니다. 함수가 최신 보안 암호 값을 사용하도록 하는 두 가지 옵션이 있습니다.
+ `SECRETS_MANAGER_TTL` 환경 변수를 더 낮은 값(초)으로 설정하여 캐시 TTL을 줄입니다. 예를 들어, `60`으로 설정하면 함수가 1분 이상 지난 보안 암호를 사용하지 않습니다.
+ 보안 암호 요청에서 `AWSCURRENT` 또는 `AWSPREVIOUS` 스테이징 레이블을 사용하여 원하는 특정 버전을 가져오도록 합니다.

  ```
  secretsmanager/get?secretId=YOUR_SECRET_NAME&versionStage=AWSCURRENT
  ```

성능과 최신 상태에 대한 요구 사항의 균형을 가장 잘 맞출 수 있는 접근 방식을 선택하세요. TTL이 낮을수록 Secrets Manager를 더 자주 직접적으로 호출하지만 가장 최신의 보안 암호 값으로 작업할 수 있습니다.

## Powertools for AWS Lambda 파라미터 유틸리티 사용
<a name="lambda-secrets-manager-powertools-approach"></a>

Powertools for AWS Lambda의 파라미터 유틸리티는 Secrets Manager, 파라미터 스토어 및 AppConfig를 포함한 여러 공급자에서 보안 암호를 검색하기 위한 통합 인터페이스를 제공합니다. 캐싱, 변환을 처리하고 확장 접근 방식에 비해 더 통합된 개발 경험을 제공합니다.

### 파라미터 유틸리티의 이점
<a name="lambda-secrets-manager-powertools-benefits"></a>
+ **다양한 공급자** - Secrets Manager, Parameter Store 및 AppConfig에서 동일한 인터페이스를 사용하여 파라미터 검색
+ **내장 변환** - 자동 JSON 구문 분석, base64 디코딩 및 기타 데이터 변환
+ **통합 캐싱** - TTL 지원을 통해 구성 가능한 캐싱으로 API 직접 호출을 줄임
+ **유형 안전** - TypeScript 및 기타 지원되는 런타임에서 강력한 유형 지정 지원
+ **오류 처리** - 재시도 로직 및 오류 처리 내장

### 코드 예제
<a name="lambda-secrets-manager-powertools-examples"></a>

다음 예제에서는 다양한 런타임에서 파라미터 유틸리티를 사용하여 보안 암호를 검색하는 방법을 보여줍니다.

**Python**  
전체 예제 및 설정 지침은 [파라미터 유틸리티 설명서](https://docs.powertools.aws.dev/lambda/python/latest/utilities/parameters/)를 참조하세요.
Powertools for AWS Lambda 파라미터 유틸리티를 사용하여 Secrets Manager에서 보안 암호를 검색합니다.  

```
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities import parameters

logger = Logger()

def lambda_handler(event, context):
    try:
        # Get secret with caching (default TTL: 5 seconds)
        secret_value = parameters.get_secret("my-secret-name")
        
        # Get secret with custom TTL
        secret_with_ttl = parameters.get_secret("my-secret-name", max_age=300)
        
        # Get secret and transform JSON
        secret_json = parameters.get_secret("my-json-secret", transform="json")
        
        logger.info("Successfully retrieved secrets")
        
        return {
            'statusCode': 200,
            'body': 'Successfully retrieved secrets'
        }
        
    except Exception as e:
        logger.error(f"Error retrieving secret: {str(e)}")
        return {
            'statusCode': 500,
            'body': f'Error: {str(e)}'
        }
```

**TypeScript**  
전체 예제 및 설정 지침은 [파라미터 유틸리티 설명서](https://docs.aws.amazon.com/powertools/typescript/2.1.1/utilities/parameters/)를 참조하세요.
Powertools for AWS Lambda 파라미터 유틸리티를 사용하여 Secrets Manager에서 보안 암호를 검색합니다.  

```
import { Logger } from '@aws-lambda-powertools/logger';
import { getSecret } from '@aws-lambda-powertools/parameters/secrets';
import type { Context } from 'aws-lambda';

const logger = new Logger();

export const handler = async (event: any, context: Context) => {
    try {
        // Get secret with caching (default TTL: 5 seconds)
        const secretValue = await getSecret('my-secret-name');
        
        // Get secret with custom TTL
        const secretWithTtl = await getSecret('my-secret-name', { maxAge: 300 });
        
        // Get secret and transform JSON
        const secretJson = await getSecret('my-json-secret', { transform: 'json' });
        
        logger.info('Successfully retrieved secrets');
        
        return {
            statusCode: 200,
            body: 'Successfully retrieved secrets'
        };
        
    } catch (error) {
        logger.error('Error retrieving secret', { error });
        return {
            statusCode: 500,
            body: `Error: ${error}`
        };
    }
};
```

**Java**  
전체 예제 및 설정 지침은 [파라미터 유틸리티 설명서](https://docs.powertools.aws.dev/lambda/java/latest/utilities/parameters/)를 참조하세요.
Powertools for AWS Lambda 파라미터 유틸리티를 사용하여 Secrets Manager에서 보안 암호를 검색합니다.  

```
import software.amazon.lambda.powertools.logging.Logging;
import software.amazon.lambda.powertools.parameters.SecretsProvider;
import software.amazon.lambda.powertools.parameters.ParamManager;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class SecretHandler implements RequestHandler<Object, String> {
    
    private final SecretsProvider secretsProvider = ParamManager.getSecretsProvider();
    
    @Logging
    @Override
    public String handleRequest(Object input, Context context) {
        try {
            // Get secret with caching (default TTL: 5 seconds)
            String secretValue = secretsProvider.get("my-secret-name");
            
            // Get secret with custom TTL (300 seconds)
            String secretWithTtl = secretsProvider.withMaxAge(300).get("my-secret-name");
            
            // Get secret and transform JSON
            MySecret secretJson = secretsProvider.get("my-json-secret", MySecret.class);
            
            return "Successfully retrieved secrets";
            
        } catch (Exception e) {
            return "Error retrieving secret: " + e.getMessage();
        }
    }
    
    public static class MySecret {
        // Define your secret structure here
    }
}
```

**.NET**  
전체 예제 및 설정 지침은 [파라미터 유틸리티 설명서](https://docs.aws.amazon.com/powertools/typescript/latest/features/parameters/)를 참조하세요.
Powertools for AWS Lambda 파라미터 유틸리티를 사용하여 Secrets Manager에서 보안 암호를 검색합니다.  

```
using AWS.Lambda.Powertools.Logging;
using AWS.Lambda.Powertools.Parameters;
using Amazon.Lambda.Core;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

public class Function
{
    private readonly ISecretsProvider _secretsProvider;
    
    public Function()
    {
        _secretsProvider = ParametersManager.SecretsProvider;
    }
    
    [Logging]
    public async Task<string> FunctionHandler(object input, ILambdaContext context)
    {
        try
        {
            // Get secret with caching (default TTL: 5 seconds)
            var secretValue = await _secretsProvider.GetAsync("my-secret-name");
            
            // Get secret with custom TTL
            var secretWithTtl = await _secretsProvider.WithMaxAge(TimeSpan.FromMinutes(5))
                .GetAsync("my-secret-name");
            
            // Get secret and transform JSON
            var secretJson = await _secretsProvider.GetAsync<MySecret>("my-json-secret");
            
            return "Successfully retrieved secrets";
        }
        catch (Exception e)
        {
            return $"Error retrieving secret: {e.Message}";
        }
    }
    
    public class MySecret
    {
        // Define your secret structure here
    }
}
```

### 설정 및 권한
<a name="lambda-secrets-manager-powertools-setup"></a>

파라미터 유틸리티를 사용하려면 다음을 수행해야 합니다.

1. 사용하시는 런타임에 맞는 Powertools for AWS Lambda를 설치합니다. 자세한 내용은 [AWS Lambda용 Powertools](powertools-for-lambda.md)을 참조하세요.

1. 함수의 실행 역할에 필요한 IAM 권한을 추가합니다. 자세한 내용은 [AWS Lambda에서 권한 관리](lambda-permissions.md) 섹션을 참조하세요.

1. [환경 변수](configuration-envvars.md)를 통해 선택적 설정을 구성합니다.

필요한 IAM 권한은 확장 접근 방식과 동일합니다. 유틸리티는 구성에 따라 Secrets Manager에 대한 캐싱 및 API 직접 호출을 자동으로 처리합니다.

# Amazon SQS에서 Lambda 사용
<a name="with-sqs"></a>

**참고**  
Lambda 함수 이외의 대상으로 데이터를 전송하거나 데이터를 전송하기 전에 데이터를 보강하려는 경우 [Amazon EventBridge 파이프](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes.html)를 참조하세요.

Lambda 함수를 사용하여 Amazon Simple Queue Service(Amazon SQS) 대기열의 메시지를 처리할 수 있습니다. Lambda는 [이벤트 소스 매핑](invocation-eventsourcemapping.md)을 위해 [표준 대기열](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html)과 [선입선출(FIFO) 대기열](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html)을 모두 지원합니다. 프로비저닝 모드를 사용하여 Amazon SQS 이벤트 소스 매핑에 전용 폴링 리소스를 할당할 수도 있습니다. Lambda 함수와 Amazon SQS 대기열은 [서로 다른 AWS 계정](with-sqs-cross-account-example.md)에 있을 수 있지만 동일한 AWS 리전에 있어야 합니다.

Amazon SQS 메시지를 처리할 때, 배치의 일부 메시지가 실패하는 경우 처리 완료된 메시지가 재시도되지 않도록 부분 배치 응답 로직을 구현해야 합니다. Powertools for AWS Lambda의 [배치 프로세서 유틸리티](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)는 부분 배치 응답 로직을 자동으로 처리하여 개발 시간을 단축하고 신뢰성을 개선하여 해당 구현을 간소화합니다.

**Topics**
+ [

## Amazon SQS 이벤트 소스 매핑에 대한 폴링 및 배치 동작 이해
](#sqs-polling-behavior)
+ [

## Amazon SQS 이벤트 소스 매핑에서 프로비저닝 모드 사용
](#sqs-provisioned-mode)
+ [

## Amazon SQS 이벤트 소스 매핑에 대한 프로비저닝 모드 구성
](#sqs-configuring-provisioned-mode)
+ [

## 표준 대기열 메시지 이벤트의 예
](#example-standard-queue-message-event)
+ [

## FIFO 대기열 메시지 이벤트의 예
](#sample-fifo-queues-message-event)
+ [

# Amazon SQS 이벤트 소스 매핑 생성 및 구성
](services-sqs-configure.md)
+ [

# SQS 이벤트 소스 매핑에 대한 규모 조정 동작 구성
](services-sqs-scaling.md)
+ [

# Lambda에서 SQS 이벤트 소스에 대한 오류 처리
](services-sqs-errorhandling.md)
+ [

# Amazon SQS 이벤트 소스 매핑을 위한 Lambda 파라미터
](services-sqs-parameters.md)
+ [

# Amazon SQS 이벤트 소스를 통해 이벤트 필터링 사용
](with-sqs-filtering.md)
+ [

# 자습서: Amazon SQS에서 Lambda 사용
](with-sqs-example.md)
+ [

# 자습서: 교차 계정 Amazon SQS 대기열을 이벤트 소스로 사용
](with-sqs-cross-account-example.md)

## Amazon SQS 이벤트 소스 매핑에 대한 폴링 및 배치 동작 이해
<a name="sqs-polling-behavior"></a>

Amazon SQS 이벤트 소스 매핑을 사용하면 Lambda가 대기열을 폴링하고 이벤트와 [동기적으로](invocation-sync.md) 함수를 간접적으로 간접 호출합니다. 각 이벤트에는 대기열의 여러 메시지 배치가 포함될 수 있습니다. Lambda는 이러한 이벤트를 한 번에 한 배치씩 수신하고 각 배치에 대해 함수를 한 번씩 간접적으로 간접 호출합니다. 함수가 배치를 성공적으로 처리하면 Lambda는 대기열에서 메시지를 삭제합니다.

Lambda가 배치를 수신하면 메시지는 대기열에 머무르지만 대기열의 [표시 제한 시간](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html) 동안 숨겨집니다. 함수가 배치의 모든 메시지를 성공적으로 처리하면 Lambda는 대기열에서 메시지를 삭제합니다. 기본적으로 배치를 처리하는 동안 함수에 오류가 발생하면 표시 제한 시간이 만료된 후 해당 배치의 모든 메시지가 대기열에 다시 표시됩니다. 이러한 이유로 함수 코드는 의도하지 않은 부작용 없이 동일한 메시지를 여러 번 처리할 수 있어야 합니다.

**주의**  
Lambda 이벤트 소스 매핑은 각 이벤트를 한 번 이상 처리하므로 레코드가 중복될 수 있습니다. 중복 이벤트와 관련된 잠재적 문제를 방지하려면 함수 코드를 멱등성으로 만드는 것이 좋습니다. 자세한 내용은 AWS 지식 센터의 [함수를 멱등성 Lambda 함수로 만들려면 어떻게 해야 하나요?](https://repost.aws/knowledge-center/lambda-function-idempotent)를 참조하세요.

Lambda가 메시지를 여러 번 처리하지 못하도록 하려면 함수 응답에 [배치 항목 실패](services-sqs-errorhandling.md#services-sqs-batchfailurereporting)를 포함하도록 이벤트 소스 매핑을 구성하거나, Lambda 함수가 메시지를 성공적으로 처리할 경우 [DeleteMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html) API를 사용하여 대기열에서 메시지를 제거할 수 있습니다.

SQS 이벤트 소스 매핑을 위해 Lambda가 지원하는 구성 파라미터에 대한 자세한 내용은 [SQS 이벤트 소스 매핑 생성](services-sqs-configure.md#events-sqs-eventsource) 섹션을 참조하세요.

## Amazon SQS 이벤트 소스 매핑에서 프로비저닝 모드 사용
<a name="sqs-provisioned-mode"></a>

이벤트 소스 매핑의 처리량을 미세 조정해야 하는 워크로드의 경우 프로비저닝된 모드를 사용할 수 있습니다. 프로비저닝된 모드에서는 프로비저닝된 이벤트 폴러의 양에 대한 최소 및 최대 제한을 정의합니다. 이러한 프로비저닝된 이벤트 폴러는 이벤트 소스 매핑 전용이며 응답형 오토스케일링을 통해 예상치 못한 메시지 급증을 처리할 수 있습니다. 프로비저닝 모드로 구성된 Amazon SQS 이벤트 소스 매핑은 기본 Amazon SQS 이벤트 소스 매핑 기능보다 3배 더 빠르게 확장되고(분당 최대 1,000개의 동시 간접 호출) 16배 더 높은 동시성(최대 20,000개의 동시 간접 호출)을 지원합니다. 시장 데이터 피드를 처리하는 금융 서비스 회사, 실시간 맞춤형 추천을 제공하는 전자 상거래 플랫폼, 라이브 플레이어 상호 작용을 관리하는 게임 회사 등 성능 요구 사항이 엄격한 Amazon SQS 이벤트 기반 워크로드에는 프로비저닝 모드를 사용하는 것이 좋습니다. 프로비저닝된 모드를 사용하면 추가 비용이 발생합니다. 요금에 대한 자세한 내용은 [AWS Lambda 요금](https://aws.amazon.com/lambda/pricing/)을 참조하세요.

프로비저닝 모드에서 각 이벤트 폴러는 최대 1MB/s의 처리량, 최대 10개의 동시 간접 호출 또는 초당 최대 10개의 Amazon SQS 폴링 API 직접 호출을 처리할 수 있습니다. 최소 이벤트 폴러 수(MinimumPollers)에 대해 허용되는 값의 범위는 2\$1200으로, 기본값은 2입니다. 최대 이벤트 폴러 수(MaximumPollers)에 대해 허용되는 값의 범위는 2\$12,000으로, 기본값은 200입니다. MaximumPollers는 MinimumPollers보다 크거나 같아야 합니다.

### 필요한 이벤트 폴러 결정
<a name="sqs-determining-event-pollers"></a>

SQS ESM에 프로비저닝 모드를 사용할 때 최적의 메시지 처리 성능 보장에 필요한 이벤트 폴러 수를 추정하려면 애플리케이션에 대해 지연 시간이 짧은 처리가 필요한 초당 최대 SQS 이벤트 수, 평균 SQS 이벤트 페이로드 크기, 평균 Lambda 함수 기간, 구성된 배치 크기 등의 지표를 수집합니다.

먼저 다음 공식을 사용하여 이벤트 폴러가 워크로드에 지원하는 초당 SQS 이벤트 수(EPS)를 추정할 수 있습니다.

```
EPS per event poller = 
        minimum(
            ceiling(1024 / average event size in KB),
            ceiling(10 / average function duration in seconds) * batch size, 
            min(100, 10 * batch size)
                )
```

이후 아래 공식을 사용하여 필요한 최소 폴러 수를 계산할 수 있습니다. 이 계산을 통해 최대 트래픽 요구 사항을 처리할 수 있는 충분한 용량을 프로비저닝할 수 있습니다.

```
Required event pollers = (Peak number of events per second in Queue) / EPS per event poller
```

기본 배치 크기가 10이고, 평균 이벤트 크기가 3KB이고, 평균 함수 기간이 100ms이고, 초당 1,000개의 이벤트를 처리해야 하는 워크로드를 고려합니다. 이 시나리오에서 각 이벤트 폴러는 약 100개의 초당 이벤트(EPS)를 지원합니다. 따라서 최대 트래픽 요구 사항을 적절하게 처리하려면 최소 폴러 수를 10으로 설정해야 합니다. 워크로드의 특성이 동일하지만 평균 함수 기간이 1초인 경우 각 폴러는 10 EPS만 지원하므로 짧은 지연 시간으로 초당 1,000개의 이벤트를 지원하도록 최소 100개의 폴러를 구성해야 합니다.

프로비저닝 모드 이벤트 폴러의 효율성을 극대화하려면 기본 배치 크기인 10 이상을 사용하는 것이 좋습니다. 배치 크기가 클수록 각 폴러가 간접 호출당 더 많은 이벤트를 처리하고, 이를 통해 처리량과 비용 효율성을 개선할 수 있습니다. 이벤트 폴러 용량을 계획할 때 잠재적 트래픽 급증을 고려하고 minimumPollers 값을 계산된 최소 값보다 약간 높게 설정하여 여유분을 두는 것이 좋습니다. 추가로 메시지 크기, 함수 기간 또는 트래픽 패턴의 변경으로 인해 최적의 성능과 비용 효율성을 유지하기 위해 이벤트 폴러 구성을 조정해야 할 수 있으므로 시간 경과에 따른 워크로드 특성을 모니터링합니다. 정확한 용량 계획을 위해 특정 워크로드를 테스트하여 각 이벤트 폴러가 처리할 수 있는 실제 EPS를 결정하는 것이 좋습니다.

## Amazon SQS 이벤트 소스 매핑에 대한 프로비저닝 모드 구성
<a name="sqs-configuring-provisioned-mode"></a>

콘솔 또는 Lambda API를 사용하여 Amazon SQS 이벤트 소스 매핑에 대한 프로비저닝 모드를 구성할 수 있습니다.

**기존 Amazon SQS 이벤트 소스 매핑에 대한 프로비저닝 모드를 구성하는 방법(콘솔)**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 프로비저닝 모드를 구성하려는 Amazon SQS 이벤트 소스 매핑을 사용하여 함수를 선택합니다.

1. **구성**을 선택한 다음 **트리거**를 선택합니다.

1. 프로비저닝 모드를 구성하려는 Amazon SQS 이벤트 소스 매핑을 선택하고 **편집**을 선택합니다.

1. **이벤트 소스 매핑 구성**에서 **프로비저닝된 모드 구성**을 선택하세요.
   + **최소 이벤트 폴러**에 2\$1200의 값을 입력하세요. 값을 지정하지 않는 경우 Lambda에서는 기본값(2)을 선택합니다.
   + **최대 이벤트 폴러**에 2\$12,000의 값을 입력하세요 이 값은 **최소 이벤트 폴러**의 값 이상이어야 합니다. 값을 지정하지 않는 경우 Lambda에서는 기본값(200)을 선택합니다.

1. **저장**을 선택합니다.

`EventSourceMappingConfiguration`의 `ProvisionedPollerConfig` 객체를 사용하여 프로그래밍 방식으로 프로비저닝 모드를 구성할 수 있습니다. 예를 들어 다음 `UpdateEventSourceMapping` CLI 명령은 `MinimumPollers` 값을 5로, `MaximumPollers` 값을 100으로 구성합니다.

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --provisioned-poller-config '{"MinimumPollers": 5, "MaximumPollers": 100}'
```

프로비저닝된 모드를 구성한 후 `ProvisionedPollers` 지표를 모니터링하여 워크로드에 대한 이벤트 폴러 사용량을 관찰할 수 있습니다. 자세한 내용은 이벤트 소스 매핑 지표를 참조하세요.

프로비저닝 모드를 비활성화하고 기본(온디맨드) 모드로 돌아가기 위해 다음 `UpdateEventSourceMapping` CLI 명령을 사용할 수 있습니다.

```
aws lambda update-event-source-mapping \
    --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
    --provisioned-poller-config '{}'
```

**참고**  
프로비저닝 모드는 최대 동시성 설정과 함께 사용할 수 없습니다. 프로비저닝 모드를 사용하는 경우 최대 이벤트 폴러 수를 통해 최대 동시성을 제어합니다.

프로비저닝 모드 구성에 대한 자세한 정보는 [Amazon SQS 이벤트 소스 매핑 생성 및 구성](services-sqs-configure.md) 항목을 참조하세요.

## 표준 대기열 메시지 이벤트의 예
<a name="example-standard-queue-message-event"></a>

**Example Amazon SQS 메시지 이벤트(표준 대기열)**  

```
{
    "Records": [
        {
            "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
            "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
            "body": "Test message.",
            "attributes": {
                "ApproximateReceiveCount": "1",
                "SentTimestamp": "1545082649183",
                "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                "ApproximateFirstReceiveTimestamp": "1545082649185"
            },
            "messageAttributes": {
                "myAttribute": {
                    "stringValue": "myValue", 
                    "stringListValues": [], 
                    "binaryListValues": [], 
                    "dataType": "String"
                }
            },
            "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
            "eventSource": "aws:sqs",
            "eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:my-queue",
            "awsRegion": "us-east-2"
        },
        {
            "messageId": "2e1424d4-f796-459a-8184-9c92662be6da",
            "receiptHandle": "AQEBzWwaftRI0KuVm4tP+/7q1rGgNqicHq...",
            "body": "Test message.",
            "attributes": {
                "ApproximateReceiveCount": "1",
                "SentTimestamp": "1545082650636",
                "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                "ApproximateFirstReceiveTimestamp": "1545082650649"
            },
            "messageAttributes": {},
            "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
            "eventSource": "aws:sqs",
            "eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:my-queue",
            "awsRegion": "us-east-2"
        }
    ]
}
```

기본적으로 Lambda는 대기열에서 최대 10개의 메시지를 한 번에 폴링하고 해당 배치를 함수로 보냅니다. 소수의 레코드로 함수를 간접적으로 호출하는 것을 피하려면 배치 기간을 구성하여 이벤트 소스가 최대 5분 동안 레코드를 버퍼링하도록 구성할 수 있습니다. 함수를 간접적으로 호출하기 전에 Lambda는 배치 기간이 만료되거나, [간접 호출 페이로드 크기 할당량](gettingstarted-limits.md)에 도달하거나, 구성된 최대 배치 크기에 도달할 때까지 표준 대기열에서 메시지를 계속 폴링합니다.

배치 기간을 사용하고 SQS 대기열에 트래픽이 매우 적은 경우, Lambda는 함수를 호출하기 전에 최대 20초까지 기다릴 수 있습니다. 이는 배치 기간을 20초 미만으로 설정한 경우에도 마찬가지입니다.

**참고**  
Java에서는 JSON을 역직렬화할 때 null 포인터 오류가 발생할 수 있습니다. 이는 JSON 객체 매퍼가 ‘Records’ 및 “eventSourceARN’의 대소문자를 변환하는 방식 때문일 수 있습니다.

## FIFO 대기열 메시지 이벤트의 예
<a name="sample-fifo-queues-message-event"></a>

FIFO 대기열의 경우 레코드에는 중복 제거 및 시퀀싱과 관련된 추가 속성이 포함되어 있습니다.

**Example Amazon SQS 메시지 이벤트(FIFO 대기열)**  

```
{
    "Records": [
        {
            "messageId": "11d6ee51-4cc7-4302-9e22-7cd8afdaadf5",
            "receiptHandle": "AQEBBX8nesZEXmkhsmZeyIE8iQAMig7qw...",
            "body": "Test message.",
            "attributes": {
                "ApproximateReceiveCount": "1",
                "SentTimestamp": "1573251510774",
                "SequenceNumber": "18849496460467696128",
                "MessageGroupId": "1",
                "SenderId": "AIDAIO23YVJENQZJOL4VO",
                "MessageDeduplicationId": "1",
                "ApproximateFirstReceiveTimestamp": "1573251510774"
            },
            "messageAttributes": {},
            "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
            "eventSource": "aws:sqs",
            "eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:fifo.fifo",
            "awsRegion": "us-east-2"
        }
    ]
}
```

# Amazon SQS 이벤트 소스 매핑 생성 및 구성
<a name="services-sqs-configure"></a>

Lambda로 Amazon SQS 메시지를 처리하려면 적절한 설정으로 대기열을 구성한 다음 Lambda 이벤트 소스 매핑을 생성하세요.

**Topics**
+ [

## Lambda에서 사용할 수 있도록 대기열 구성
](#events-sqs-queueconfig)
+ [

## Lambda 실행 역할 권한 설정
](#events-sqs-permissions)
+ [

## SQS 이벤트 소스 매핑 생성
](#events-sqs-eventsource)

## Lambda에서 사용할 수 있도록 대기열 구성
<a name="events-sqs-queueconfig"></a>

기존 Amazon SQS 대기열이 없으면 Lambda 함수의 이벤트 소스로 사용할 [대기열을 생성](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-create-queue.html)합니다. Lambda 함수와 Amazon SQS 대기열은 [서로 다른 AWS 계정](with-sqs-cross-account-example.md)에 있을 수 있지만 동일한 AWS 리전에 있어야 합니다.

함수 시간이 각 레코드 배치를 처리할 수 있도록 하려면 소스 대기열의 [표시 제한 시간](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)을 함수에 [구성 제한 시간](configuration-timeout.md)의 6배 이상으로 설정하세요. 이전 배치를 처리하는 동안 함수가 제한되는 경우 추가 시간을 통해 Lambda가 재시도할 수 있습니다.

**참고**  
함수의 제한 시간은 대기열의 표시 제한 시간보다 작거나 같아야 합니다. Lambda는 이벤트 소스 매핑을 생성하거나 업데이트할 때 해당 요구 사항을 검증하고 함수 제한 시간이 대기열의 표시 제한 시간을 초과하면 오류를 반환합니다.

기본적으로 배치를 처리하는 동안 Lambda에 오류가 발생하면 해당 배치의 모든 메시지가 대기열로 돌아갑니다. [표시 제한 시간](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html) 후 메시지가 Lambda에 다시 표시됩니다. [부분 배치 응답](services-sqs-errorhandling.md#services-sqs-batchfailurereporting)을 사용하여 실패한 메시지만 대기열에 반환하도록 이벤트 소스 매핑을 구성할 수 있습니다. 또한 함수가 메시지를 여러 번 처리하지 못하면 Amazon SQS에서 메시지를 [Dead Letter Queue(DLQ)](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)로 보낼 수 있습니다. 소스 대기열의 [리드라이브 정책](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html#policies-for-dead-letter-queues)에서 `maxReceiveCount`를 5 이상으로 설정하는 것이 좋습니다. 이를 통해 Lambda는 실패한 메시지를 Dead Letter Queue(DLQ)로 직접 전송하기 전에 몇 번의 재시도를 할 수 있습니다.

## Lambda 실행 역할 권한 설정
<a name="events-sqs-permissions"></a>

[AWSLambdaSQSQueueExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaSQSQueueExecutionRole.html) AWS 관리형 정책에는 Lambda가 Amazon SQS 대기열에서 읽는 데 필요한 권한이 포함되어 있습니다. 함수의 실행 역할에 [이 관리형 정책을 추가](lambda-intro-execution-role.md)할 수 있습니다.

선택적으로 암호화된 대기열을 사용하는 경우 실행 역할에 다음 권한도 추가해야 합니다.
+ [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)

## SQS 이벤트 소스 매핑 생성
<a name="events-sqs-eventsource"></a>

이벤트 소스 매핑을 생성하여 Lambda가 대기열의 항목을 Lambda 함수로 전송하게 할 수 있습니다. 여러 이벤트 소스 매핑을 생성하여 하나의 함수로 여러 대기열의 항목을 처리할 수 있습니다. Lambda가 대상 함수를 간접 호출하면 이벤트에는 구성 가능한 최대 *배치 크기*까지 항목이 여러 개 포함될 수 있습니다.

Amazon SQS에서 읽도록 함수를 구성하려면 [ AWSLambdaSQSQueueExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaSQSQueueExecutionRole.html) AWS 관리형 정책을 실행 역할에 연결합니다. 그리고 다음 단계를 사용하여 콘솔에서 **SQS** 이벤트 소스 매핑을 생성합니다.

**권한 추가 및 트리거 생성**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

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

1. **구성(Configuration)** 탭을 선택한 다음, **권한(Permissions)**을 선택합니다.

1. **역할 이름**에서 실행 역할에 대한 링크를 선택합니다. 이 링크를 클릭하면 IAM 콘솔에서 역할이 열립니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/execution-role.png)

1. **권한 추가**를 선택하고 **정책 연결**을 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/attach-policies.png)

1. 검색 필드에 `AWSLambdaSQSQueueExecutionRole`를 입력합니다. 실행 역할에 이 정책을 추가합니다. 이는 함수가 Amazon SQS 대기열에서 읽어야 하는 권한을 포함하는 AWS 관리형 정책입니다. 이 정책에 대한 자세한 내용은 **AWS Managed Policy 참조 안내서의 [AWSLambdaSQSQueueExecutionRole](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaSQSQueueExecutionRole.html)을 참조하세요.

1. Lambda 콘솔에서 함수로 돌아갑니다. **함수 개요(Function overview)**에서 **트리거 추가(Add trigger)**를 선택합니다.  
![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/add-trigger.png)

1. 트리거 유형을 선택합니다.

1. 필요한 옵션을 구성한 다음 **추가**를 선택합니다.

Lambda는 Amazon SQS 이벤트 소스에 대해 다음과 같은 구성 옵션을 지원합니다.

**SQS 대기열**  
레코드를 읽어 올 Amazon SQS 대기열입니다. Lambda 함수와 Amazon SQS 대기열은 [서로 다른 AWS 계정](with-sqs-cross-account-example.md)에 있을 수 있지만 동일한 AWS 리전에 있어야 합니다.

**트리거 활성화**  
이벤트 소스 매핑의 상태입니다. **Enable trigger**(트리거 활성화)는 기본적으로 선택됩니다.

**배치 크기**  
각 배치에서 함수에 보낼 레코드 최대 수입니다. 표준 대기열의 경우 최대 10,000개의 레코드가 될 수 있습니다. FIFO 대기열의 경우 최대값은 10입니다. 10을 초과하는 배치 크기의 경우 배치 기간(`MaximumBatchingWindowInSeconds`)도 최소 1초로 설정해야 합니다.  
[함수 제한 시간](https://serverlessland.com/content/service/lambda/guides/aws-lambda-operator-guide/configurations#timeouts)은 항목의 전체 배치를 처리할 시간이 충분하도록 구성합니다. 항목을 처리하는 데 걸리는 시간이 길면 더 작은 배치 크기를 선택합니다. 배치 크기가 크면 매우 빠르거나 오버헤드가 큰 워크로드에 대한 효율성에 영향을 미칠 수 있습니다. 함수에 [예약된 동시성](configuration-concurrency.md)을 구성할 경우 최소 동시성 실행 수를 5로 설정하여 Lambda가 함수를 간접 호출할 때 스로틀링할 수 있는 가능성을 줄이세요.  
이벤트의 총 크기가 동기식 간접 호출에 대한 [간접 호출 페이로드 크기 할당량](gettingstarted-limits.md)(6MB)을 초과하지 않는 한 Lambda는 단일 직접 호출로 배치의 모든 레코드를 함수에 전달합니다. Lambda와 Amazon SQS는 모두 각 레코드의 메타데이터를 생성합니다. 이 추가 메타데이터는 총 페이로드 크기에 포함되며, 그러면 배치로 전송된 총 레코드 수가 구성된 배치 크기보다 작을 수 있습니다. Amazon SQS에서 전송하는 메타데이터 필드는 길이가 가변적일 수 있습니다. Amazon SQS 메타데이터 필드에 대한 자세한 내용은 **Amazon Simple Queue Service API 참조의 [ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html) API 작업 설명서를 참조하세요.

**배치 기간**  
함수를 호출하기 전에 기록을 수집할 최대 기간(단위: 초)입니다. 이 지표는 표준 대기열에만 적용됩니다.  
0초보다 큰 배치 기간을 사용하는 경우 대기열의 [표시 제한 시간](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)에서 늘어난 처리 시간을 고려해야 합니다. 대기열의 가시성 제한 시간을 [함수 제한 시간](configuration-timeout.md)의 6배에 `MaximumBatchingWindowInSeconds` 값을 더한 값으로 설정하는 것이 좋습니다. 이렇게 하면 Lambda 함수가 각 이벤트 배치를 처리하고 스로틀링 오류가 발생할 경우 다시 시도할 수 있습니다.  
메시지를 사용할 수 있게 되면 Lambda는 메시지를 일괄 처리하기 시작합니다. Lambda는 함수를 동시에 5번 호출하여 한 번에 5개의 배치를 처리하기 시작합니다. 메시지를 계속 사용할 수 있는 경우 Lambda는 분당 최대 300개의 함수 동시 간접 호출을 추가해 최대 1,250개까지 동시 간접 호출을 추가합니다. 프로비저닝 모드를 사용할 때 각 이벤트 폴러는 최대 1MB/s의 처리량, 최대 10개의 동시 간접 호출 또는 초당 최대 10개의 Amazon SQS 폴링 API 직접 호출을 처리할 수 있습니다. Lambda는 구성된 최소 및 최대 이벤트 폴러 수를 조정하여 분당 최대 1,000개의 동시 간접 호출을 빠르게 추가하면서 Amazon SQS 이벤트를 지연 시간이 짧은 방식으로 처리합니다. 이러한 최소 및 최대 이벤트 폴러 설정을 통해 규모 조정 및 동시성을 제어합니다. 함수 규모 조정 및 동시성에 대한 자세한 내용은 [Lambda 함수 규모 조정 이행](lambda-concurrency.md) 항목을 참조하세요.  
더 많은 메시지를 처리하기 위해 Lambda 함수를 최적화하여 처리량을 높일 수 있습니다. 자세한 내용은 [AWS Lambda의 Amazon SQS 표준 대기열 규모 조정 방식 이해](https://aws.amazon.com/blogs/compute/understanding-how-aws-lambda-scales-when-subscribed-to-amazon-sqs-queues/#:~:text=If there are more messages,messages from the SQS queue.)를 참조하세요.

**필터 기준**  
필터 기준을 추가하여 Lambda가 처리를 위해 함수로 보내는 이벤트를 제어합니다. 자세한 내용은 [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md) 섹션을 참조하세요.

**최대 동시성**  
이벤트 소스가 간접 호출할 수 있는 최대 동시성 함수 수입니다. 프로비저닝 모드가 활성화된 상태에서는 사용할 수 없습니다. 자세한 내용은 [Amazon SQS 이벤트 소스의 최대 동시성 구성](services-sqs-scaling.md#events-sqs-max-concurrency) 섹션을 참조하세요.

**프로비저닝된 모드**  
활성화되면 이벤트 소스 매핑에 대한 전용 폴링 리소스를 할당합니다. 이벤트 폴러의 최소(2\$1200) 및 최대(2\$12,000) 수를 구성할 수 있습니다. 각 이벤트 폴러는 최대 1MB/초의 처리량, 최대 10개의 동시 간접 호출 또는 초당 최대 10개의 Amazon SQS 폴링 API 직접 호출을 처리할 수 있습니다.  
참고: 프로비저닝 모드와 최대 동시성을 함께 사용할 수 없습니다. 프로비저닝 모드가 활성화된 경우 최대 폴러 설정을 사용하여 동시성을 제어합니다.

# SQS 이벤트 소스 매핑에 대한 규모 조정 동작 구성
<a name="services-sqs-scaling"></a>

최대 동시성 설정을 통해 또는 프로비저닝 모드를 활성화하여 Amazon SQS 이벤트 소스 매핑의 규모 조정 동작을 제어할 수 있습니다. 둘을 함께 사용할 수는 없습니다.

기본적으로 Lambda는 메시지 볼륨을 기반으로 이벤트 폴러의 규모를 자동으로 조정합니다. 프로비저닝 모드를 활성화하면 예상 트래픽 패턴을 처리할 준비 상태가 유지되는 최소 및 최대 전용 폴링 리소스 수를 할당합니다. 이렇게 하면 다음 2가지 방법으로 이벤트 소스 매핑의 성능을 최적화할 수 있습니다.
+ 표준 모드(기본값): Lambda는 소수의 폴러로 시작하여 워크로드에 따라 스케일 업하거나 스케일 다운하여 스케일을 자동으로 관리합니다.
+ 프로비저닝 모드: 최소 및 최대 제한을 사용하여 전용 폴링 리소스를 구성하면서 규모 조정 속도를 3배 높이고 처리 용량을 최대 16배 높일 수 있습니다.

표준 대개열의 경우 Lambda는 [긴 폴링](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html#sqs-long-polling)을 사용하여 대기열이 활성화될 때까지 대기열을 폴링합니다. 메시지를 사용할 수 있는 경우 Lambda는 함수를 동시에 5번 호출하여 한 번에 5개의 배치를 처리하기 시작합니다. 메시지를 계속 사용할 수 있는 경우 Lambda는 배치를 읽는 프로세스의 수를 분당 최대 300개의 추가 동시 간접 호출까지 증가시킵니다. 이벤트 소스 매핑으로 동시에 처리할 수 있는 최대 간접 호출 수는 1,250개입니다. 트래픽이 적으면 Lambda는 처리 규모를 5개의 동시 간접 호출로 다시 조정하고 동시 간접 호출을 2개까지 최적화하여 Amazon SQS 직접 호출과 해당 비용을 줄일 수 있습니다. 그러나 최대 동시성 설정을 활성화한 경우에는 이 최적화를 사용할 수 없습니다.

FIFO 대기열의 경우, Lambda는 메시지를 수신하는 순서대로 함수에 메시지를 보냅니다. FIFO 대기열에 메시지를 전송할 때 [메시지 그룹 ID](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html)를 지정합니다. Amazon SQS는 동일한 그룹의 메시지가 순서대로 Lambda에 전송되도록 합니다. Lambda가 메시지를 배치로 읽을 때 각 배치에는 둘 이상의 메시지 그룹의 메시지가 포함될 수 있지만 메시지 순서는 그대로 유지됩니다. 함수가 오류를 반환하면 함수는 Lambda가 동일한 그룹에서 추가 메시지를 수신하기 전에 영향을 받는 메시지에 대해 모든 재시도를 시도합니다.

프로비저닝 모드를 사용할 때 각 이벤트 폴러는 최대 1MB/초의 처리량, 최대 10개의 동시 간접 호출 또는 초당 최대 10개의 Amazon SQS 폴링 API 직접 호출을 처리할 수 있습니다. Lambda는 구성된 최소 및 최대 이벤트 폴러 수를 조정하여 분당 최대 1,000개의 동시성을 빠르게 추가하면서 Amazon SQS 이벤트를 일관적이면서 지연 시간이 짧은 방식으로 처리합니다. 프로비저닝된 모드를 사용하면 추가 비용이 발생합니다. 요금에 대한 자세한 내용은 [AWS Lambda 요금](https://aws.amazon.com/lambda/pricing/)을 참조하세요. 각 이벤트 폴러는 SQS 대기열에 초당 최대 10개의 폴링을 사용하는 [긴 폴링](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html)을 사용하므로 SQS API 요청 비용이 발생합니다. 자세한 내용은 [Amazon SQS 요금](https://aws.amazon.com/sqs/pricing/ )을 참조하세요. 이러한 옵션은 함께 사용할 수 없으므로 최대 동시성 설정을 사용하는 대신 최소 및 최대 이벤트 폴러 설정을 통해 조정 및 동시성을 제어합니다.

**참고**  
최대 동시성 설정과 프로비저닝 모드를 동시에 사용할 수는 없습니다. 프로비저닝 모드가 활성화되면 최소 및 최대 이벤트 폴러 수를 통해 Amazon SQS 이벤트 소스 매핑의 조정 및 동시성을 제어할 수 있습니다.

## Amazon SQS 이벤트 소스의 최대 동시성 구성
<a name="events-sqs-max-concurrency"></a>

최대 동시성 설정을 사용하여 SQS 이벤트 소스의 규모 조정 동작을 제어할 수 있습니다. 최대 동시성은 프로비저닝 모드가 활성화된 상태에서 사용할 수 없습니다. 최대 동시성 설정은 Amazon SQS 이벤트 소스가 간접 호출할 수 있는 함수의 동시 인스턴스 수를 제한합니다. 최대 동시성은 이벤트 소스 수준 설정입니다. 여러 Amazon SQS 이벤트 소스가 하나의 함수에 매핑되어 있는 경우, 각 이벤트 소스마다 별도의 최대 동시성 설정이 있을 수 있습니다. 최대 동시성을 사용하여 단일 대기열이 함수의 [예약된 동시성](configuration-concurrency.md) 전체를 사용하거나 [계정의 나머지 동시성 할당량](gettingstarted-limits.md)을 사용하지 못하도록 할 수 있습니다. Amazon SQS 이벤트 소스에 대해 최대 동시성을 구성하는 데는 요금이 부과되지 않습니다.

중요한 것은 최대 동시성과 예약된 동시성은 독립된 두 설정이라는 것입니다. 함수의 예약된 동시성보다 큰 최대 동시성을 설정하지 마세요. 최대 동시성을 구성한 경우, 함수의 예약된 동시성이 함수의 모든 Amazon SQS 이벤트 소스에 대한 총 최대 동시성보다 크거나 같은지 확인합니다. 그렇지 않으면 Lambda가 메시지를 제한할 수도 있습니다.

계정의 동시 실행 할당량이 기본값인 1,000으로 설정된 경우, 최대 동시성을 지정하지 않는 한 Amazon SQS 이벤트 소스 매핑은 함수 인스턴스를 이 값까지 간접 호출하도록 확장할 수 있습니다.

계정의 기본 동시성 할당량이 증가하면 Lambda가 새 할당량까지 동시 함수 인스턴스를 간접 호출하지 못할 수 있습니다. 기본적으로 Lambda는 Amazon SQS 이벤트 소스 매핑을 위해 최대 1,250개의 동시 함수 인스턴스를 간접 호출하도록 확장할 수 있습니다. 사용 사례에 충분하지 않은 경우 AWS Support에 문의하여 계정의 Amazon SQS 이벤트 소스 매핑 동시성 증가에 대해 논의하세요.

**참고**  
FIFO 대기열의 경우 동시 호출은 [메시지 그룹 ID](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html)(`messageGroupId`) 또는 최대 동시성 설정 중 더 낮은 값으로 제한됩니다. 예를 들어, 메시지 그룹 ID가 6개이고 최대 동시성이 10으로 설정된 경우 함수는 최대 6개의 동시 호출을 가질 수 있습니다.

신규 및 기존 Amazon SQS 이벤트 소스 매핑에 대해 최대 동시성을 구성할 수 있습니다.

**Lambda 콘솔을 사용하여 최대 동시성 구성**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

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

1. **Function overview**(함수 개요)에서 **SQS**를 선택합니다. 그러면 **Configuration**(구성) 탭이 열립니다.

1. Amazon SQS 트리거를 선택하고 **Edit**(편집)를 선택합니다.

1. **Maximum concurrency**(최대 동시성)에 2에서 1,000 사이의 숫자를 입력합니다. 최대 동시성을 해제하려면 상자를 비워 둡니다.

1. **저장**을 선택합니다.

**AWS Command Line Interface(AWS CLI)를 사용하여 최대 동시성 구성**  
`--scaling-config` 옵션과 함께 [update-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-event-source-mapping.html) 명령을 사용합니다. 예제:

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --scaling-config '{"MaximumConcurrency":5}'
```

최대 동시성을 해제하려면 `--scaling-config`에 빈 값을 입력합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --scaling-config "{}"
```

**Lambda API를 사용하여 최대 동시성 구성**  
[ScalingConfig](https://docs.aws.amazon.com/lambda/latest/api/API_ScalingConfig.html) 객체와 함께 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 또는 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) 작업을 사용합니다.

# Lambda에서 SQS 이벤트 소스에 대한 오류 처리
<a name="services-sqs-errorhandling"></a>

SQS 이벤트 소스와 관련된 오류를 처리하기 위해 Lambda는 백오프 전략과 함께 재시도 전략을 자동으로 사용합니다. [부분 배치 응답](#services-sqs-batchfailurereporting)을 반환하도록 SQS 이벤트 소스 매핑을 구성하여 오류 처리 동작을 사용자 지정할 수도 있습니다.

## 실패한 호출에 대한 백오프 전략
<a name="services-sqs-backoff-strategy"></a>

호출이 실패하면 Lambda는 백오프 전략을 구현하면서 호출을 재시도합니다. 백오프 전략은 Lambda가 함수 코드의 오류로 인해 장애를 겪었는지 아니면 스로틀링으로 인해 장애가 발생했는지에 따라 약간 다릅니다.
+  **함수 코드**로 인해 오류가 발생한 경우 Lambda는 간접 호출 처리 및 재시도를 중지합니다. 그 동안 Lambda는 점진적으로 백오프를 수행하여 Amazon SQS 이벤트 소스 매핑에 할당되는 동시성의 양을 줄입니다. 대기열의 표시 제한 시간이 다 지나면 메시지가 대기열에 다시 나타납니다.
+ **스로틀링**으로 인해 호출이 실패하는 경우 Lambda는 Amazon SQS 이벤트 소스 매핑에 할당되는 동시성의 양을 줄여 재시도를 점진적으로 백오프합니다. Lambda는 메시지의 타임스탬프가 대기열의 가시성 제한 시간을 초과할 때(이때 Lambda가 메시지를 삭제)까지 메시지를 계속 재시도합니다.

## 부분 일괄 응답 구현
<a name="services-sqs-batchfailurereporting"></a>

배치를 처리하는 동안 Lambda 함수에 오류가 발생하면 Lambda가 성공적으로 처리한 메시지를 포함하여 해당 배치의 모든 메시지가 기본적으로 대기열에 다시 표시됩니다. 따라서 함수가 동일한 메시지를 여러 번 처리할 수 있습니다.

실패한 배치에서 정상 처리된 메시지를 재처리하지 않으려면 실패한 메시지만 다시 표시하도록 이벤트 소스 매핑을 구성할 수 있습니다. 이를 부분 일괄 응답이라고 합니다. 부분 일괄 응답을 켜려면 이벤트 소스 매핑을 구성할 때 [FunctionResponseTypes](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html#lambda-UpdateEventSourceMapping-request-FunctionResponseTypes) 작업에 대해 `ReportBatchItemFailures`을 지정하십시오. 그러면 함수가 부분적인 성공을 반환할 수 있으므로 레코드에 대한 불필요한 재시도 횟수를 줄일 수 있습니다.

**참고**  
Powertools for AWS Lambda의 [배치 프로세서 유틸리티](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/)는 모든 부분 배치 응답 로직을 자동으로 처리합니다. 이 유틸리티는 배치 처리 패턴 구현을 간소화하고 배치 항목 실패를 올바르게 처리하는 데 필요한 사용자 지정 코드를 줄입니다. Python, Java, Typescript 및 .NET에 사용할 수 있습니다.

`ReportBatchItemFailures`이 활성화되면 Lambda는 함수 호출이 실패할 때 [메시지 폴링을 스케일 다운](#services-sqs-backoff-strategy)하지 않습니다. 일부 메시지에 오류가 발생할 것으로 예상되고 이러한 오류가 메시지 처리 속도에 영향을 미치지 않도록 하려면 `ReportBatchItemFailures`를 사용하십시오.

**참고**  
부분 일괄 응답을 사용할 때는 다음 사항에 유의하세요.  
함수에서 예외가 발생한 경우 전체 배치가 완전한 실패로 간주됩니다.
FIFO 대기열과 함께 이 기능을 사용하는 경우 함수는 첫 번째 실패 후 메시지 처리를 중지하고 `batchItemFailures`에서 모든 실패한 메시지와 처리되지 않은 메시지를 반환해야 합니다. 그러면 대기열의 메시지 순서를 유지할 수 있습니다.

**부분 배치 보고를 활성화 방법**

1. [부분 일괄 응답 구현에 대한 모범 사례](https://docs.aws.amazon.com/prescriptive-guidance/latest/lambda-event-filtering-partial-batch-responses-for-sqs/best-practices-partial-batch-responses.html)를 검토하세요.

1. 다음 명령을 실행하여 함수의 `ReportBatchItemFailures`을 활성화합니다. 이벤트 소스 매핑의 UUID를 가져오려면 [list-event-source-mappings](https://docs.aws.amazon.com/cli/latest/reference/lambda/list-event-source-mappings.html) AWS CLI 명령을 실행합니다.

   ```
   aws lambda update-event-source-mapping \
   --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
   --function-response-types "ReportBatchItemFailures"
   ```

1. 함수 코드를 업데이트하여 모든 예외를 포착하고 실패한 메시지를 `batchItemFailures` JSON 응답으로 반환하세요. `batchItemFailures` 응답에는 메시지 ID 목록이 `itemIdentifier` JSON 값으로 포함되어야 합니다.

   예를 들어 메시지 ID가 `id1`, `id2`, `id3`, `id4`, `id5`인 5개의 메시지로 구성된 배치가 있다고 가정합니다. 함수가 `id1`, `id3`, `id5`를 성공적으로 처리합니다. `id2` 및 `id4` 메시지를 대기열에서 다시 볼 수 있도록 하려면 함수가 다음 응답을 리턴해야 합니다.

   ```
   { 
     "batchItemFailures": [ 
           {
               "itemIdentifier": "id2"
           },
           {
               "itemIdentifier": "id4"
           }
       ]
   }
   ```

   다음은 일괄적으로 실패한 메시지 ID 목록을 반환하는 함수 코드의 몇 가지 예입니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 SQS 배치 항목 실패 보고  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   using Amazon.Lambda.Core;
   using Amazon.Lambda.SQSEvents;
   
   // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
   [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
   namespace sqsSample;
   
   public class Function
   {
       public async Task<SQSBatchResponse> FunctionHandler(SQSEvent evnt, ILambdaContext context)
       {
           List<SQSBatchResponse.BatchItemFailure> batchItemFailures = new List<SQSBatchResponse.BatchItemFailure>();
           foreach(var message in evnt.Records)
           {
               try
               {
                   //process your message
                   await ProcessMessageAsync(message, context);
               }
               catch (System.Exception)
               {
                   //Add failed message identifier to the batchItemFailures list
                   batchItemFailures.Add(new SQSBatchResponse.BatchItemFailure{ItemIdentifier=message.MessageId}); 
               }
           }
           return new SQSBatchResponse(batchItemFailures);
       }
   
       private async Task ProcessMessageAsync(SQSEvent.SQSMessage message, ILambdaContext context)
       {
           if (String.IsNullOrEmpty(message.Body))
           {
               throw new Exception("No Body in SQS Message.");
           }
           context.Logger.LogInformation($"Processed message {message.Body}");
           // TODO: Do interesting work based on the new message
           await Task.CompletedTask;
       }
   }
   ```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 SQS 배치 항목 실패 보고  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   package main
   
   import (
   	"context"
   	"fmt"
   	"github.com/aws/aws-lambda-go/events"
   	"github.com/aws/aws-lambda-go/lambda"
   )
   
   func handler(ctx context.Context, sqsEvent events.SQSEvent) (map[string]interface{}, error) {
   	batchItemFailures := []map[string]interface{}{}
   
   	for _, message := range sqsEvent.Records {
   		if len(message.Body) > 0 {
   			// Your message processing condition here
   			fmt.Printf("Successfully processed message: %s\n", message.Body)
   		} else {
   			// Message processing failed
   			fmt.Printf("Failed to process message %s\n", message.MessageId)
   			batchItemFailures = append(batchItemFailures, map[string]interface{}{"itemIdentifier": message.MessageId})
   		}
   	}
   
   	sqsBatchResponse := map[string]interface{}{
   		"batchItemFailures": batchItemFailures,
   	}
   	return sqsBatchResponse, nil
   }
   
   func main() {
   	lambda.Start(handler)
   }
   ```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda로 SQS 배치 항목 실패 보고  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   import com.amazonaws.services.lambda.runtime.events.SQSEvent;
   import com.amazonaws.services.lambda.runtime.events.SQSBatchResponse;
    
   import java.util.ArrayList;
   import java.util.List;
    
   public class ProcessSQSMessageBatch implements RequestHandler<SQSEvent, SQSBatchResponse> {
       @Override
       public SQSBatchResponse handleRequest(SQSEvent sqsEvent, Context context) {
            List<SQSBatchResponse.BatchItemFailure> batchItemFailures = new ArrayList<SQSBatchResponse.BatchItemFailure>();
   
            for (SQSEvent.SQSMessage message : sqsEvent.getRecords()) {
                try {
                    //process your message
                } catch (Exception e) {
                    //Add failed message identifier to the batchItemFailures list
                    batchItemFailures.add(new SQSBatchResponse.BatchItemFailure(message.getMessageId()));
                }
            }
            return new SQSBatchResponse(batchItemFailures);
        }
   }
   ```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda에서 SQS 배치 항목 실패를 보고합니다.  

   ```
   // Node.js 20.x Lambda runtime, AWS SDK for Javascript V3
   export const handler = async (event, context) => {
       const batchItemFailures = [];
       for (const record of event.Records) {
           try {
               await processMessageAsync(record, context);
           } catch (error) {
               batchItemFailures.push({ itemIdentifier: record.messageId });
           }
       }
       return { batchItemFailures };
   };
   
   async function processMessageAsync(record, context) {
       if (record.body && record.body.includes("error")) {
           throw new Error("There is an error in the SQS Message.");
       }
       console.log(`Processed message: ${record.body}`);
   }
   ```
TypeScript를 사용하여 Lambda로 SQS 배치 항목 실패를 보고합니다.  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   import { SQSEvent, SQSBatchResponse, Context, SQSBatchItemFailure, SQSRecord } from 'aws-lambda';
   
   export const handler = async (event: SQSEvent, context: Context): Promise<SQSBatchResponse> => {
       const batchItemFailures: SQSBatchItemFailure[] = [];
   
       for (const record of event.Records) {
           try {
               await processMessageAsync(record);
           } catch (error) {
               batchItemFailures.push({ itemIdentifier: record.messageId });
           }
       }
   
       return {batchItemFailures: batchItemFailures};
   };
   
   async function processMessageAsync(record: SQSRecord): Promise<void> {
       if (record.body && record.body.includes("error")) {
           throw new Error('There is an error in the SQS Message.');
       }
       console.log(`Processed message ${record.body}`);
   }
   ```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 SQS 배치 항목 실패 보고  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   <?php
   
   use Bref\Context\Context;
   use Bref\Event\Sqs\SqsEvent;
   use Bref\Event\Sqs\SqsHandler;
   use Bref\Logger\StderrLogger;
   
   require __DIR__ . '/vendor/autoload.php';
   
   class Handler extends SqsHandler
   {
       private StderrLogger $logger;
       public function __construct(StderrLogger $logger)
       {
           $this->logger = $logger;
       }
   
       /**
        * @throws JsonException
        * @throws \Bref\Event\InvalidLambdaEvent
        */
       public function handleSqs(SqsEvent $event, Context $context): void
       {
           $this->logger->info("Processing SQS records");
           $records = $event->getRecords();
   
           foreach ($records as $record) {
               try {
                   // Assuming the SQS message is in JSON format
                   $message = json_decode($record->getBody(), true);
                   $this->logger->info(json_encode($message));
                   // TODO: Implement your custom processing logic here
               } catch (Exception $e) {
                   $this->logger->error($e->getMessage());
                   // failed processing the record
                   $this->markAsFailed($record);
               }
           }
           $totalRecords = count($records);
           $this->logger->info("Successfully processed $totalRecords SQS records");
       }
   }
   
   $logger = new StderrLogger();
   return new Handler($logger);
   ```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 SQS 배치 항목 실패 보고  

   ```
   # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   # SPDX-License-Identifier: Apache-2.0
   
   def lambda_handler(event, context):
       if event:
           batch_item_failures = []
           sqs_batch_response = {}
        
           for record in event["Records"]:
               try:
                   print(f"Processed message: {record['body']}")
               except Exception as e:
                   batch_item_failures.append({"itemIdentifier": record['messageId']})
           
           sqs_batch_response["batchItemFailures"] = batch_item_failures
           return sqs_batch_response
   ```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda-with-batch-item-handling) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 SQS 배치 항목 실패를 보고합니다.  

   ```
   # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   # SPDX-License-Identifier: Apache-2.0
   require 'json'
   
   def lambda_handler(event:, context:)
     if event
       batch_item_failures = []
       sqs_batch_response = {}
   
       event["Records"].each do |record|
         begin
           # process message
         rescue StandardError => e
           batch_item_failures << {"itemIdentifier" => record['messageId']}
         end
       end
   
       sqs_batch_response["batchItemFailures"] = batch_item_failures
       return sqs_batch_response
     end
   end
   ```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/lambda-function-sqs-report-batch-item-failures) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 SQS 배치 항목 실패를 보고합니다.  

   ```
   // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   // SPDX-License-Identifier: Apache-2.0
   use aws_lambda_events::{
       event::sqs::{SqsBatchResponse, SqsEvent},
       sqs::{BatchItemFailure, SqsMessage},
   };
   use lambda_runtime::{run, service_fn, Error, LambdaEvent};
   
   async fn process_record(_: &SqsMessage) -> Result<(), Error> {
       Err(Error::from("Error processing message"))
   }
   
   async fn function_handler(event: LambdaEvent<SqsEvent>) -> Result<SqsBatchResponse, Error> {
       let mut batch_item_failures = Vec::new();
       for record in event.payload.records {
           match process_record(&record).await {
               Ok(_) => (),
               Err(_) => batch_item_failures.push(BatchItemFailure {
                   item_identifier: record.message_id.unwrap(),
               }),
           }
       }
   
       Ok(SqsBatchResponse {
           batch_item_failures,
       })
   }
   
   #[tokio::main]
   async fn main() -> Result<(), Error> {
       run(service_fn(function_handler)).await
   }
   ```

------

실패한 이벤트가 대기열로 반환되지 않는 경우 AWS 지식 센터에서 [Lambda 함수 SQS ReportBatchItemFailure의 문제를 해결하려면 어떻게 해야 합니까?](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-sqs-report-batch-item-failures/)를 참조하십시오.

### 성공 및 실패 조건
<a name="sqs-batchfailurereporting-conditions"></a>

Lambda는 함수가 다음 중 하나를 반환할 경우 배치를 완전한 성공으로 처리합니다.
+ 비어 있는 `batchItemFailures` 목록
+ null `batchItemFailures` 목록
+ 비어 있는 `EventResponse`
+ null `EventResponse`

Lambda는 함수가 다음 중 하나를 반환할 경우 배치를 완전한 실패로 처리합니다.
+ 잘못된 JSON 응답
+ 빈 문자열 `itemIdentifier`
+ null `itemIdentifier`
+ 키 이름이 잘못된 `itemIdentifier`
+ 존재하지 않는 메시지 ID가 있는 `itemIdentifier` 값

### CloudWatch 지표
<a name="sqs-batchfailurereporting-metrics"></a>

함수가 배치 항목 실패를 올바르게 보고하는지 확인하려면 Amazon CloudWatch에서 `NumberOfMessagesDeleted` 및 `ApproximateAgeOfOldestMessage` Amazon SQS 지표를 모니터링하면 됩니다.
+ `NumberOfMessagesDeleted`는 대기열에서 제거된 메시지 수를 추적합니다. 이 값이 0으로 떨어지면 함수 응답이 실패한 메시지를 올바르게 반환하지 않는다는 신호입니다.
+ `ApproximateAgeOfOldestMessage`는 가장 오래된 메시지가 대기열에 머물렀던 시간을 추적합니다. 이 지표가 급격히 증가하면 함수가 실패한 메시지를 올바르게 반환하지 않음을 나타낼 수 있습니다.

### Powertools for AWS Lambda 배치 프로세서 사용
<a name="services-sqs-batchfailurereporting-powertools"></a>

Powertools for AWS Lambda의 배치 프로세서 유틸리티는 부분 배치 응답 로직을 자동으로 처리하여 배치 실패 보고 구현에 따르는 복잡성을 줄입니다. 다음은 배치 프로세서를 사용하는 예제입니다.

**Python**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서를](https://docs.powertools.aws.dev/lambda/python/latest/utilities/batch/) 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 Amazon SQS 메시지를 처리합니다.  

```
import json
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.batch import BatchProcessor, EventType, process_partial_response
from aws_lambda_powertools.utilities.data_classes import SQSEvent
from aws_lambda_powertools.utilities.typing import LambdaContext

processor = BatchProcessor(event_type=EventType.SQS)
logger = Logger()

def record_handler(record):
    logger.info(record)
    # Your business logic here
    # Raise an exception to mark this record as failed
    
def lambda_handler(event, context: LambdaContext):
    return process_partial_response(
        event=event, 
        record_handler=record_handler, 
        processor=processor,
        context=context
    )
```

**TypeScript**  
전체 예제 및 설정 지침은 [배치 프로세서 설명서를](https://docs.aws.amazon.com/powertools/typescript/latest/features/batch/) 참조하세요.
AWS Lambda 배치 프로세서를 사용하여 Amazon SQS 메시지를 처리합니다.  

```
import { BatchProcessor, EventType, processPartialResponse } from '@aws-lambda-powertools/batch';
import { Logger } from '@aws-lambda-powertools/logger';
import type { SQSEvent, Context } from 'aws-lambda';

const processor = new BatchProcessor(EventType.SQS);
const logger = new Logger();

const recordHandler = async (record: any): Promise<void> => {
    logger.info('Processing record', { record });
    // Your business logic here
    // Throw an error to mark this record as failed
};

export const handler = async (event: SQSEvent, context: Context) => {
    return processPartialResponse(event, recordHandler, processor, {
        context,
    });
};
```

# Amazon SQS 이벤트 소스 매핑을 위한 Lambda 파라미터
<a name="services-sqs-parameters"></a>

모든 Lambda 이벤트 소스 유형은 동일한 [CreateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_CreateEventSourceMapping.html) 및 [UpdateEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateEventSourceMapping.html) API 작업을 공유합니다. 그러나 일부 파라미터만 Amazon SQS에 적용됩니다.


| 파라미터 | 필수 | 기본값 | 참고 | 
| --- | --- | --- | --- | 
|  BatchSize  |  N  |  10  |  표준 대기열의 경우 최댓값은 10,000입니다. FIFO 대기열의 경우 최댓값은 10입니다.  | 
|  활성  |  N  |  true  | 없음  | 
|  EventSourceArn  |  Y  | 해당 사항 없음 |  데이터 스트림 또는 스트림 소비자의 ARN  | 
|  FunctionName  |  Y  | 해당 사항 없음  | 없음  | 
|  FilterCriteria  |  N  |  해당 사항 없음   |  [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)  | 
|  FunctionResponseTypes  |  N  | 해당 사항 없음  |  함수가 배치에서 특정 실패를 보고하도록 하려면 `FunctionResponseTypes`에 `ReportBatchItemFailures` 값을 포함하세요. 자세한 내용은 [부분 일괄 응답 구현](services-sqs-errorhandling.md#services-sqs-batchfailurereporting) 섹션을 참조하세요.  | 
|  MaximumBatchingWindowInSeconds  |  N  |  0  | FIFO 대기열에는 배치 기간이 지원되지 않습니다. | 
|  ProvisionedPollerConfig  |  N  |  해당 사항 없음  |  SQS 이벤트 소스 매핑에 대한 최소(2\$1200) 및 최대(2\$12,000) 전용 이벤트 폴러 수를 구성합니다. 각 폴러는 최대 1MB/s의 처리량과 10개의 동시 간접 호출을 처리할 수 있습니다.  | 
|  ScalingConfig  |  N  |  N/A   |  [Amazon SQS 이벤트 소스의 최대 동시성 구성](services-sqs-scaling.md#events-sqs-max-concurrency)  | 

# Amazon SQS 이벤트 소스를 통해 이벤트 필터링 사용
<a name="with-sqs-filtering"></a>

이벤트 필터링을 사용하여 Lambda가 함수로 전송하는 스트림 또는 대기열의 레코드를 제어할 수 있습니다. 이벤트 필터링의 작동 방식에 대한 일반적인 내용은 [Lambda가 함수로 보내는 이벤트에 대한 제어](invocation-eventfiltering.md)을 참조하세요.

이 섹션에서는 Amazon SQS 이벤트 소스에 대한 이벤트 필터링에 중점을 둡니다.

**참고**  
Amazon SQS 이벤트 소스 매핑은 `body` 키에 대한 필터링만 지원합니다.

**Topics**
+ [

## Amazon SQS 이벤트 필터링 기본 사항
](#filtering-SQS)

## Amazon SQS 이벤트 필터링 기본 사항
<a name="filtering-SQS"></a>

Amazon SQS 대기열에 다음 JSON 형식의 메시지가 포함되어 있다고 가정해 보겠습니다.

```
{
    "RecordNumber": 1234,
    "TimeStamp": "yyyy-mm-ddThh:mm:ss",
    "RequestCode": "AAAA"
}
```

이 대기열에 대한 예제 레코드는 다음과 같습니다.

```
{
    "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
    "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
    "body": "{\n "RecordNumber": 1234,\n "TimeStamp": "yyyy-mm-ddThh:mm:ss",\n "RequestCode": "AAAA"\n}",
    "attributes": {
        "ApproximateReceiveCount": "1",
        "SentTimestamp": "1545082649183",
        "SenderId": "AIDAIENQZJOLO23YVJ4VO",
        "ApproximateFirstReceiveTimestamp": "1545082649185"
        },
    "messageAttributes": {},
    "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
    "eventSource": "aws:sqs",
    "eventSourceARN": "arn:aws:sqs:us-west-2:123456789012:my-queue",
    "awsRegion": "us-west-2"
}
```

Amazon SQS 메시지의 콘텐츠를 기반으로 필터링하려면 Amazon SQS 메시지 레코드의 `body` 키를 사용합니다. Amazon SQS 메시지의 `RequestCode`가 'BBBB'인 레코드만 처리하려고 한다고 가정해 보겠습니다. `FilterCriteria` 객체는 다음과 같습니다.

```
{
    "Filters": [
        {
            "Pattern": "{ \"body\" : { \"RequestCode\" : [ \"BBBB\" ] } }"
        }
    ]
}
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{
    "body": {
        "RequestCode": [ "BBBB" ]
        }
}
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "body" : { "RequestCode" : [ "BBBB" ] } }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:sqs:us-east-2:123456789012:my-queue \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"body\" : { \"RequestCode\" : [ \"BBBB\" ] } }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"body\" : { \"RequestCode\" : [ \"BBBB\" ] } }"}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
  Filters:
    - Pattern: '{ "body" : { "RequestCode" : [ "BBBB" ] } }'
```

------

함수가 `RecordNumber`가 9,999보다 큰 레코드만 처리하도록 하려는 경우를 가정해 보겠습니다. `FilterCriteria` 객체는 다음과 같습니다.

```
{
    "Filters": [
        {
            "Pattern": "{ \"body\" : { \"RecordNumber\" : [ { \"numeric\": [ \">\", 9999 ] } ] } }"
        }
    ]
}
```

명확성을 더하기 위해 일반 JSON으로 확장된 필터의 `Pattern` 값은 다음과 같습니다.

```
{
    "body": {
        "RecordNumber": [
            {
                "numeric": [ ">", 9999 ]
            }
        ]
    }
}
```

콘솔, AWS CLI 또는 AWS SAM 템플릿을 사용하여 필터를 추가할 수 있습니다.

------
#### [ Console ]

콘솔을 사용하여 이 필터를 추가하려면 [이벤트 소스 매핑에 필터 기준 연결(콘솔)](invocation-eventfiltering.md#filtering-console)의 지침을 따르고 **필터 기준**에 대해 다음 문자열을 입력합니다.

```
{ "body" : { "RecordNumber" : [ { "numeric": [ ">", 9999 ] } ] } }
```

------
#### [ AWS CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 이러한 필터 기준으로 새 이벤트 소스 매핑을 생성하려면 다음 명령을 실행합니다.

```
aws lambda create-event-source-mapping \
    --function-name my-function \
    --event-source-arn arn:aws:sqs:us-east-2:123456789012:my-queue \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"body\" : { \"RecordNumber\" : [ { \"numeric\": [ \">\", 9999 ] } ] } }"}]}'
```

이러한 필터 기준을 기존 이벤트 소스 매핑에 추가하려면 다음 명령을 실행합니다.

```
aws lambda update-event-source-mapping \
    --uuid "a1b2c3d4-5678-90ab-cdef-11111EXAMPLE" \
    --filter-criteria '{"Filters": [{"Pattern": "{ \"body\" : { \"RecordNumber\" : [ { \"numeric\": [ \">\", 9999 ] } ] } }"}]}'
```

------
#### [ AWS SAM ]

AWS SAM을 사용하여 이 필터를 추가하려면 이벤트 소스의 YAML 템플릿에 다음 코드 조각을 추가합니다.

```
FilterCriteria:
  Filters:
    - Pattern: '{ "body" : { "RecordNumber" : [ { "numeric": [ ">", 9999 ] } ] } }'
```

------

Amazon SQS의 경우 메시지 본문은 임의의 문자열이 될 수 있습니다. 그러나 `FilterCriteria`에서 유효한 JSON 형식의 `body`를 기대하는 경우 문제가 될 수 있습니다. 반대 시나리오도 마찬가지입니다. 수신 메시지 본문이 JSON 형식이지만 필터 기준이 `body`를 일반 문자열로 예상하는 경우 의도하지 않은 동작이 발생할 수 있습니다.

이 문제를 방지하려면 `FilterCriteria`에서 본문의 형식이 대기열에서 수신하는 메시지의 `body`의 예상 형식과 일치하는지 확인합니다. 메시지를 필터링하기 전에 Lambda는 수신 메시지 본문의 형식과 `body`의 필터 패턴의 형식을 자동으로 평가합니다. 일치하지 않으면 Lambda는 메시지를 삭제합니다. 다음 표에는 이 평가가 요약되어 있습니다.


| 수신 메시지 `body` 형식 | 필터 패턴 `body` 형식 | 결과적 작업 | 
| --- | --- | --- | 
|  일반 문자열  |  일반 문자열  |  Lambda는 필터 기준에 따라 필터링합니다.  | 
|  일반 문자열  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  일반 문자열  |  유효한 JSON  |  Lambda가 메시지를 삭제합니다.  | 
|  유효한 JSON  |  일반 문자열  |  Lambda가 메시지를 삭제합니다.  | 
|  유효한 JSON  |  데이터 속성에 대한 필터 패턴 없음  |  Lambda는 필터 기준에 따라(다른 메타데이터 속성에만 해당) 필터링합니다.  | 
|  유효한 JSON  |  유효한 JSON  |  Lambda는 필터 기준에 따라 필터링합니다.  | 

# 자습서: Amazon SQS에서 Lambda 사용
<a name="with-sqs-example"></a>

이 자습서에서는 [Amazon Simple Queue Service(Amazon SQS)](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html) 대기열에서 메시지를 사용하는 Lambda 함수를 생성합니다. Lambda 함수는 새 메시지가 대기열에 추가될 때마다 실행됩니다. 이 함수는 메시지를 Amazon CloudWatch Logs 스트림에 기록합니다. 다음 다이어그램은 자습서를 완료하는 데 사용하는 AWS 리소스를 보여 줍니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/sqs_tut_resources.png)


이 자습서를 완료하려면 다음 단계를 수행하세요.

1. CloudWatch Logs에 메시지를 작성하는 Lambda 함수를 생성합니다.

1. Amazon SQS 대기열을 생성합니다.

1. Lambda 이벤트 소스 매핑을 생성합니다. 이벤트 소스 매핑은 Amazon SQS 대기열을 읽고 새 메시지가 추가되면 Lambda 함수를 간접적으로 간접 호출합니다.

1. 대기열에 메시지를 추가하고 CloudWatch Logs에서 결과를 모니터링하여 설정을 테스트합니다.

## 사전 조건
<a name="with-sqs-prepare"></a>

### AWS Command Line Interface 설치
<a name="install_aws_cli"></a>

아직 AWS Command Line Interface를 설치하지 않은 경우 [AWS CLI의 최신 버전 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)에서 설명하는 단계에 따라 설치하세요.

이 자습서에서는 명령을 실행할 셸 또는 명령줄 터미널이 필요합니다. Linux 및 macOS에서는 선호하는 셸과 패키지 관리자를 사용합니다.

**참고**  
Windows에서는 Lambda와 함께 일반적으로 사용하는 일부 Bash CLI 명령(예:`zip`)은 운영 체제의 기본 제공 터미널에서 지원되지 않습니다. Ubuntu와 Bash의 Windows 통합 버전을 가져오려면 [Linux용 Windows Subsystem을 설치](https://docs.microsoft.com/en-us/windows/wsl/install-win10)합니다.

## 실행 역할 생성
<a name="with-sqs-create-execution-role"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/sqs_tut_steps1.png)


[실행 역할](lambda-intro-execution-role.md)은 AWS 서비스 및 리소스에 액세스할 수 있는 권한을 Lambda 함수에 부여하는 AWS Identity and Access Management(IAM) 역할입니다. 함수가 Amazon SQS에서 항목을 읽을 수 있도록 허용하려면 **AWSLambdaSQSQueueExecutionRole** 권한 정책을 연결합니다.

**실행 역할을 생성하고 Amazon SQS 권한 정책을 연결하려면**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. **역할 생성**을 선택합니다.

1. **신뢰할 수 있는 엔터티 유형**에서 **AWS 서비스**를 선택합니다.

1. **사용 사례**에서 **Lambda**를 선택합니다.

1. **다음**을 선택합니다.

1. **권한 정책** 검색 상자에 **AWSLambdaSQSQueueExecutionRole**을 입력합니다.

1. **AWSLambdaSQSQueueExecutionRole** 정책을 선택한 후 **다음**을 선택합니다.

1. **역할 세부 정보**에서 **역할 이름**에 **lambda-sqs-role**을 입력한 다음 **역할 생성**을 선택합니다.

역할을 생성한 후에는 실행 역할의 Amazon 리소스 이름(ARN)을 기록해 둡니다. 이는 이후 단계에서 필요합니다.

## 함수 생성
<a name="with-sqs-create-function"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/sqs_tut_steps2.png)


Amazon SQS 메시지를 처리하는 Lambda 함수를 생성합니다. 함수 코드는 Amazon SQS 메시지 본문을 CloudWatch Logs에 로그합니다.

이 자습서에서는 Node.js 24 런타임을 사용하지만 다른 런타임 언어의 예제 코드도 제공했습니다. 다음 상자에서 탭을 선택하여 관심 있는 런타임에 대한 코드를 볼 수 있습니다. 이 단계에서 사용할 JavaScript 코드는 **JavaScript** 탭에 표시된 첫 번째 예제입니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 SQS 이벤트 사용  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
﻿using Amazon.Lambda.Core;
using Amazon.Lambda.SQSEvents;


// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace SqsIntegrationSampleCode
{
    public async Task FunctionHandler(SQSEvent evnt, ILambdaContext context)
    {
        foreach (var message in evnt.Records)
        {
            await ProcessMessageAsync(message, context);
        }

        context.Logger.LogInformation("done");
    }

    private async Task ProcessMessageAsync(SQSEvent.SQSMessage message, ILambdaContext context)
    {
        try
        {
            context.Logger.LogInformation($"Processed message {message.Body}");

            // TODO: Do interesting work based on the new message
            await Task.CompletedTask;
        }
        catch (Exception e)
        {
            //You can use Dead Letter Queue to handle failures. By configuring a Lambda DLQ.
            context.Logger.LogError($"An error occurred");
            throw;
        }

    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 SQS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration_sqs_to_lambda

import (
	"fmt"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(event events.SQSEvent) error {
	for _, record := range event.Records {
		err := processMessage(record)
		if err != nil {
			return err
		}
	}
	fmt.Println("done")
	return nil
}

func processMessage(record events.SQSMessage) error {
	fmt.Printf("Processed message %s\n", record.Body)
	// TODO: Do interesting work based on the new message
	return nil
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda로 SQS 이벤트 사용  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;

public class Function implements RequestHandler<SQSEvent, Void> {
    @Override
    public Void handleRequest(SQSEvent sqsEvent, Context context) {
        for (SQSMessage msg : sqsEvent.getRecords()) {
            processMessage(msg, context);
        }
        context.getLogger().log("done");
        return null;
    }

    private void processMessage(SQSMessage msg, Context context) {
        try {
            context.getLogger().log("Processed message " + msg.getBody());

            // TODO: Do interesting work based on the new message

        } catch (Exception e) {
            context.getLogger().log("An error occurred");
            throw e;
        }

    }
}
```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/blob/main/integration-sqs-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda로 SQS 이벤트 사용  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
  for (const message of event.Records) {
    await processMessageAsync(message);
  }
  console.info("done");
};

async function processMessageAsync(message) {
  try {
    console.log(`Processed message ${message.body}`);
    // TODO: Do interesting work based on the new message
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}
```
TypeScript를 사용하여 Lambda로 SQS 이벤트 사용  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { SQSEvent, Context, SQSHandler, SQSRecord } from "aws-lambda";

export const functionHandler: SQSHandler = async (
  event: SQSEvent,
  context: Context
): Promise<void> => {
  for (const message of event.Records) {
    await processMessageAsync(message);
  }
  console.info("done");
};

async function processMessageAsync(message: SQSRecord): Promise<any> {
  try {
    console.log(`Processed message ${message.body}`);
    // TODO: Do interesting work based on the new message
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}
```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 SQS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
<?php

# using bref/bref and bref/logger for simplicity

use Bref\Context\Context;
use Bref\Event\InvalidLambdaEvent;
use Bref\Event\Sqs\SqsEvent;
use Bref\Event\Sqs\SqsHandler;
use Bref\Logger\StderrLogger;

require __DIR__ . '/vendor/autoload.php';

class Handler extends SqsHandler
{
    private StderrLogger $logger;
    public function __construct(StderrLogger $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @throws InvalidLambdaEvent
     */
    public function handleSqs(SqsEvent $event, Context $context): void
    {
        foreach ($event->getRecords() as $record) {
            $body = $record->getBody();
            // TODO: Do interesting work based on the new message
        }
    }
}

$logger = new StderrLogger();
return new Handler($logger);
```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 SQS 이벤트를 사용합니다.  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event, context):
    for message in event['Records']:
        process_message(message)
    print("done")

def process_message(message):
    try:
        print(f"Processed message {message['body']}")
        # TODO: Do interesting work based on the new message
    except Exception as err:
        print("An error occurred")
        raise err
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 SQS 이벤트를 사용합니다.  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event:, context:)
  event['Records'].each do |message|
    process_message(message)
  end
  puts "done"
end

def process_message(message)
  begin
    puts "Processed message #{message['body']}"
    # TODO: Do interesting work based on the new message
  rescue StandardError => err
    puts "An error occurred"
    raise err
  end
end
```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sqs-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 SQS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use aws_lambda_events::event::sqs::SqsEvent;
use lambda_runtime::{run, service_fn, Error, LambdaEvent};

async fn function_handler(event: LambdaEvent<SqsEvent>) -> Result<(), Error> {
    event.payload.records.iter().for_each(|record| {
        // process the record
        tracing::info!("Message body: {}", record.body.as_deref().unwrap_or_default())
    });

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        // disable printing the name of the module in every log line.
        .with_target(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

**Node.js Lambda 함수를 생성하려면**

1. 프로젝트에 대한 디렉터리를 생성하고 해당 디렉터리로 전환합니다.

   ```
   mkdir sqs-tutorial
   cd sqs-tutorial
   ```

1. 샘플 JavaScript 코드를 새로운 `index.js` 파일에 복사합니다.

1. 다음 `zip` 명령을 사용하여 배포 패키지를 생성합니다.

   ```
   zip function.zip index.js
   ```

1. [create-function](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-function.html) AWS CLI 명령을 사용하여 Lambda 함수를 생성합니다. `role` 파라미터에 앞서 생성한 실행 역할의 ARN을 입력합니다.
**참고**  
Lambda 함수와 Amazon SQS 대기열은 같은 AWS 리전에 있어야 합니다.

   ```
   aws lambda create-function --function-name ProcessSQSRecord \
   --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
   --role arn:aws:iam::111122223333:role/lambda-sqs-role
   ```

## 함수 테스트
<a name="with-sqs-create-test-function"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/sqs_tut_steps3.png)


`invoke` AWS CLI 명령 및 샘플 Amazon SQS 이벤트를 사용하여 Lambda 함수를 수동으로 간접 호출합니다.

**샘플 이벤트를 사용하여 Lambda 함수를 간접적으로 간접 호출하려면**

1. 다음 JSON을 `input.json`라는 파일로 저장합니다. 이 JSON은 Amazon SQS가 `"body"`에 대기열의 실제 메시지를 포함하는 Lambda 함수로 보낼 수 있는 이벤트를 시뮬레이션합니다. 이 예제에서 메시지는 `"test"`입니다.  
**Example Amazon SQS 이벤트**  

   이는 테스트 이벤트이므로 메시지나 계정 번호를 변경할 필요가 없습니다.

   ```
   {
       "Records": [
           {
               "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
               "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
               "body": "test",
               "attributes": {
                   "ApproximateReceiveCount": "1",
                   "SentTimestamp": "1545082649183",
                   "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                   "ApproximateFirstReceiveTimestamp": "1545082649185"
               },
               "messageAttributes": {},
               "md5OfBody": "098f6bcd4621d373cade4e832627b4f6",
               "eventSource": "aws:sqs",
               "eventSourceARN": "arn:aws:sqs:us-east-1:111122223333:my-queue",
               "awsRegion": "us-east-1"
           }
       ]
   }
   ```

1. 다음 AWS CLI [간접 호출](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/invoke.html) 명령을 실행합니다. 이 명령은 응답으로 CloudWatch 로그를 반환합니다. 로그 검색에 대한 자세한 내용은 [AWS CLI를 사용한 로그 액세스](monitoring-cloudwatchlogs-view.md#monitoring-cloudwatchlogs-cli) 단원을 참조하십시오.

   ```
   aws lambda invoke --function-name ProcessSQSRecord --payload file://input.json out --log-type Tail \
   --query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode
   ```

   **cli-binary-format** 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 `aws configure set cli-binary-format raw-in-base64-out`을(를) 실행하세요. 자세한 내용은 [AWS CLI 지원되는 글로벌 명령줄 옵션](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)을 AWS Command Line Interface 사용 설명서 버전 2에서 참조하세요.

1. 응답에서 `INFO` 로그를 찾습니다. 여기에 Lambda 함수가 메시지 본문을 기록합니다. 다음과 유사한 로그가 표시되어야 합니다.

   ```
   2023-09-11T22:45:04.271Z	348529ce-2211-4222-9099-59d07d837b60	INFO	Processed message test
   2023-09-11T22:45:04.288Z	348529ce-2211-4222-9099-59d07d837b60	INFO	done
   ```

## Amazon SQS 대기열 생성
<a name="with-sqs-configure-sqs"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/sqs_tut_steps4.png)


Lambda 함수가 이벤트 소스로 사용할 수 있는 Amazon SQS 대기열을 생성합니다. Lambda 함수와 Amazon SQS 대기열은 같은 AWS 리전에 있어야 합니다.

**대기열 생성**

1. [Amazon SQS 콘솔](https://console.aws.amazon.com/sqs)을 엽니다.

1. **Create queue**(대기열 생성)를 선택합니다.

1. 대기열의 이름을 입력합니다. 다른 모든 옵션은 기본 설정으로 둡니다.

1. **대기열 생성**을 선택합니다.

대기열을 생성한 후 해당 ARN을 기록해 둡니다. 다음 단계에서 대기열을 Lambda 함수와 연결할 때 필요합니다.

## 이벤트 소스 구성
<a name="with-sqs-attach-notification-configuration"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/sqs_tut_steps5.png)


[이벤트 소스 매핑](invocation-eventsourcemapping.md)을 생성하여 Amazon SQS 대기열을 Lambda 함수에 연결합니다. 이벤트 소스 매핑은 Amazon SQS 대기열을 읽고 새 메시지가 추가되면 Lambda 함수를 간접적으로 간접 호출합니다.

Amazon SQS 대기열과 Lambda 함수 간에 매핑을 생성하려면 AWS CLI [create-event-source-mapping](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-event-source-mapping.html) 명령을 사용합니다. 예제:

```
aws lambda create-event-source-mapping --function-name ProcessSQSRecord  --batch-size 10 \
--event-source-arn arn:aws:sqs:us-east-1:111122223333:my-queue
```

이벤트 소스 매핑 목록을 가져오려면 [list-event-source-mappings](https://awscli.amazonaws.com/v2/documentation/api/2.1.29/reference/lambda/list-event-source-mappings.html) 명령을 사용합니다. 예제:

```
aws lambda list-event-source-mappings --function-name ProcessSQSRecord
```

## 테스트 메시지 보내기
<a name="with-sqs-test-message"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/sqs_tut_steps6.png)


**Amazon SQS 메시지를 Lambda 함수로 보내려면**

1. [Amazon SQS 콘솔](https://console.aws.amazon.com/sqs)을 엽니다.

1. 이전에 생성한 대기열을 선택합니다.

1. [**메시지 전송 및 수신(Send and receive messages)**]을 선택합니다.

1. **메시지 본문**에 테스트 메시지(예: “이것은 테스트 메시지입니다.”)를 입력합니다.

1. **메시지 전송**을 선택합니다.

Lambda는 업데이트를 위해 대기열을 폴링합니다. 새 메시지가 있는 경우 Lambda는 대기열에서 이 새 이벤트 데이터를 사용하여 함수를 간접 호출합니다. 함수 핸들러가 예외 없이 반환되면 Lambda는 메시지가 성공적으로 처리된 것으로 간주하고 대기열의 새 메시지 읽기를 시작합니다. 메시지를 성공적으로 처리하면 Lambda는 대기열에서 메시지를 자동으로 삭제합니다. 핸들러가 예외를 발생시키면 Lambda는 메시지 배치가 성공적으로 처리되지 않은 것으로 간주하고 Lambda는 동일한 메시지 배치로 함수를 간접 호출합니다.

## CloudWatch Logs 확인
<a name="with-sqs-check-logs"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/sqs_tut_steps7.png)


**함수가 메시지를 처리했는지 확인하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. **ProcessSQSRecord** 함수를 선택합니다.

1. **모니터(Monitor)**를 선택합니다.

1. **CloudWatch 로그 보기**를 선택합니다.

1. CloudWatch 콘솔에서 함수의 **로그 스트림**을 선택합니다.

1. `INFO` 로그를 찾습니다. 여기에 Lambda 함수가 메시지 본문을 기록합니다. Amazon SQS 대기열을 통해 보낸 메시지가 표시됩니다. 예제:

   ```
   2023-09-11T22:49:12.730Z b0c41e9c-0556-5a8b-af83-43e59efeec71 INFO Processed message this is a test message.
   ```

## 리소스 정리
<a name="cleanup"></a>

이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.

**집행 역할 삭제**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. 생성한 실행 역할을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 역할의 이름을 입력하고 **Delete**(삭제)를 선택합니다.

**Lambda 함수를 삭제하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 생성한 함수를 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **confirm**를 입력하고 **Delete**(삭제)를 선택합니다.

**Amazon SQS 대기열을 삭제하려면**

1. AWS Management Console에 로그인한 후 [https://console.aws.amazon.com/sqs/](https://console.aws.amazon.com/sqs/)에서 Amazon SQS 콘솔을 엽니다.

1. 생성한 대기열을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **confirm**을 입력합니다.

1. **삭제**를 선택합니다.

# 자습서: 교차 계정 Amazon SQS 대기열을 이벤트 소스로 사용
<a name="with-sqs-cross-account-example"></a>

이 자습서에서는 다른 AWS 계정의 Amazon Simple Queue Service(Amazon SQS) 대기열에서 메시지를 사용하는 Lambda 함수를 생성합니다. 이 자습서에는 2개의 AWS 계정, 즉 Lambda 함수가 포함된 계정을 나타내는 **계정 A**와 Amazon SQS 대기열이 포함된 계정을 나타내는 **계정 B**가 사용됩니다.

## 사전 조건
<a name="with-sqs-cross-account-prepare"></a>

### AWS Command Line Interface 설치
<a name="install_aws_cli"></a>

아직 AWS Command Line Interface를 설치하지 않은 경우 [AWS CLI의 최신 버전 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)에서 설명하는 단계에 따라 설치하세요.

이 자습서에서는 명령을 실행할 셸 또는 명령줄 터미널이 필요합니다. Linux 및 macOS에서는 선호하는 셸과 패키지 관리자를 사용합니다.

**참고**  
Windows에서는 Lambda와 함께 일반적으로 사용하는 일부 Bash CLI 명령(예:`zip`)은 운영 체제의 기본 제공 터미널에서 지원되지 않습니다. Ubuntu와 Bash의 Windows 통합 버전을 가져오려면 [Linux용 Windows Subsystem을 설치](https://docs.microsoft.com/en-us/windows/wsl/install-win10)합니다.

## 실행 역할 생성(계정 A)
<a name="with-sqs-cross-account-create-execution-role"></a>

**계정 A**에서 필요한 AWS 리소스에 액세스하는 함수 권한을 부여하는 [실행 역할](lambda-intro-execution-role.md)을 만듭니다.

**실행 역할을 만들려면**

1. AWS Identity and Access Management(IAM) 콘솔에서 [역할(Roles) 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. **역할 생성**을 선택합니다.

1. 다음 속성을 사용하여 역할을 만듭니다.
   + **신뢰할 수 있는 엔터티** – **AWS Lambda**
   + **권한** – **AWSLambdaSQSQueueExecutionRole**
   + **역할 이름** – **cross-account-lambda-sqs-role**

**AWSLambdaSQSQueueExecutionRole** 정책은 함수가 Amazon SQS에서 항목을 읽고 Amazon CloudWatch Logs에 로그를 쓰는 데 필요한 권한을 가집니다.

## 함수 생성(계정 A)
<a name="with-sqs-cross-account-create-function"></a>

**계정 A**에서 Amazon SQS 메시지를 처리하는 Lambda 함수를 생성합니다. Lambda 함수와 Amazon SQS 대기열은 같은 AWS 리전에 있어야 합니다.

다음 Node.js 코드 예는 각 메시지를 CloudWatch Logs의 로그에 기록합니다.

**Example index.mjs**  

```
export const handler = async function(event, context) {
  event.Records.forEach(record => {
    const { body } = record;
    console.log(body);
  });
  return {};
}
```

**함수를 만들려면**
**참고**  
다음 단계에 따라 Node.js 함수를 생성합니다. 다른 언어의 경우 단계는 비슷하지만 일부 세부 사항은 다릅니다.

1. 예제 코드를 `index.mjs`라는 파일로 저장합니다.

1. 배포 패키지를 만듭니다.

   ```
   zip function.zip index.mjs
   ```

1. `create-function` AWS Command Line Interface(AWS CLI) 명령을 사용하여 함수를 만듭니다. `arn:aws:iam::111122223333:role/cross-account-lambda-sqs-role`을 이전에 생성한 실행 역할의 ARN으로 변경합니다.

   ```
   aws lambda create-function --function-name CrossAccountSQSExample \
   --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
   --role arn:aws:iam::111122223333:role/cross-account-lambda-sqs-role
   ```

## 함수 테스트(계정 A)
<a name="with-sqs-cross-account-create-test-function"></a>

**계정 A**에서 `invoke` AWS CLI 명령 및 샘플 Amazon SQS 이벤트를 사용하여 Lambda 함수를 수동으로 테스트합니다.

핸들러가 예외 없이 정상적으로 반환되면 Lambda는 메시지가 성공적으로 처리된 것으로 간주하고 대기열의 새 메시지 읽기를 시작합니다. 메시지를 성공적으로 처리하면 Lambda는 대기열에서 메시지를 자동으로 삭제합니다. 핸들러가 예외를 발생시키면 Lambda는 메시지 배치가 성공적으로 처리되지 않은 것으로 간주하고 Lambda는 동일한 메시지 배치로 함수를 간접 호출합니다.

1. 다음 JSON을 `input.txt`라는 파일로 저장합니다.

   ```
   {
       "Records": [
           {
               "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
               "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
               "body": "test",
               "attributes": {
                   "ApproximateReceiveCount": "1",
                   "SentTimestamp": "1545082649183",
                   "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                   "ApproximateFirstReceiveTimestamp": "1545082649185"
               },
               "messageAttributes": {},
               "md5OfBody": "098f6bcd4621d373cade4e832627b4f6",
               "eventSource": "aws:sqs",
               "eventSourceARN": "arn:aws:sqs:us-east-1:111122223333:example-queue",
               "awsRegion": "us-east-1"
           }
       ]
   }
   ```

   앞의 JSON은 Amazon SQS가 `"body"`에 대기열의 실제 메시지를 포함하는 Lambda 함수로 보낼 수 있는 이벤트를 시뮬레이션합니다.

1. 다음 `invoke` AWS CLI 명령을 실행합니다.

   ```
   aws lambda invoke --function-name CrossAccountSQSExample \
   --cli-binary-format raw-in-base64-out \
   --payload file://input.txt outputfile.txt
   ```

   **cli-binary-format** 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 `aws configure set cli-binary-format raw-in-base64-out`을(를) 실행하세요. 자세한 내용은 *AWS Command Line Interface 사용 설명서 버전 2*에서 [AWS CLI 지원 글로벌 명령줄 옵션](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)을 참조하세요.

1. `outputfile.txt` 파일의 출력을 확인합니다.

## Amazon SQS 대기열 생성(계정 B)
<a name="with-sqs-cross-account-configure-sqs"></a>

**계정 B**에서 **계정 A**의 Lambda 함수가 이벤트 소스로 사용할 수 있는 Amazon SQS 대기열을 생성합니다. Lambda 함수와 Amazon SQS 대기열은 같은 AWS 리전에 있어야 합니다.

**대기열 생성**

1. [Amazon SQS 콘솔](https://console.aws.amazon.com/sqs)을 엽니다.

1. **Create queue**(대기열 생성)를 선택합니다.

1. 다음 속성을 사용하여 대기열을 만듭니다.
   + **Type** – **Standard**
   + **Name** – **LambdaCrossAccountQueue**
   + **Configuration** - 기본 설정을 유지합니다.
   + **Access policy** – **Advanced**를 선택합니다. 다음 JSON 정책을 붙여 넣습니다. 다음 값을 교체합니다.
     + `111122223333`: **계정 A**의 AWS 계정 ID
     + `444455556666`: **계정 B**의 AWS 계정 ID

------
#### [ JSON ]

****  

     ```
     {
         "Version":"2012-10-17",		 	 	 
         "Id": "Queue1_Policy_UUID",
         "Statement": [
             {
                 "Sid": "Queue1_AllActions",
                 "Effect": "Allow",
                 "Principal": {
                     "AWS": [
                         "arn:aws:iam::111122223333:role/cross-account-lambda-sqs-role"
                     ]
                 },
                 "Action": "sqs:*",
                 "Resource": "arn:aws:sqs:us-east-1:444455556666:LambdaCrossAccountQueue"
             }
         ]
     }
     ```

------

     이 정책은 이 Amazon SQS 대기열에서 발생하는 메시지를 사용할 수 있는 **계정 A** 권한에 Lambda 실행 역할을 부여합니다.

1. 대기열을 만든 후 대기열의 Amazon 리소스 이름(ARN)을 기록합니다. 다음 단계에서 대기열을 Lambda 함수와 연결할 때 필요합니다.

## 이벤트 소스 구성(계정 A)
<a name="with-sqs-cross-account-event-source"></a>

다음 `create-event-source-mapping` AWS CLI 명령을 실행하여, **계정 A**에서 **계정 B**의 Amazon SQS 대기열 간에 이벤트 소스 매핑과 Lambda 함수를 생성합니다. `arn:aws:sqs:us-east-1:444455556666:LambdaCrossAccountQueue`을 이전 단계에서 생성한 Amazon SQS 대기열의 ARN으로 변경합니다.

```
aws lambda create-event-source-mapping --function-name CrossAccountSQSExample --batch-size 10 \
--event-source-arn arn:aws:sqs:us-east-1:444455556666:LambdaCrossAccountQueue
```

이벤트 소스 매핑 목록을 가져오려면 다음 명령을 실행합니다.

```
aws lambda list-event-source-mappings --function-name CrossAccountSQSExample \
--event-source-arn arn:aws:sqs:us-east-1:444455556666:LambdaCrossAccountQueue
```

## 설정 테스트
<a name="with-sqs-final-integration-test-no-iam"></a>

이제 다음과 같이 설정을 테스트할 수 있습니다.

1. **계정 B**에서 [Amazon SQS 콘솔](https://console.aws.amazon.com/sqs)을 엽니다.

1. 앞서 생성한 **LambdaCrossAccountQueue**를 선택합니다.

1. [**메시지 전송 및 수신(Send and receive messages)**]을 선택합니다.

1. **메시지 본문** 아래에 테스트 메시지를 입력합니다.

1. **메시지 전송**을 선택합니다.

**계정 A**의 Lambda 함수가 이 메시지를 수신해야 합니다. Lambda는 계속해서 업데이트를 위해 대기열을 폴링합니다. 새 메시지가 있는 경우 Lambda는 대기열에서 이 새 이벤트 데이터를 사용하여 함수를 간접 호출합니다. 함수는 Amazon CloudWatch에서 로그를 실행하고 생성합니다. [CloudWatch 콘솔](https://console.aws.amazon.com/cloudwatch)에서 로그를 확인할 수 있습니다.

## 리소스 정리
<a name="cleanup"></a>

이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.

**계정 A**에서 실행 역할 및 Lambda 함수를 정리합니다.

**집행 역할 삭제**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. 생성한 실행 역할을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 역할의 이름을 입력하고 **Delete**(삭제)를 선택합니다.

**Lambda 함수를 삭제하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 생성한 함수를 선택합니다.

1. **작업**, **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **confirm**를 입력하고 **Delete**(삭제)를 선택합니다.

**계정 B**에서 Amazon SQS 대기열을 정리합니다.

**Amazon SQS 대기열을 삭제하려면**

1. AWS Management Console에 로그인한 후 [https://console.aws.amazon.com/sqs/](https://console.aws.amazon.com/sqs/)에서 Amazon SQS 콘솔을 엽니다.

1. 생성한 대기열을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **confirm**을 입력합니다.

1. **삭제**를 선택합니다.

# Step Functions로 Lambda 함수 오케스트레이션
<a name="with-step-functions"></a>

AWS Step Functions는 Lambda 함수를 다른 AWS 서비스와 조정하기 위한 시각적 워크플로 오케스트레이션을 제공합니다. 220개 이상의 AWS 서비스와의 네이티브 통합 및 완전관리형 제로 유지 관리 인프라를 제공하므로 Step Functions는 시각적 워크플로 설계 및 완전관리형 서비스 통합이 필요한 경우에 적합합니다.

워크플로 로직과 비즈니스 로직이 함께 존재하는 Lambda 내에서 표준 프로그래밍 언어를 사용한 오케스트레이션의 경우 [Lambda 지속성 함수](durable-functions.md)를 고려하세요. 이러한 옵션 중에서 선택하는 데 도움이 필요하면 [지속성 함수 또는 Step Functions](durable-step-functions.md)를 참조하세요.

예를 들어, 주문을 처리하려면 주문 세부 정보를 검증하고, 인벤토리 수준을 확인하고, 결제를 처리하고, 인보이스를 생성해야 할 수 있습니다. 각 태스크에 대해 별도의 Lambda 함수를 작성하고 Step Functions를 사용하여 워크플로를 관리합니다. Step Functions는 함수 간의 데이터 흐름을 조정하고 각 단계에서 오류를 처리합니다. 이렇게 분리하면 워크플로가 더 복잡해질수록 시각화, 수정 및 유지 관리가 더 쉬워집니다.

## Lambda에서 Step Functions를 사용해야 하는 경우
<a name="when-to-use-step-functions"></a>

다음 시나리오는 Step Functions가 Lambda 기반 애플리케이션의 오케스트레이션에 특히 적합한 경우의 좋은 예입니다.
+ [순차적 처리](#sequential-processing)
+ [복잡한 오류 처리](#complex-error-handling)
+ [조건부 워크플로 및 사람 승인](#conditional-workflows-human-approvals)
+ [병렬 처리](#parallel-processing)

### 순차적 처리
<a name="sequential-processing"></a>

순차적 처리는 한 태스크가 완료되어야 다음 태스크가 시작되는 것을 말합니다. 예를 들어 주문 처리 시스템에서는 주문 검증이 완료될 때까지 결제 처리를 시작할 수 없으며 인보이스 생성은 결제 확인을 기다려야 합니다. 각 태스크에 대해 별도의 Lambda 함수를 작성하고 Step Functions를 사용하여 시퀀스를 관리하고 함수 간 데이터 흐름을 처리합니다.

#### 안티 패턴 예시
<a name="anti-pattern-sequential"></a>

단일 Lambda 함수가 다음을 통해 전체 주문 처리 워크플로를 관리합니다.
+ 순차적으로 다른 Lambda 함수 간접 호출
+ 각 함수의 응답 구문 분석 및 검증
+ 오류 처리 및 복구 로직 구현
+ 함수 간 데이터 흐름 관리

#### 권장 접근 방식
<a name="recommended-sequential"></a>

두 개의 Lambda 함수를 사용합니다. 하나는 주문을 검증하는 데 사용하고, 다른 하나는 결제를 처리하는 데 사용합니다. Step Functions가 다음을 통해 이러한 함수를 조정합니다.
+ 올바른 순서로 태스크 실행
+ 함수 간 데이터 전달
+ 각 단계에서 오류 처리 구현
+ [Choice](https://docs.aws.amazon.com/step-functions/latest/dg/state-choice.html) 상태를 사용하여 유효한 주문만 결제로 진행되도록 하기

**Example 워크플로 그래프**  

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/sequential_workflow.png)


**참고**  
**코드 우선 대안:** 코드 기반 체크포인팅 및 재시도를 사용한 순차 처리는 [Lambda 지속성 함수 단계](durable-basic-concepts.md)를 참조하세요.

### 복잡한 오류 처리
<a name="complex-error-handling"></a>

Lambda는 [비동기식 간접 호출 및 이벤트 소스 매핑을 위한 재시도 기능](invocation-retries.md)을 제공하는 반면, Step Functions는 복잡한 워크플로를 위한 보다 정교한 오류 처리를 제공합니다. 지수 백오프를 사용하여 [자동 재시도를 구성](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html#error-handling-retrying-after-an-error)하고 다양한 유형의 오류에 대해 서로 다른 재시도 정책을 설정할 수 있습니다. 재시도가 소진되면 `Catch`를 사용하여 오류를 [폴백 상태](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html#error-handling-fallback-states)로 라우팅합니다. 이는 여러 함수와 서비스를 조정하는 워크플로 수준 오류 처리가 필요한 경우에 특히 유용합니다.

상태 시스템의 Lambda 함수 오류 처리에 대한 자세한 내용은 *The AWS Step Functions Workshop*의 [Handling errors](https://catalog.workshops.aws/stepfunctions/handling-errors)를 참조하세요.

#### 안티 패턴 예시
<a name="anti-pattern-error-handling"></a>

단일 Lambda 함수가 다음을 모두 처리합니다.
+ 결제 처리 서비스 직접 호출 시도
+ 결제 서비스를 사용할 수 없는 경우 함수가 기다렸다가 나중에 다시 시도함
+ 대기 시간에 대한 사용자 지정 지수 백오프 구현
+ 모든 시도 실패 후 오류 파악 및 다른 흐름 선택

#### 권장 접근 방식
<a name="recommended-error-handling"></a>

결제 처리에만 초점을 맞춘 단일 Lambda 함수를 사용합니다. Step Functions가 다음을 통해 오류 처리를 관리합니다.
+ [구성 가능한 백오프 기간으로 실패한 태스크 자동 재시도](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html#error-handling-retrying-after-an-error)
+ 오류 유형에 따라 다양한 재시도 정책 적용
+ 적절한 폴백 상태로 다양한 유형의 오류 라우팅
+ 오류 처리 상태 및 기록 유지

**Example 워크플로 그래프**  

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/error_handling_workflow.png)


**참고**  
**코드 우선 대안:** 지속성 함수는 구성 가능한 재시도 전략을 통해 try-catch 오류 처리를 제공합니다. [지속성 함수의 오류 처리](durable-execution-sdk-retries.md)를 참조하세요.

### 조건부 워크플로 및 사람 승인
<a name="conditional-workflows-human-approvals"></a>

Step Functions [Choice 상태](https://docs.aws.amazon.com/step-functions/latest/dg/state-choice.html)를 사용하여 함수 출력에 따라 워크플로를 라우팅하고 [waitForTaskToken 접미사](https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html#connect-wait-token)를 사용하여 사람 결정을 위해 워크플로를 일시 중지합니다. 예를 들어 신용 한도 증가 요청을 처리하려면 Lambda 함수를 사용하여 위험 요소를 평가합니다. 그런 다음 Step Functions를 사용하여 위험도가 높은 요청을 수동 승인으로 라우팅하고 위험도가 낮은 요청을 자동 승인으로 라우팅합니다.

콜백 태스크 토큰 통합 패턴을 사용하는 예시 워크플로를 배포하려면 *The AWS Step Functions Workshop*의 [Callback with Task Token](https://catalog.workshops.aws/stepfunctions/integrating-services/3-callback-token)을 참조하세요.

#### 안티 패턴 예시
<a name="anti-pattern-conditional"></a>

단일 Lambda 함수가 다음을 통해 복잡한 승인 워크플로를 관리합니다.
+ 중첩된 조건부 로직을 구현하여 신용 요청 평가
+ 요청 금액에 따라 다른 승인 함수 간접 호출
+ 여러 승인 경로 및 결정 지점 관리
+ 대기 중인 승인 상태 추적
+ 승인을 위한 제한 시간 및 알림 로직 구현

#### 권장 접근 방식
<a name="recommended-conditional"></a>

3개의 Lambda 함수를 사용합니다. 하나는 각 요청의 위험을 평가하는 데 사용하고, 다른 하나는 위험도가 낮은 요청을 승인하는 데 사용하고, 나머지 하나는 위험도가 높은 요청을 검토를 위해 관리자에게 라우팅하는 데 사용합니다. Step Functions가 다음을 통해 워크플로를 관리합니다.
+ [Choice](https://docs.aws.amazon.com/step-functions/latest/dg/state-choice.html) 상태를 사용하여 금액 및 위험 수준에 따라 요청 라우팅
+ 사람 승인을 기다리는 동안 실행 일시 중지
+ 대기 중인 승인에 대한 제한 시간 관리
+ 각 요청의 현재 상태에 대한 가시성 제공

**Example 워크플로 그래프**  

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/conditional_workflow.png)


**참고**  
**코드 우선 대안:** 지속성 함수는 휴먼 인 더 루프(human-in-the-loop) 워크플로에 대한 콜백을 지원합니다. [지속성 함수의 콜백](durable-execution-sdk.md)을 참조하세요.

### 병렬 처리
<a name="parallel-processing"></a>

Step Functions가 병렬 처리를 처리하는 3가지 방법을 제공합니다.
+ [Parallel 상태](https://docs.aws.amazon.com/step-functions/latest/dg/state-parallel.html)는 워크플로의 여러 브랜치를 동시에 실행합니다. 이미지 메타데이터를 추출하는 동안 썸네일을 생성하는 등 여러 함수를 병렬로 실행해야 할 때 이 상태를 사용합니다.
+ [Inline Map 상태](https://docs.aws.amazon.com/step-functions/latest/dg/state-map-inline.html)는 최대 40회의 동시 반복으로 데이터 배열을 처리합니다. 각 항목에 대해 동일한 작업을 수행해야 하는 중소 규모의 데이터세트에 이 상태를 사용합니다.
+ [Distributed Map 상태](https://docs.aws.amazon.com/step-functions/latest/dg/state-map-distributed.html)는 최대 1만 개의 동시 실행으로 대규모 병렬 처리를 처리하여 JSON 배열과 Amazon Simple Storage Service(Amazon S3) 데이터 소스를 모두 지원합니다. 대규모 데이터세트를 처리하거나 더 높은 동시성이 필요할 때 이 상태를 사용합니다.

#### 안티 패턴 예시
<a name="anti-pattern-parallel"></a>

단일 Lambda 함수가 다음을 통해 병렬 처리 관리를 시도합니다.
+ 동시에 여러 이미지 처리 함수 간접 호출
+ 사용자 지정 병렬 실행 로직 구현
+ 각 병렬 태스크에 대한 제한 시간 및 오류 처리 관리
+ 모든 함수에서 결과 수집 및 집계

#### 권장 접근 방식
<a name="recommended-parallel"></a>

3개의 Lambda 함수를 사용합니다. 하나는 썸네일 이미지를 생성하는 데 사용하고, 다른 하나는 워터마크를 추가하는 데 사용하고, 다른 하나는 메타데이터를 추출하는 데 사용합니다. Step Functions가 다음을 통해 이러한 함수를 관리합니다.
+ [Parallel](https://docs.aws.amazon.com/step-functions/latest/dg/state-parallel.html) 상태를 사용하여 동시에 모든 함수 실행
+ 정렬된 배열로 각 함수의 결과 수집
+ 모든 병렬 실행에서 제한 시간 및 오류 처리 관리
+ 모든 병렬 브랜치가 완료된 경우에만 진행

**Example 워크플로 그래프**  

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/parallel_workflow.png)


**참고**  
**코드 우선 대안:** 지속성 함수는 `parallel()` 및 `map()` 작업을 제공합니다. [병렬 실행](durable-execution-sdk.md)을 참조하세요.

## Lambda에서 Step Functions를 사용하지 않아야 하는 경우
<a name="when-not-to-use"></a>

모든 Lambda 기반 애플리케이션이 Step Functions 사용의 이점을 누릴 수 있는 것은 아닙니다. 애플리케이션 아키텍처를 선택할 때 다음 시나리오를 고려하세요.
+ [단순 애플리케이션](#simple-applications)
+ [복잡한 데이터 처리](#complex-data-processing)
+ [CPU 집약적 워크로드](#cpu-intensive)

### 단순 애플리케이션
<a name="simple-applications"></a>

**참고**  
시각적 디자인 또는 광범위한 서비스 통합이 필요하지 않은 워크플로의 경우 [Lambda 지속성 함수](durable-functions.md)는 Lambda 내에서 워크플로 로직을 코드에 유지하는 더 간단한 대안일 수 있습니다.

복잡한 오케스트레이션이 필요하지 않은 애플리케이션의 경우 Step Functions를 사용하면 불필요한 복잡성이 더해질 수 있습니다. 예를 들어 Amazon SQS 대기열에서 메시지를 처리하거나 Amazon EventBridge 이벤트에 응답하는 경우 Lambda 함수를 직접 간접적으로 호출하도록 이러한 서비스를 구성할 수 있습니다. 마찬가지로 애플리케이션이 간단한 오류 처리 기능을 갖춘 한두 개의 Lambda 함수로만 구성된 경우 직접 Lambda 간접 호출 또는 이벤트 중심 아키텍처를 사용하는 것이 배포 및 유지가 더 간단할 수 있습니다.

### 복잡한 데이터 처리
<a name="complex-data-processing"></a>

Step Functions [Distributed Map](https://docs.aws.amazon.com/step-functions/latest/dg/state-map-distributed.html) 상태를 사용하여 Lambda 함수로 대규모 Amazon S3 데이터세트를 동시에 처리할 수 있습니다. 이는 JSON 또는 CSV 파일과 같은 반정형 데이터 처리를 포함한 많은 대규모 병렬 워크로드에 효과적입니다. 그러나 더 복잡한 데이터 변환 또는 고급 분석의 경우 다음 대안을 고려하세요.
+ **데이터 변환 파이프라인**: 여러 소스의 정형 또는 반정형 데이터를 처리하는 ETL 작업에 AWS Glue를 사용합니다. AWS Glue는 내장 데이터 카탈로그와 스키마 관리 기능이 필요할 때 특히 유용합니다.
+ **데이터 분석:** 페타바이트 규모의 데이터 분석, 특히 Apache Hadoop 에코시스템 도구가 필요하거나 Lambda의 [메모리](configuration-memory.md) 제한을 초과하는 기계 학습 워크로드에 Amazon EMR을 사용합니다.

### CPU 집약적 워크로드
<a name="cpu-intensive"></a>

Step Functions는 CPU 집약적 태스크를 오케스트레이션할 수 있는 반면, Lambda 함수는 제한된 CPU 리소스로 인해 이러한 워크로드에 부적합할 수 있습니다. 워크플로 내 컴퓨팅 집약적 작업의 경우 다음 대안을 고려하세요.
+ **컨테이너 오케스트레이션:** Step Functions를 사용하여 보다 일관되고 확장 가능한 컴퓨팅 리소스를 위해 Amazon Elastic Container Service(Amazon ECS) 태스크를 관리합니다.
+ **배치 처리:** 지속적인 CPU 사용이 필요한 컴퓨팅 집약적 배치 작업을 관리하기 위해 AWS Batch를 Step Functions와 통합합니다.

# Amazon S3 배치 이벤트로 Lambda 함수 간접 호출
<a name="services-s3-batch"></a>

Amazon S3 Batch Operations를 사용하여 대규모 Amazon S3 객체 집합에 대해 Lambda 함수를 간접 호출할 수 있습니다. Amazon S3는 배치 작업의 진행 상황을 추적하고, 알림을 전송하며, 각 작업의 상태를 보여주는 완료 보고서를 저장합니다.

배치 작업을 실행하려면 Amazon S3 [Batch Operations 작업](https://docs.aws.amazon.com/AmazonS3/latest/dev/batch-ops-operations.html)을 생성합니다. 작업을 생성할 때 매니페스트(객체 목록)를 제공하고 해당 객체에 대해 수행할 작업을 구성합니다.

배치 작업이 시작되면 Amazon S3에서 매니페스트의 각 객체에 대해 Lambda 함수를 [동기적으로](invocation-sync.md) 간접 호출합니다. 이벤트 파라미터에는 버킷과 객체의 이름이 포함됩니다.

다음 예제에서는 Amazon S3가 **amzn-s3-demo-bucket** 버킷에 있는 **customerImage1.jpg**라는 객체에 대해 Lambda 함수에 전송하는 이벤트를 보여줍니다.

**Example Amazon S3 배치 요청 이벤트**  

```
{
"invocationSchemaVersion": "1.0",
    "invocationId": "YXNkbGZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZza2RmaAo",
    "job": {
        "id": "f3cc4f60-61f6-4a2b-8a21-d07600c373ce"
    },
    "tasks": [
        {
            "taskId": "dGFza2lkZ29lc2hlcmUK",
            "s3Key": "customerImage1.jpg",
            "s3VersionId": "1",
            "s3BucketArn": "arn:aws:s3:::amzn-s3-demo-bucket"
        }
    ]  
}
```

Lambda 함수는 다음 예제에 나온 것과 같은 필드를 포함한 JSON 객체를 반환해야 합니다. 이벤트 파라미터에서 `invocationId` 및 `taskId`를 복사할 수 있습니다. `resultString`의 문자열을 반환할 수 있습니다. Amazon S3는 완료 보고서의 `resultString` 값을 저장합니다.

**Example Amazon S3 배치 요청 응답**  

```
{
  "invocationSchemaVersion": "1.0",
  "treatMissingKeysAs" : "PermanentFailure",
  "invocationId" : "YXNkbGZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZza2RmaAo",
  "results": [
    {
      "taskId": "dGFza2lkZ29lc2hlcmUK",
      "resultCode": "Succeeded",
      "resultString": "[\"Alice\", \"Bob\"]"
    }
  ]
}
```

## Amazon S3 Batch Operations에서 Lambda 함수 호출
<a name="invoking"></a>

정규화되거나 정규화되지 않은 함수 ARN을 사용하여 Lambda 함수를 간접 호출할 수 있습니다. 전체 배치 작업에 동일한 함수 버전을 사용하려면 작업을 생성할 때 `FunctionARN` 파라미터에 특정 함수 버전을 구성합니다. 별칭 또는 \$1LATEST 한정자를 구성하는 경우 작업 실행 중에 별칭 또는 \$1LATEST가 업데이트되면 배치 작업이 함수의 새 버전을 즉시 호출하기 시작합니다.

기존 Amazon S3 이벤트 기반 함수는 배치 작업에 재사용할 수 없습니다. 이는 Amazon S3 Batch Operations가 Lambda 함수에 다른 이벤트 파라미터를 전달하고 특정 JSON 구조의 반환 메시지를 예상하기 때문입니다.

Amazon S3 Batch Job에 대해 생성하는 [리소스 기반 정책](access-control-resource-based.md)에서 Lambda 함수를 간접 호출하는 작업에 대한 권한을 설정해야 합니다.

함수의 [실행 역할](https://docs.aws.amazon.com/AmazonS3/latest/userguide/batch-ops-iam-role-policies.html)에서 Amazon S3가 함수를 실행할 때 역할을 수임하기 위한 신뢰 정책을 설정합니다.

함수가 AWS SDK를 사용하여 Amazon S3 리소스를 관리하는 경우 실행 역할에 Amazon S3 권한을 추가해야 합니다.

작업이 실행될 때 Amazon S3는 여러 함수 인스턴스를 시작하여 Amazon S3 객체를 함수의 [동시성 한도](lambda-concurrency.md)까지 병렬로 처리합니다. Amazon S3는 소규모 작업에 대한 과도한 비용을 막기 위해 인스턴스의 초기 증가량을 제한합니다.

Lambda 함수가 `TemporaryFailure` 응답 코드를 반환하면 Amazon S3는 작업을 다시 시도합니다.

Amazon S3 Batch Operations에 대한 자세한 내용은 *Amazon S3 개발자 안내서*의 [배치 작업 수행](https://docs.aws.amazon.com/AmazonS3/latest/dev/batch-ops.html)을 참조하세요.

Amazon S3 Batch Operations에서 Lambda 함수를 사용하는 방법에 대한 예는 *Amazon S3 개발자 안내서*의 [Amazon S3 Batch Operations에서 Lambda 함수 호출](https://docs.aws.amazon.com/AmazonS3/latest/dev/batch-ops-invoke-lambda.html)을 참조하세요.

# Amazon SNS 알림을 사용하여 Lambda 함수 간접 호출
<a name="with-sns"></a>

Lambda 함수를 사용하여 Amazon Simple Notification Service(Amazon SNS) 알림을 처리할 수 있습니다. Amazon SNS는 Lambda 함수를 주제에 전송된 메시지에 대한 대상으로 지원합니다. 동일한 계정 또는 다른 AWS 계정의 주제에 함수를 등록할 수 있습니다. 자세한 내용은 [자습서: Amazon Simple Notification Service에서 AWS Lambda 사용](with-sns-example.md) 섹션을 참조하세요.

Lambda는 표준 SNS 주제에 대해서만 SNS 트리거를 지원합니다. FIFO 주제는 지원되지 않습니다.

Lambda는 메시지를 대기열에 넣고 재시도를 처리하여 SNS 메시지를 비동기식으로 처리합니다. Amazon SNS가 Lambda에 도달할 수 없거나 메시지가 거부되는 경우, Amazon SNS는 몇 시간 동안 간격을 늘리면서 재시도합니다. 자세한 내용은 Amazon SNS FAQ에서 [안정성](https://aws.amazon.com/sns/faqs/#Reliability)을 참조하세요.

**주의**  
Lambda 비동기식 간접 호출은 각 이벤트를 한 번 이상 처리하므로 레코드가 중복될 수 있습니다. 중복 이벤트와 관련된 잠재적 문제를 방지하려면 함수 코드를 멱등성으로 만드는 것이 좋습니다. 자세한 내용은 AWS 지식 센터의 [함수를 멱등성 Lambda 함수로 만들려면 어떻게 해야 하나요?](https://repost.aws/knowledge-center/lambda-function-idempotent)를 참조하세요.

## Powertools for AWS Lambda 멱등성 유틸리티
<a name="services-sns-powertools-idempotency"></a>

Powertools for AWS Lambda의 멱등성 유틸리티는 Lambda 함수가 멱등성을 가지게 만듭니다. Python, TypeScript, Java 및 .NET에 사용할 수 있습니다. 자세한 내용은 *Powertools for AWS Lambda(Python) 설명서*의 [멱등성 유틸리티](https://docs.powertools.aws.dev/lambda/python/latest/utilities/idempotency/), *Powertools for AWS Lambda(TypeScript) 설명서*의 [멱등성 유틸리티](https://docs.aws.amazon.com/powertools/typescript/2.1.1/utilities/idempotency/), *Powertools for AWS Lambda(Java) 설명서*의 [멱등성 유틸리티](https://docs.powertools.aws.dev/lambda/java/latest/utilities/idempotency/), *Powertools for AWS Lambda(.NET) 설명서*의 [멱등성 유틸리티](https://docs.powertools.aws.dev/lambda/dotnet/utilities/idempotency/)를 참조하세요.

**Topics**
+ [

## Powertools for AWS Lambda 멱등성 유틸리티
](#services-sns-powertools-idempotency)
+ [

## 콘솔을 사용하여 Lambda 함수에 대한 Amazon SNS 주제 트리거 추가
](#sns-trigger-console)
+ [

## Lambda 함수에 대한 Amazon SNS 주제 트리거 수동 추가
](#sns-trigger-manual)
+ [

## 샘플 SNS 이벤트 셰이프
](#sns-sample-event)
+ [

# 자습서: Amazon Simple Notification Service에서 AWS Lambda 사용
](with-sns-example.md)

## 콘솔을 사용하여 Lambda 함수에 대한 Amazon SNS 주제 트리거 추가
<a name="sns-trigger-console"></a>

Lambda 함수에 대한 트리거로 SNS 주제를 추가하는 가장 쉬운 방법은 Lambda 콘솔을 사용하는 것입니다. 콘솔을 통해 트리거를 추가하면 Lambda가 SNS 주제에서 이벤트 수신을 시작하는 데 필요한 권한과 구독을 자동으로 설정합니다.

**Lambda 함수에 대한 트리거로 SNS 주제를 추가하려면 다음을 수행하세요(콘솔).**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 트리거를 추가할 함수의 이름을 선택합니다.

1. **구성**을 선택하고 **트리거**를 선택합니다.

1. **트리거 추가**를 선택합니다.

1. **트리거 구성** 아래의 드롭다운 메뉴에서 **SNS**를 선택합니다.

1. **SNS 주제**로 구독할 SNS 주제를 선택합니다.

## Lambda 함수에 대한 Amazon SNS 주제 트리거 수동 추가
<a name="sns-trigger-manual"></a>

Lambda 함수에 대한 SNS 트리거를 수동으로 설정하려면 다음 단계를 완료해야 합니다.
+ SNS가 함수를 간접적으로 간접 호출할 수 있도록 함수에 대한 리소스 기반 정책을 정의합니다.
+ Amazon SNS 주제에 대한 Lambda 함수를 구독합니다.
**참고**  
SNS 주제와 Lambda 함수가 서로 AWS 다른 계정에 있는 경우 SNS 주제에 대한 크로스 계정 구독을 허용하려면 추가 권한도 부여해야 합니다. 자세한 내용은 [Amazon SNS 구독을 위한 크로스 계정 권한 부여](with-sns-example.md#with-sns-subscription-grant-permission)를 참조하세요.

AWS Command Line Interface(AWS CLI)를 사용하여 이 두 단계를 모두 완료할 수 있습니다. 먼저, SNS 간접 호출을 허용하는 Lambda 함수에 대한 리소스 기반 정책을 정의하려면 다음 AWS CLI 명령을 사용하세요. `--function-name` 값을 Lambda 함수 이름으로 바꾸고 `--source-arn` 값을 SNS 주제 ARN으로 바꿔야 합니다.

```
aws lambda add-permission --function-name example-function \
    --source-arn arn:aws:sns:us-east-1:123456789012:sns-topic-for-lambda \
    --statement-id function-with-sns --action "lambda:InvokeFunction" \
    --principal sns.amazonaws.com
```

SNS 주제의 함수를 구독하려면 다음 AWS CLI 명령을 사용하세요. `--topic-arn` 값을 SNS 주제 ARN으로 바꾸고, `--notification-endpoint` 값을 Lambda 함수 ARN으로 바꿉니다.

```
aws sns subscribe --protocol lambda \
    --region us-east-1 \
    --topic-arn arn:aws:sns:us-east-1:123456789012:sns-topic-for-lambda \
    --notification-endpoint arn:aws:lambda:us-east-1:123456789012:function:example-function
```

## 샘플 SNS 이벤트 셰이프
<a name="sns-sample-event"></a>

Amazon SNS는 메시지 및 메타데이터를 포함하는 이벤트와 [비동기적으로](invocation-async.md) 함수를 간접 호출합니다.

**Example Amazon SNS 메시지 이벤트**  

```
{
  "Records": [
    {
      "EventVersion": "1.0",
      "EventSubscriptionArn": "arn:aws:sns:us-east-1:123456789012:sns-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
      "EventSource": "aws:sns",
      "Sns": {
        "SignatureVersion": "1",
        "Timestamp": "2019-01-02T12:45:07.000Z",
        "Signature": "tcc6faL2yUC6dgZdmrwh1Y4cGa/ebXEkAi6RibDsvpi+tE/1+82j...65r==",
        "SigningCertURL": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-ac565b8b1a6c5d002d285f9598aa1d9b.pem",
        "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
        "Message": "Hello from SNS!",
        "MessageAttributes": {
          "Test": {
            "Type": "String",
            "Value": "TestString"
          },
          "TestBinary": {
            "Type": "Binary",
            "Value": "TestBinary"
          }
        },
        "Type": "Notification",
        "UnsubscribeUrl": "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&amp;SubscriptionArn=arn:aws:sns:us-east-1:123456789012:test-lambda:21be56ed-a058-49f5-8c98-aedd2564c486",
        "TopicArn":"arn:aws:sns:us-east-1:123456789012:sns-lambda",
        "Subject": "TestInvoke"
      }
    }
  ]
}
```

# 자습서: Amazon Simple Notification Service에서 AWS Lambda 사용
<a name="with-sns-example"></a>

이 자습서에서는 하나의 AWS 계정에서 Lambda 함수를 사용하여 별도의 AWS 계정에서 Amazon Simple Notification Service(SNS) 주제를 구독합니다. Amazon SNS 주제에 메시지를 게시하면 Lambda 함수가 메시지 내용을 읽어 Amazon CloudWatch Logs에 출력합니다. 이 자습서를 완료하려면 AWS Command Line Interface(AWS CLI)를 사용합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-sns-tutorial/sns_tut_resources.png)


이 자습서를 완료하려면 다음 단계를 수행합니다.
+ **계정 A**에서 Amazon SNS 주제를 생성합니다.
+ **계정 B**에서 주제에서 메시지를 읽을 Lambda 함수를 생성합니다.
+ **계정 B**에서 주제에 대한 구독을 생성합니다.
+ **계정 A**의 Amazon SNS 주제에 메시지를 게시하고 **계정 B**의 Lambda 함수가 메시지를 CloudWatch Logs로 출력하는지 확인합니다.

이 단계를 완료하면 Lambda 함수를 간접적으로 간접 호출하도록 Amazon SNS 주제를 구성하는 방법을 배우게 됩니다. 또한 다른 AWS 계정의 리소스가 Lambda를 간접적으로 간접 호출할 수 있는 권한을 부여하는 AWS Identity and Access Management(IAM) 정책을 생성하는 방법도 배웁니다.

이 자습서에서는 2개의 개별 AWS 계정을 사용합니다. AWS CLI 명령은 각각 다른 AWS 계정에서 사용하도록 구성된 `accountA`와 `accountB`라는 2개의 명명된 프로파일을 사용하여 이를 설명합니다. 다른 프로파일을 사용하도록 AWS CLI를 구성하는 방법에 대한 자세한 내용은 **AWS Command Line Interface - 버전 2 사용 설명서의 [구성 및 자격 증명 파일 설정](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)을 참조하세요. 두 프로파일에 대해 동일한 기본 AWS 리전을 구성해야 합니다.

두 AWS 계정에 대해 생성하는 AWS CLI 프로파일이 서로 다른 이름을 사용하거나 기본 프로파일과 하나의 명명된 프로파일을 사용하는 경우 필요에 따라 다음 단계에서 AWS CLI 명령을 수정합니다.

## 사전 조건
<a name="with-sns-prereqs"></a>

### AWS Command Line Interface 설치
<a name="install_aws_cli"></a>

아직 AWS Command Line Interface를 설치하지 않은 경우 [AWS CLI의 최신 버전 설치 또는 업데이트](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)에서 설명하는 단계에 따라 설치하세요.

이 자습서에서는 명령을 실행할 셸 또는 명령줄 터미널이 필요합니다. Linux 및 macOS에서는 선호하는 셸과 패키지 관리자를 사용합니다.

**참고**  
Windows에서는 Lambda와 함께 일반적으로 사용하는 일부 Bash CLI 명령(예:`zip`)은 운영 체제의 기본 제공 터미널에서 지원되지 않습니다. Ubuntu와 Bash의 Windows 통합 버전을 가져오려면 [Linux용 Windows Subsystem을 설치](https://docs.microsoft.com/en-us/windows/wsl/install-win10)합니다.

## Amazon SNS 주제 생성(계정 A)
<a name="with-sns-create-topic"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_1.png)


**주제를 생성하려면**
+ **계정 A**에서 다음 AWS CLI 명령을 사용하여 Amazon SNS 표준 주제를 생성합니다.

  ```
  aws sns create-topic --name sns-topic-for-lambda --profile accountA
  ```

  다음과 유사한 출력 화면이 표시되어야 합니다.

  ```
  {
      "TopicArn": "arn:aws:sns:us-west-2:123456789012:sns-topic-for-lambda"
  }
  ```

  주제의 Amazon 리소스 이름(ARN)을 기록해 둡니다. 이는 나중에 자습서에서 주제를 구독하기 위해 Lambda 함수에 권한을 추가할 때 필요합니다.

## 함수 실행 역할 생성(계정 B)
<a name="with-sns-example-create-iam-role"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_2.png)


실행 역할은 AWS 서비스 및 리소스에 액세스할 수 있는 권한을 Lambda 함수에 부여하는 IAM 역할입니다. **계정 B**에서 함수를 생성하기 전에 CloudWatch Logs에 로그를 쓸 수 있는 기본 권한을 함수에 부여하는 역할을 생성합니다. Amazon SNS 주제에서 읽을 수 있는 권한은 이후 단계에서 추가하겠습니다.

**실행 역할을 만들려면**

1. **계정 B**의 IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. **역할 생성**을 선택합니다.

1. **신뢰할 수 있는 엔터티 유형**에서 **AWS 서비스**를 선택합니다.

1. **사용 사례**에서 **Lambda**를 선택합니다.

1. **다음**을 선택합니다.

1. 다음을 수행하여 역할에 기본 권한 정책을 추가합니다.

   1. **권한 정책** 검색 상자에 **AWSLambdaBasicExecutionRole**을 입력합니다.

   1. **다음**을 선택합니다.

1. 다음을 수행하여 역할 생성을 마무리합니다.

   1. **역할 세부 정보**의 **역할 이름**에 **lambda-sns-role**을 입력합니다.

   1. **역할 생성**을 선택합니다.

## Lambda 함수 생성(계정 B)
<a name="with-sns-example-create-test-function"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_3.png)


Amazon SNS 메시지를 처리하는 Lambda 함수를 생성합니다. 함수 코드는 각 레코드의 메시지 콘텐츠를 Amazon CloudWatch Logs에 로그합니다.

이 자습서에서는 Node.js 24 런타임을 사용하지만 다른 런타임 언어의 예제 코드도 제공했습니다. 다음 상자에서 탭을 선택하여 관심 있는 런타임에 대한 코드를 볼 수 있습니다. 이 단계에서 사용할 JavaScript 코드는 **JavaScript** 탭에 표시된 첫 번째 예제입니다.

------
#### [ .NET ]

**SDK for .NET**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
.NET을 사용하여 Lambda로 SNS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
using Amazon.Lambda.Core;
using Amazon.Lambda.SNSEvents;


// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace SnsIntegration;

public class Function
{
    public async Task FunctionHandler(SNSEvent evnt, ILambdaContext context)
    {
        foreach (var record in evnt.Records)
        {
            await ProcessRecordAsync(record, context);
        }
        context.Logger.LogInformation("done");
    }

    private async Task ProcessRecordAsync(SNSEvent.SNSRecord record, ILambdaContext context)
    {
        try
        {
            context.Logger.LogInformation($"Processed record {record.Sns.Message}");

            // TODO: Do interesting work based on the new message
            await Task.CompletedTask;
        }
        catch (Exception e)
        {
            //You can use Dead Letter Queue to handle failures. By configuring a Lambda DLQ.
            context.Logger.LogError($"An error occurred");
            throw;
        }
    }
}
```

------
#### [ Go ]

**SDK for Go V2**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Go를 사용하여 Lambda로 SNS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main

import (
	"context"
	"fmt"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

func handler(ctx context.Context, snsEvent events.SNSEvent) {
	for _, record := range snsEvent.Records {
		processMessage(record)
	}
	fmt.Println("done")
}

func processMessage(record events.SNSEventRecord) {
	message := record.SNS.Message
	fmt.Printf("Processed message: %s\n", message)
	// TODO: Process your record here
}

func main() {
	lambda.Start(handler)
}
```

------
#### [ Java ]

**SDK for Java 2.x**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Java를 사용하여 Lambda로 SNS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package example;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SNSEvent;
import com.amazonaws.services.lambda.runtime.events.SNSEvent.SNSRecord;


import java.util.Iterator;
import java.util.List;

public class SNSEventHandler implements RequestHandler<SNSEvent, Boolean> {
    LambdaLogger logger;

    @Override
    public Boolean handleRequest(SNSEvent event, Context context) {
        logger = context.getLogger();
        List<SNSRecord> records = event.getRecords();
        if (!records.isEmpty()) {
            Iterator<SNSRecord> recordsIter = records.iterator();
            while (recordsIter.hasNext()) {
                processRecord(recordsIter.next());
            }
        }
        return Boolean.TRUE;
    }

    public void processRecord(SNSRecord record) {
        try {
            String message = record.getSNS().getMessage();
            logger.log("message: " + message);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
```

------
#### [ JavaScript ]

**SDK for JavaScript (v3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/blob/main/integration-sns-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
JavaScript를 사용하여 Lambda로 SNS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
exports.handler = async (event, context) => {
  for (const record of event.Records) {
    await processMessageAsync(record);
  }
  console.info("done");
};

async function processMessageAsync(record) {
  try {
    const message = JSON.stringify(record.Sns.Message);
    console.log(`Processed message ${message}`);
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}
```
TypeScript를 사용하여 Lambda로 SNS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { SNSEvent, Context, SNSHandler, SNSEventRecord } from "aws-lambda";

export const functionHandler: SNSHandler = async (
  event: SNSEvent,
  context: Context
): Promise<void> => {
  for (const record of event.Records) {
    await processMessageAsync(record);
  }
  console.info("done");
};

async function processMessageAsync(record: SNSEventRecord): Promise<any> {
  try {
    const message: string = JSON.stringify(record.Sns.Message);
    console.log(`Processed message ${message}`);
    await Promise.resolve(1); //Placeholder for actual async work
  } catch (err) {
    console.error("An error occurred");
    throw err;
  }
}
```

------
#### [ PHP ]

**SDK for PHP**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
PHP를 사용하여 Lambda로 SNS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
<?php

/* 
Since native PHP support for AWS Lambda is not available, we are utilizing Bref's PHP functions runtime for AWS Lambda.
For more information on Bref's PHP runtime for Lambda, refer to: https://bref.sh/docs/runtimes/function

Another approach would be to create a custom runtime. 
A practical example can be found here: https://aws.amazon.com/blogs/apn/aws-lambda-custom-runtime-for-php-a-practical-example/
*/

// Additional composer packages may be required when using Bref or any other PHP functions runtime.
// require __DIR__ . '/vendor/autoload.php';

use Bref\Context\Context;
use Bref\Event\Sns\SnsEvent;
use Bref\Event\Sns\SnsHandler;

class Handler extends SnsHandler
{
    public function handleSns(SnsEvent $event, Context $context): void
    {
        foreach ($event->getRecords() as $record) {
            $message = $record->getMessage();

            // TODO: Implement your custom processing logic here
            // Any exception thrown will be logged and the invocation will be marked as failed

            echo "Processed Message: $message" . PHP_EOL;
        }
    }
}

return new Handler();
```

------
#### [ Python ]

**SDK for Python(Boto3)**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Python을 사용하여 Lambda로 SNS 이벤트를 사용합니다.  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event, context):
    for record in event['Records']:
        process_message(record)
    print("done")

def process_message(record):
    try:
        message = record['Sns']['Message']
        print(f"Processed message {message}")
        # TODO; Process your record here
        
    except Exception as e:
        print("An error occurred")
        raise e
```

------
#### [ Ruby ]

**SDK for Ruby**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Ruby를 사용하여 Lambda로 SNS 이벤트를 사용합니다.  

```
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
def lambda_handler(event:, context:)
  event['Records'].map { |record| process_message(record) }
end

def process_message(record)
  message = record['Sns']['Message']
  puts("Processing message: #{message}")
rescue StandardError => e
  puts("Error processing message: #{e}")
  raise
end
```

------
#### [ Rust ]

**SDK for Rust**  
 GitHub에 더 많은 내용이 있습니다. [서버리스 예제](https://github.com/aws-samples/serverless-snippets/tree/main/integration-sns-to-lambda) 리포지토리에서 전체 예제를 찾아보고 설정 및 실행 방법을 알아봅니다.
Rust를 사용하여 Lambda로 SNS 이벤트를 사용합니다.  

```
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use aws_lambda_events::event::sns::SnsEvent;
use aws_lambda_events::sns::SnsRecord;
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use tracing::info;

// Built with the following dependencies:
//  aws_lambda_events = { version = "0.10.0", default-features = false, features = ["sns"] }
//  lambda_runtime = "0.8.1"
//  tokio = { version = "1", features = ["macros"] }
//  tracing = { version = "0.1", features = ["log"] }
//  tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }

async fn function_handler(event: LambdaEvent<SnsEvent>) -> Result<(), Error> {
    for event in event.payload.records {
        process_record(&event)?;
    }
    
    Ok(())
}

fn process_record(record: &SnsRecord) -> Result<(), Error> {
    info!("Processing SNS Message: {}", record.sns.message);

    // Implement your record handling code here.

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        .with_target(false)
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

------

**함수를 만들려면**

1. 프로젝트에 대한 디렉터리를 생성하고 해당 디렉터리로 전환합니다.

   ```
   mkdir sns-tutorial
   cd sns-tutorial
   ```

1. 샘플 JavaScript 코드를 새로운 `index.js` 파일에 복사합니다.

1. 다음 `zip` 명령을 사용하여 배포 패키지를 생성합니다.

   ```
   zip function.zip index.js
   ```

1. 다음 AWS CLI 명령을 실행하여 **계정 B**에서 Lambda 함수를 생성합니다.

   ```
   aws lambda create-function --function-name Function-With-SNS \
       --zip-file fileb://function.zip --handler index.handler --runtime nodejs24.x \
       --role arn:aws:iam::<AccountB_ID>:role/lambda-sns-role  \
       --timeout 60 --profile accountB
   ```

   다음과 유사한 출력 화면이 표시되어야 합니다.

   ```
   {
       "FunctionName": "Function-With-SNS",
       "FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:Function-With-SNS",
       "Runtime": "nodejs24.x",
       "Role": "arn:aws:iam::123456789012:role/lambda_basic_role",
       "Handler": "index.handler",
       ...
       "RuntimeVersionConfig": {
           "RuntimeVersionArn": "arn:aws:lambda:us-west-2::runtime:7d5f06b69c951da8a48b926ce280a9daf2e8bb1a74fc4a2672580c787d608206"
       }
   }
   ```

1. 함수의 Amazon 리소스 이름(ARN)을 기록합니다. 이는 나중에 자습서에서 Amazon SNS에 함수를 간접적으로 간접 호출할 권한을 추가할 때 필요합니다.

## 함수에 권한 추가(계정 B)
<a name="with-sns-create-function-permissions"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_4.png)


Amazon SNS가 함수를 간접적으로 간접 호출하려면 [리소스 기반 정책](access-control-resource-based.md)의 문에서 권한을 부여해야 합니다. AWS CLI `add-permission` 명령을 사용하여 이 문을 추가합니다.

**Amazon SNS에 함수를 간접적으로 간접 호출할 수 있는 권한 부여**
+ **계정 B**에서 이전에 기록한 Amazon SNS 주제의 ARN을 사용하여 다음 AWS CLI 명령을 실행합니다.

  ```
  aws lambda add-permission --function-name Function-With-SNS \
      --source-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \
      --statement-id function-with-sns --action "lambda:InvokeFunction" \
      --principal sns.amazonaws.com --profile accountB
  ```

  다음과 유사한 출력 화면이 표시되어야 합니다.

  ```
  {
      "Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":
        \"arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda\"}},
        \"Action\":[\"lambda:InvokeFunction\"],
        \"Resource\":\"arn:aws:lambda:us-east-1:<AccountB_ID>:function:Function-With-SNS\",
        \"Effect\":\"Allow\",\"Principal\":{\"Service\":\"sns.amazonaws.com\"},
        \"Sid\":\"function-with-sns\"}"
  }
  ```

**참고**  
Amazon SNS 주제가 있는 계정이 [옵트인 AWS 리전](https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-regions.html)에서 호스팅되는 경우 보안 주체에서 리전을 지정해야 합니다. 예를 들어, 아시아 태평양(홍콩) 리전에서 Amazon SNS 주제를 사용하는 경우 보안 주체에 대해 `sns.amazonaws.com` 대신 `sns.ap-east-1.amazonaws.com`을 지정해야 합니다.

## Amazon SNS 구독을 위한 크로스 계정 권한 부여(계정 A)
<a name="with-sns-subscription-grant-permission"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_5.png)


**계정 B**의 Lambda 함수가 **계정 A**에서 생성한 Amazon SNS 주제를 구독할 수 있도록 **계정 B**에 주제를 구독할 수 있는 권한을 부여해야 합니다. AWS CLI `add-permission` 명령을 사용하여 이 권한을 부여합니다.

**계정 B가 주제를 구독할 수 있는 권한 부여**
+ **계정 A**에서 다음 AWS CLI 명령을 실행합니다. 이전에 기록한 Amazon SNS 주제의 ARN을 사용합니다.

  ```
  aws sns add-permission --label lambda-access --aws-account-id <AccountB_ID> \
      --topic-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \  
      --action-name Subscribe ListSubscriptionsByTopic --profile accountA
  ```

## 구독 생성(계정 B)
<a name="with-sns-create-subscription"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_6.png)


이제 **계정 B**에서 **계정 A**의 자습서 시작 부분에서 생성한 Amazon SNS 주제에 대한 Lambda 함수를 구독합니다. 이 주제(`sns-topic-for-lambda`)로 메시지가 전송되면 Amazon SNS는 **계정 B**에서 Lambda 함수 `Function-With-SNS`를 간접 호출합니다.

**구독 생성**
+ **계정 B**에서 다음 AWS CLI 명령을 실행합니다. 주제를 생성한 기본 리전과 주제 및 Lambda 함수의 ARN을 사용합니다.

  ```
  aws sns subscribe --protocol lambda \
      --region us-east-1 \
      --topic-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \
      --notification-endpoint arn:aws:lambda:us-east-1:<AccountB_ID>:function:Function-With-SNS \
      --profile accountB
  ```

  다음과 유사한 출력 화면이 표시되어야 합니다.

  ```
  {
      "SubscriptionArn": "arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda:5d906xxxx-7c8x-45dx-a9dx-0484e31c98xx"
  }
  ```

## 주제에 메시지 게시(계정 A 및 계정 B)
<a name="with-sns-publish-message"></a>

![\[\]](http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/images/services-sns-tutorial/sns_tut_steps_7.png)


이제 **계정 B**의 Lambda 함수가 **계정 A**의 Amazon SNS 주제를 구독하므로 주제에 메시지를 게시하여 설정을 테스트할 차례입니다. Amazon SNS가 Lambda 함수를 간접적으로 간접 호출했는지 확인하려면 CloudWatch Logs를 사용하여 함수의 출력을 봅니다.

**주제에 메시지 게시 및 함수의 출력 보기**

1. 텍스트 파일에 `Hello World`를 입력하고 `message.txt`로 저장합니다.

1. 텍스트 파일을 저장한 디렉터리와 동일한 디렉터리에서 **계정 A**의 다음 AWS CLI 명령을 실행합니다. 사용자 주제의 ARN을 사용합니다.

   ```
   aws sns publish --message file://message.txt --subject Test \
       --topic-arn arn:aws:sns:us-east-1:<AccountA_ID>:sns-topic-for-lambda \
       --profile accountA
   ```

   그러면 Amazon SNS가 메시지를 수락했음을 나타내는 고유 식별자가 포함된 메시지 ID가 반환됩니다. Amazon SNS는 주제의 구독자에게 메시지를 전달하려고 시도합니다. Amazon SNS가 Lambda 함수를 간접적으로 간접 호출했는지 확인하려면 CloudWatch Logs를 사용하여 함수의 출력을 봅니다.

1. **계정 B**에서 Amazon CloudWatch 콘솔의 [로그 그룹](https://console.aws.amazon.com/cloudwatch/home#logsV2:log-groups) 페이지를 엽니다.

1. 함수에 대한 로그 그룹(`/aws/lambda/Function-With-SNS`)을 선택합니다.

1. 최신 로그 스트림을 선택합니다.

1. 함수가 간접적으로 제대로 간접 호출되면 주제에 게시한 메시지의 내용을 보여주는 다음과 유사한 출력이 표시됩니다.

   ```
   2023-07-31T21:42:51.250Z c1cba6b8-ade9-4380-aa32-d1a225da0e48 INFO Processed message Hello World
   2023-07-31T21:42:51.250Z c1cba6b8-ade9-4380-aa32-d1a225da0e48 INFO done
   ```

## 리소스 정리
<a name="cleanup"></a>

이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.

**계정 A**에서 Amazon SNS 주제를 정리합니다.

**Amazon SNS 주제를 삭제하려면**

1. Amazon SNS 콘솔의 [주제 페이지](https://console.aws.amazon.com//sns/home#topics:)를 엽니다.

1. 생성한 주제를 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 **delete me**을 입력합니다.

1. **삭제**를 선택합니다.

**계정 B**에서 실행 역할, Lambda 함수 및 Amazon SNS 구독을 정리합니다.

**집행 역할 삭제**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. 생성한 실행 역할을 선택합니다.

1. **삭제**를 선택합니다.

1. 텍스트 입력 필드에 역할의 이름을 입력하고 **Delete**(삭제)를 선택합니다.

**Lambda 함수를 삭제하려면**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 생성한 함수를 선택합니다.

1. **작업**(Actions), **삭제**(Delete)를 선택합니다.

1. 텍스트 입력 필드에 **confirm**를 입력하고 **Delete**(삭제)를 선택합니다.

**Amazon SNS 구독을 삭제하려면**

1. Amazon SNS 콘솔의 [구독 페이지](https://console.aws.amazon.com//sns/home#subscriptions:)를 엽니다.

1. 생성한 구독을 선택합니다.

1. **삭제(Delete)**와 **삭제(Delete)**를 차례로 선택합니다.