Amazon SAA-C03: サーバーレスとイベント駆動型アーキテクチャ / API統合 — 学習ガイド
こちらの一部です: AWS SAA-C03 — 完全学習ガイド. 検証済みの解答で練習: Amazon試験ハブ, または時間制限付き模擬試験に挑戦: ExamRoll.io.
AWS Lambda: 実行モデル、ランタイムライフサイクル、そしてコールドスタート
Lambdaは、2フェーズのライフサイクルを持つ、分離されたFirecrackerマイクロVMでコードを実行します。INITフェーズでは、コンテナのプロビジョニング、ランタイムのブートストラップ、デプロイパッケージのダウンロードと展開、そしてモジュールレベルの初期化(SDKクライアントの構築、KMSで復号されたシークレットの読み込み、データベース接続プールのセットアップ、JVMのクラスローディングとJITウォームアップなど)が実行されます。INVOKEフェーズでは、ハンドラが実行されます。コールドスタートではINITの全コストが発生しますが、ウォーム呼び出しでは環境が再利用されるため、ハンドラの外部でキャッシュされたもの(HTTPキープアライブプール、復号されたシークレット、DBクライアントなど)は、そのコンテナでの呼び出しをまたいで永続化します。これが、高コストなオブジェクトをモジュールスコープで構築し、再利用するのが標準的なパターンである理由です。
import boto3, os
ddb = boto3.client('dynamodb') # reused across warm invokes
_secret = None
def _load_secret():
global _secret
if _secret is None:
_secret = kms.decrypt(...) # KMS call once per container, not per invoke
return _secret
def handler(event, ctx):
...
コールドスタートの大きさはランタイムによって異なります。Node.jsとPythonは数十から数百ミリ秒ですが、JVMと.NETは1秒を超えることがあります。VPCにアタッチされた関数では、Hyperplane ENIが歴史的なENIアタッチのペナルティを大幅に償却しましたが、依然としてパッケージサイズと重いINITコードが主な要因です。
コールドスタートに対処する3つのツールは、それぞれ異なるアプローチを取ります。
| 機能 | 動作 | コスト | 最適なケース |
|---|---|---|---|
| オンデマンド同時実行数 | デフォルト。最初のバーストで約500~3,000までスケールし、その後は+500/分 | 呼び出しごと + 実行時間 | バースト性があり、レイテンシーに寛容なワークロード |
| プロビジョニング済み同時実行数 | N個の環境を事前初期化し、トラフィックが来る前にINITを完了させる | プロビジョニングされたユニットに対して24時間365日支払い + 呼び出し料金 | 厳格なp99レイテンシーSLA |
| SnapStart (Java, Python, .NET) | INIT後にFirecrackerのスナップショットを作成し、コールドスタート時に復元する | Javaでは追加料金なし。その他では小額のキャッシュ料金 | 完全なプロビジョニングが非効率なJava関数 |
SnapStartは、厳格なレイテンシー契約がないJavaワークロードにとって、コスト効率の良いスイートスポットです。呼び出しごとの追加料金なしで、コールドスタートが約1桁減少します。プロビジョニング済み同時実行数は、同期APIがバースト時にp99を例えば100ミリ秒未満に維持する必要がある場合に正しい答えとなります。p95のバーストに合わせてサイジングすることで、テールレイテンシーのギャップを埋めることができます。これを過小にサイジングするのは典型的な失敗例です。オンデマンドではリクエストが到着して初めて新しいコンテナが起動するため、スパイクが発生すると実際のユーザーに数秒の待機時間が発生します。
# SAM: SnapStart on a Java 17 function
MyJavaFn:
Type: AWS::Serverless::Function
Properties:
Runtime: java17
SnapStart: { ApplyOn: PublishedVersions }
AutoPublishAlias: live
プロビジョニング済み同時実行数自体もApplication Auto Scalingによってスケールできます。例えば、07:45に10から200にスケールアップし、10:00に元に戻すスケジュールアクションを設定すれば、夜間にウォームなキャパシティの料金を支払うのを避けつつ、朝のサージによるコールドスタートを排除できます。
メモリのサイジングは、同時にCPUの調整ダイヤルでもあります。vCPUは、1 vCPUあたり約1,769 MBまでメモリと線形にスケールします。128 MBに固定された関数は、1,024 MBの関数よりも全体的なコストが高くなることがあります。これは、実行時間が2倍になることが、ミリ秒あたりの単価が2倍になる影響を上回ることが多いためです。推測で決めないでください。AWS Lambda Power Tuningを使用して、代表的なペイロードに対して様々な設定を試しましょう。
Lambdaの同時実行制御とダウンストリームの保護
3つの同時実行数の調整ダイヤルが重要であり、それぞれ異なる役割を果たします。
- 予約済み同時実行数は、関数が消費できる同時実行数の上限を設定し、かつその数を予約します。アカウントプールからキャパシティを切り出し、ダウンストリームシステム(小規模なRDSインスタンス、レート制限のあるパートナーAPIなど)が過負荷になるのを防ぎます。
- プロビジョニング済み同時実行数は、環境を事前初期化します。これはスケーリングのレバーではなく、レイテンシーのレバーです。
- 予約されていないアカウントの同時実行数は、共有プールであり、リージョンごとにデフォルトで1,000です。
Lambdaが「無限にスケールする」と仮定することは、2つの上限を見落としています。第一に、アカウントレベルの同時実行数制限は実在し、バースト制限(リージョンに応じて初期500~3,000、その後+500/分)がスケールアップの速度を規定します。これを超えると、同期呼び出し元は 429 TooManyRequestsException を受け取り、API Gatewayはこれを5xxエラーとしてクライアントに返します。第二に、ダウンストリームシステムには独自の制限があります。max_connections=85 の db.t3.micro インスタンスは、それぞれが接続を開く1,000の同時実行Lambdaに耐えられません。PostgreSQLは接続ごとにバックエンドプロセスをフォークし、約10 MBのRAMを消費します。CPUに余裕があっても、接続のセットアップとティアダウンだけでインスタンスを張り付かせてしまう可能性があります。
2つの緩和策は、(1) 多数のクライアントサイド接続を少数の永続的なバックエンド接続にプールおよび多重化する RDS Proxy と、(2) キューを挿入して処理レートを到着レートから分離することです。
import psycopg2, os
conn = psycopg2.connect(
host=os.environ['PROXY_ENDPOINT'], # RDS Proxy, not the DB directly
dbname='orders', user='app', password=get_secret())
RDS Proxyは最小限の変更で済むソリューションです(ドライバーと接続文字列はほとんど変更されません)。そのため、「アプリケーションへの変更を最小限に抑える」ことと接続枯渇の問題を解決することが要件である場合に、正しい答えとなります。DynamoDBにはこの問題がありません。そのHTTPS APIはステートレスであるため、DynamoDBはファンアウトの大きいLambdaワークロードと自然に組み合わせることができます。
LambdaのIAM、環境変数、およびネットワーキング
すべての関数は、呼び出し時に実行ロールを引き受けます。ロールの信頼ポリシーは lambda.amazonaws.com に sts:AssumeRole を許可し、そのアクセス許可ポリシーは関数が実行できる内容を定義します。ランタイムは、短命なSTS認証情報を AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、および AWS_SESSION_TOKEN に自動的に注入します。決してIAMユーザーのアクセスキーを環境変数やコードに埋め込まないでください。それらは静的で、漏洩したソースやCloudTrailのエクスポートで発見可能であり、手動でローテーションする必要があり、一時的な認証情報モデル全体をバイパスしてしまいます。
FnRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal: { Service: lambda.amazonaws.com }
Action: sts:AssumeRole
Policies:
- PolicyName: ReadOrders
PolicyDocument:
Statement:
- Effect: Allow
Action: ["dynamodb:GetItem", "dynamodb:Query"]
Resource: !GetAtt OrdersTable.Arn
機密性の高い設定を含む環境変数は、カスタマーマネージドKMSキーで暗号化する必要があります。その際、コンソールがクライアントサイドで暗号化するように、「転送中の暗号化ヘルパー」を使用します。INITフェーズで一度だけ復号し、平文をモジュールレベルの変数にキャッシュします。さもなければ、呼び出しごとにKMS APIが呼び出されることになります。
デフォルトでは、関数はAWSが管理するVPC内で実行され、アウトバウンドのインターネットアクセスに制限はありません。VPC内のリソース(プライベートサブネット内のRDS、ElastiCache、Direct Connect経由のオンプレミスなど)にアクセスする必要がある場合にのみ、独自のVPCにアタッチします。するとLambdaは、指定したサブネットにHyperplane ENIをアタッチし、そのルーティングを継承します。
典型的な罠は、NATゲートウェイを経由する以外にAWSサービストラフィックのルートがないプライベートサブネットにLambdaを配置することです。さらに悪いことに、自己管理のNATインスタンスを配置することです。NATインスタンスは単一のNICで飽和し、単一障害点(SPOF)となり、GB単位で課金されます。NATゲートウェイでさえGB単位で課金され、AWSサービストラフィックには不要です。正しいパターンは次のとおりです。
- S3とDynamoDB用のゲートウェイVPCエンドポイント(無料)
- KMS、Secrets Manager、SQS、SNS、STSなどのためのインターフェイス(PrivateLink)エンドポイント
これにより、トラフィックはAWSバックボーン上に留まり、NATのスループット上限が取り除かれ、予期せぬエグレス料金を防ぐことができます。LambdaのENIはパブリックIPを取得しないことに注意してください。関数を「パブリック」サブネットに配置しても、インターネットアクセスは得られません。適切なルートを持つ別のパブリックサブネットにNATゲートウェイが依然として必要です。
Amazon API Gateway: エンドポイントタイプ、認可、および配信
API Gatewayは3種類のAPIを提供します。
| 機能 | REST API | HTTP API | WebSocket |
|---|---|---|---|
| レイテンシー | より高い | 約60%低い | ステートフル、双方向 |
| コスト | より高い | 約70%安い | メッセージごと |
| 使用量プラン / APIキー | あり | なし | なし |
| リクエスト/レスポンス変換 (VTL) | あり | 限定的 | — |
| JWTオーソライザー | Lambda経由 | ネイティブ | Lambda経由 |
| WAF | あり | なし (CloudFrontを前面に配置) | あり |
APIキーと使用量プラン、JSONスキーマによるリクエスト検証、VTLマッピングテンプレート、メソッドごとのスコープを持つCognitoオーソライザー、またはWAFが必要な場合はRESTを選択します。コストとレイテンシーがより重要な、軽量なJWT認証プロキシパターンにはHTTPを選択します。
エンドポイントタイプは、APIがどこでフロントされるかを決定します。
- エッジ最適化: Gatewayが管理するCloudFrontディストリビューションによってフロントされます。TLSは最寄りのPOP (Point of Presence)で終端します。グローバルに分散したクライアントに最適です。
- リージョン: CloudFrontなしで単一のリージョンから公開されます。クライアントが同一リージョン内にいる場合、独自のCloudFrontを前面に配置したい場合、または複数のリージョンにまたがってRoute 53のレイテンシーベースルーティングを使用する場合に最適です。
- プライベート: インターフェイスVPCエンドポイントを介してのみ到達可能です。パブリックインターネットを経由してはならない内部マイクロサービスに最適です。
内部の単一リージョンAPIにエッジ最適化を選択すると、不要なCloudFrontホップが追加され、デプロイの伝播が遅くなります。グローバルに利用されるパブリックAPIにリージョンを選択すると、すべてのリクエストがパブリックインターネットを経由して1つのリージョンに強制されます。
カスタムドメインにはACM証明書が必要で、その場所はエンドポイントタイプに依存します。エッジ最適化の場合はus-east-1(CloudFrontはグローバルで、そこでTLSを終端するため)、リージョンエンドポイントの場合はAPI自体のリージョンです。これを混同することは、よくある設定ミスです。ベースパスマッピングにより、1つのドメインで複数のAPIを多重化できます(/orders → orders API、/users → users API)。
認可には4つのモデルがあり、組み込み機能を使わずに独自実装に走るのは典型的なアンチパターンです。
| メカニズム | 使用するケース |
|---|---|
| IAM認可 | 呼び出し元がSigV4に署名できるAWSプリンシパルである場合(他のサービス、SDK、クロスアカウント) |
| Cognitoユーザープールオーソライザー | ユーザーがCognitoユーザープールに対して認証し、GatewayがJWTを検証する場合 |
| Lambdaオーソライザー | 非標準トークン、OIDC非対応のサードパーティIdP、リクエストごとの複雑なロジックが必要な場合 |
| APIキー + 使用量プラン | メータリング、スロットリング、クォータ — 認証としては決して使用しない |
カスタムLambdaオーソライザーは、リクエストごとに(またはキャッシュのTTLごとに)余分な呼び出しを追加し、パッチ適用と監視が必要な関数をもう1つ増やし、署名検証のバグが静かにアクセスを許可してしまう可能性のあるコードパスを生み出します。組み込み機能では要件を本当に表現できない場合にのみ使用してください。
Lambdaプロキシ統合がデフォルトのパターンです。リクエスト全体がイベントとして渡され、関数は次のレスポンスエンベロープの形状を返す必要があります。
{
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": "{\"orderId\":\"abc123\"}",
"isBase64Encoded": false
}
非常に高いTPSでのfire-and-forget(撃ちっぱなし)の取り込みには、GatewayのAWSサービスの直接統合を使用してSQSやKinesisに直接プッシュし、Lambdaのホップを完全にスキップします。これにより、書き込みパスでのコールドスタートがなくなり、取り込みレートと処理能力が分離されます。
安全なロールアウトのために、ステージでカナリアデプロイメントを使用します。トラフィックの一部が新しいデプロイメントに送られ、大部分は安定版に留まります。カナリアごとのCloudWatchメトリクスが、昇格またはロールバックの判断材料となります。
aws apigateway update-stage --rest-api-id abc123 --stage-name prod \
--patch-operations \
op=replace,path=/canarySettings/percentTraffic,value=10 \
op=replace,path=/canarySettings/deploymentId,value=xyz789
API Gatewayの儀式が過剰となる単純なwebhook(シングルテナントのSlackコールバック、GitHubのプッシュハンドラーなど)には、Lambda関数URLが関数に直接専用のHTTPSエンドポイントを提供します。呼び出し元がAWSプリンシパルの場合は AuthType: AWS_IAM で保護します。NONE の場合は、関数内でリクエスト署名を必ず検証しなければなりません。AuthType: NONE で関数内の検証がない関数URLは、パブリックインターネット上の匿名のコンピューティングエンドポイントになります。
呼び出しタイプ、リトライ、べき等性
イベントソースは、動作が大きく異なる2つのカテゴリに分類されます。プッシュベースのソース(API Gateway, ALB, S3, SNS, EventBridge, Cognito)はLambdaを直接呼び出し、正しいPrincipal(例:events.amazonaws.com)とSourceArnを持つlambda:InvokeFunctionを許可するAWS::Lambda::Permissionリソースベースのポリシーを必要とします。これがないと、ルールはイベントにマッチしても、すべての呼び出しがサイレントに拒否されます。つまり、関数は決して実行されず、失敗はCloudTrailにのみ表示されます。これは、関数が何をできるかを管理する実行ロールとは異なり、誰が関数を呼び出せるかを管理するものです。
ポーリングベースのソース(SQS, Kinesis, DynamoDB Streams, MSK)は、イベントソースマッピングを介してLambdaサービスによって読み取られます。リソースベースのポリシーは不要ですが、実行ロールには読み取り権限を付与する必要があります。
呼び出しタイプによって、リトライの動作がさらに分岐します。
- 同期(API Gateway, ALB,
RequestResponseSDK):エラーは即座に返され、リトライは呼び出し元が責任を持ちます。 - 非同期(S3, SNS, EventBridge):Lambdaは内部キューでバッファリングし、失敗時には遅延を挟んで2回リトライした後、DLQまたは失敗時の送信先に送信します。
- SQSイベントソースマッピング:SQSは
maxReceiveCountに達してソースキューのDLQに移動されるまで、再配信を続けます。 - Kinesis / DynamoDB Streams:成功または有効期限が切れるまで単一のシャードバッチをリトライし、その間シャードをブロックします。スタックしたバッチは、そのパーティションのすべての下流処理を停止させます。
リトライはあらゆるレイヤーに組み込まれているため、べき等性はオプションではなく、必須です。遅い書き込み中にSQSの可視性タイムアウトが切れたり、下流の5xxエラーの後に非同期リトライが発生したりすると、重複が生じます。定番のパターンは、決定論的なキーとDynamoDBの条件付き書き込みを使用するものです。
def handler(event, context):
msg_id = event['Records'][0]['messageId']
try:
ddb.put_item(
TableName='processed',
Item={'id': {'S': msg_id}, 'ttl': {'N': str(ttl)}},
ConditionExpression='attribute_not_exists(id)')
except ddb.exceptions.ConditionalCheckFailedException:
return # already processed
process(event)
AWS Lambda Powertoolsの@idempotentデコレーターは、DynamoDBをバックエンドとして、まさにこのパターンを実装しています。
SQSとSNSによるデカップリング
ファンアウト数が大きいプッシュソースをLambdaに直接接続するのは脆弱です。例えば、S3のイベント通知はイベントごとに同期的であり、Lambdaの同時実行数の上限に左右されます。バースト的なアップロード(マーケティングキャンペーンで数千のドキュメントが数秒でドロップされるなど)の際に、呼び出しが利用可能な同時実行数を超えると、S3のリトライウィンドウは短く、イベントが事実上**ドロップされる(失われる)**可能性があります。解決策はバッファを挟むことです。
| パターン | 使用するケース |
|---|---|
| S3 → Lambda(直接) | イベントレートが低く予測可能。べき等な処理。 |
| S3 → SQS → Lambda | バースト的なワークロード。リトライ/DLQが必要。ダウンストリームのレート制限。 |
| S3 → SNS → 複数のSQS | 複数の独立したコンシューマーへのファンアウト。 |
| S3 → EventBridge → 多数のターゲット | アカウント間のルーティング。コンテンツベースのフィルタリング。 |
SNSはpub/sub(パブリッシュ/サブスクライブ)です。1回の発行で、多数のサブスクライバー(SQS, Lambda, HTTPS, Eメール)に配信されます。メッセージフィルタリングは属性ベースです。SQSは、メッセージを最大14日間保持する耐久性のあるポイントツーポイントのキューです。定番の組み合わせはSNS → SQSのファンアウトで、各コンシューマーに独自のバッファ付きキューを提供し、独立したスケーリングとリプレイを可能にします。
厳密な順序性(例:顧客ごとの注文を順次処理する)が必要な場合は、MessageGroupIdを順序付けキーに設定したSQS FIFOキューを使用します。グループ内のメッセージは順序通りに配信され、異なるグループは並行して処理されます。標準SQSはベストエフォートでの順序保証のみです。
定番の分離された取り込みパターンは、GatewayのSQS直接統合を使用してバーストを吸収し、レート制限されたプロセッサで処理するものです。
Resources:
OrdersQueue:
Type: AWS::SQS::Queue
Properties:
FifoQueue: true
ContentBasedDeduplication: true
RedrivePolicy:
deadLetterTargetArn: !GetAtt OrdersDLQ.Arn
maxReceiveCount: 5
ProcessorFunction:
Type: AWS::Lambda::Function
Properties:
ReservedConcurrentExecutions: 20 # cap the DB write rate
Mapping:
Type: AWS::Lambda::EventSourceMapping
Properties:
EventSourceArn: !GetAtt OrdersQueue.Arn
FunctionName: !Ref ProcessorFunction
BatchSize: 10
予約された同時実行数は意図的なものです。これにより、データベースへの書き込み速度に上限を設け、キュー(RDSではなく)がバーストを吸収するようにします。失敗したメッセージは、maxReceiveCountに達した後、オフラインでの調査のためにDLQにルーティングされます。
EventBridge: ルール、入力トランスフォーメーション、API送信先
EventBridgeは、豊富なJSONパターンマッチング、SaaSパートナーソース、スキーマレジストリ、アーカイブ/リプレイ機能を備えたスキーマ対応のイベントバスです。ルールはイベントパターンにマッチし、30以上のターゲットタイプ(Lambda, Step Functions, SQS, Kinesis, ECS, Firehose)にファンアウトします。SNSのように属性だけでなく、メッセージ本文に対するコンテンツベースのフィルタリングが可能です。
{
"source": ["tenant.energy"],
"detail-type": ["UsageReported"],
"detail": { "kWh": [{ "numeric": [">", 100] }] }
}
1つのルールには最大5つのターゲットを設定でき、それぞれが生のイベントまたは変換されたサブセットを受け取ります。入力トランスフォーマーは疎結合を強制します。InputPathsMapがイベントからJSONパスを抽出し、InputTemplateがそれらをターゲットが期待する形式に正確に再形成します。
EventPattern:
source: ["com.acme.orders"]
detail-type: ["OrderPlaced"]
Targets:
- Arn: !GetAtt PaymentValidator.Arn
InputTransformer:
InputPathsMap:
orderId: "$.detail.orderId"
amount: "$.detail.total"
card: "$.detail.payment.cardToken"
InputTemplate: |
{"orderId": <orderId>, "amount": <amount>, "cardToken": <card>}
各検証Lambdaは必要な情報のみを受け取ります。住所検証機能はカードトークンを見ることはありません。これは、イベント全体を受け取って内部で分岐するモノリシックなLambdaよりも決定的に優れています。モノリスはIAM権限を集中させ(1つのロールがすべての下流の権限を持つ必要がある)、バグの影響範囲(ブラスト半径)を拡大させ、デプロイのケイデンスを結合させ、責務ごとのメモリ/タイムアウトチューニングを妨げ、関数全体が最もノイズの多い分岐のレートに合わせてスケールすることを強制します。
API送信先は方向を逆にします。EventBridgeが外部のHTTPSエンドポイントを呼び出します。Secrets ManagerにBasic認証、APIキー、またはOAuth認証情報を保存する接続と組み合わせることで、例えばAWS Batchジョブが成功したときにサードパーティのSaaSに通知するためのサーバーレスな方法となります。Lambdaは不要です。EventBridgeが状態変化イベントをキャプチャし、ルールがJobSucceededにマッチし、API送信先ターゲットが接続から注入された認証情報を使ってベンダーにPOSTします。
スケジュールされたルール(cron/rate式)や、より新しいEventBridge Schedulerは、夜間レポートや毎時のキャッシュリフレッシュといった定期的なタスクのために、ハートビート用のEC2インスタンスを置き換えます。
フィルタリングがメッセージ本文のコンテンツに基づく場合(属性だけでなく)、新しいコンシューマーをプロデューサーの変更なしに後から接続する必要がある場合、またはルーティングがアカウントやSaaSソースをまたぐ場合は、SNSよりもEventBridgeを選択します。ファンアウトが安定した(固定的な)サブスクライバーのセットへの単純な属性フィルタリングによる通知である場合は、SNSを選択します。
Step Functions: オーケストレーションと分散マップ
ワークフローに数ステップ以上の処理、分岐、リトライ、人的承認、または長時間の待機が含まれる場合、そのロジックを連鎖したLambdaに埋め込むことは維持不可能になります。Step Functionsは、Amazon States Languageでステートマシンを外部化します。
- 標準ワークフロー: 最大1年間、厳密に1回のセマンティクス、完全な実行履歴、人間や外部システムによるゲートのための
.waitForTaskToken。注文処理、ETL、承認フローなどに利用されます。 - Expressワークフロー: 最大5分間、少なくとも1回のセマンティクス、高ボリューム、実行あたりのコストが安い。API Gatewayの背後にある短い同期的なオーケストレーション、IoTやストリーミングデータの変換に利用されます。
すべてのタスクは、明示的なRetryとCatchを宣言すべきです。
"ValidatePayment": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {"FunctionName": "PaymentValidator", "Payload.$": "$"},
"Retry": [{
"ErrorEquals": ["Lambda.ServiceException", "Lambda.TooManyRequestsException"],
"IntervalSeconds": 2, "MaxAttempts": 4, "BackoffRate": 2.0
}],
"Catch": [{"ErrorEquals": ["PaymentDeclined"], "Next": "RefundStep"}],
"Next": "ShipOrder"
}
ParallelおよびMapステートは、ブランチを並行して実行し、結果を集約します。これは、独立したバリデーター(住所、在庫、支払い)を持つ注文システムにきれいに適合します。ステップ間の状態は、実行のJSONドキュメントを通じて渡されるため、ワークフローの調整のためだけに共有データベースを使用する必要がなくなります。
.waitForTaskToken パターンは、外部のアクターがトークンを使ってSendTaskSuccessを呼び出すまで実行を一時停止します。これは、ワークフローがLambda、EC2、コンテナ、オンプレミスシステムにまたがり、最小限の運用オーバーヘッドで手動承認を必要とする場合の定番の解決策です。
"ManagerApproval": {
"Type": "Task",
"Resource": "arn:aws:states:::sns:publish.waitForTaskToken",
"Parameters": {
"TopicArn": "arn:aws:sns:us-east-1:111:approvals",
"Message": { "TaskToken.$": "$$.Task.Token", "OrderId.$": "$.orderId" }
},
"Next": "Fulfill"
}
分散マップは、標準のMapステートを拡張し、最大10,000の並列子実行を処理でき、S3バケット内のオブジェクトやCSV/JSONLファイルの行を直接反復処理できます。自動的なバッチ処理、チェックポイント作成、耐障害性を備えています。何千もの半構造化されたS3オブジェクトに対して、これは運用上最も効率的な選択肢です。プレフィックスを指定し、アイテムごとのタスクを定義するだけで、Step Functionsがファンアウト、MaxConcurrency、リトライ、結果の集約を処理します。
{
"Type": "Map",
"ItemReader": {
"Resource": "arn:aws:states:::s3:listObjectsV2",
"Parameters": { "Bucket": "raw-events", "Prefix": "2024/" }
},
"MaxConcurrency": 1000,
"ItemProcessor": {
"ProcessorConfig": { "Mode": "DISTRIBUTED", "ExecutionType": "STANDARD" },
"StartAt": "ProcessObject",
"States": { "ProcessObject": { "Type": "Task", "Resource": "arn:aws:lambda:...:function:ProcessOne", "End": true } }
}
}
SQSやEventBridgeで同じことを再構築するには、完了、リトライ、結果の集約のためにカスタムの記録管理が必要です。
Step Functions vs. EventBridge: Step Functionsは、あなたがシーケンスと結果(状態、分岐、リトライ、承認)を所有する場合に適しています。EventBridgeは、プロデューサーが誰が消費するかを知らない、または気にせず、コンシューマーが独立してアタッチする場合に適しています。
S3イベント通知
アップロードのほぼリアルタイムな処理のために、s3:ObjectCreated:*(またはPut、Post、CompleteMultipartUploadなどの特定のバリアント)でS3イベント通知をLambdaターゲットに設定します。ただし、上記のバーストに関する注意点に従う必要があります。ガードレールは以下の通りです。
- 予約された同時実行数を設定して、下流のデータベースを保護する。
- ポイズンメッセージのためにDLQまたは失敗時の送信先を有効にする。
- 複数のコンシューマーが同じイベントを必要とする場合は、S3イベントをEventBridge経由でルーティングする。直接のS3通知設定は、数と表現力に制限があります。ターゲットごとの入力トランスフォーマーを備えたEventBridgeのファンアウトは、はるかに優れたスケーラビリティを提供します。
ストリーミング: Kinesis Data Streams vs. Firehose
**Kinesis Data Streams (KDS)**は、シャーディングされ、順序付けられ、再生可能なログで、24時間から365日間の保持期間を持ちます。順序はパーティションキーによってキーイングされ、シャードごとに保持されます。これは、デバイスごとやテナントごとの集計に不可欠です。複数のコンシューマーが独立して読み取ります(拡張ファンアウトによりコンシューマーごとにスループットを分離)。順序付けられたリプレイ、複数の独立したコンシューマー、またはシャードごとの高スループットが必要な場合にKDSを選択します。
Kinesis Data Firehoseは、S3、Redshift、OpenSearch、またはSplunkへのフルマネージドの配信ストリームで、組み込みのバッファリング(60秒または1〜128 MB)、オプションのLambdaによる変換、圧縮(GZIP, Snappy)、Parquet/ORCへの変換機能を備えています。管理するシャードはありません。カスタムコンシューマーやリプレイが不要で、ほぼリアルタイムのデータを着地させるだけでよい場合、Firehoseは運用負荷の低い選択肢です。
定番のほぼリアルタイム分析パイプラインは、プロデューサー → KDS → Firehose → S3 (Parquet) → Athena/QuickSight で、FirehoseでのオプションのLambdaによるエンリッチメントを伴います。
マネージドSFTPのためのAWS Transfer Family
パートナーがS3やEFSとの間でSFTP、FTPS、またはFTPを必要とする場合、AWS Transfer Familyは、クライアントが既に使用しているプロトコルを話す、マネージドのマルチAZエンドポイントを提供します。認証は、サービス管理ユーザー、SSHキー、またはAPI Gateway/Lambda経由のカスタムIdPをサポートします。ファイルはSSEとライフサイクルポリシーが適用された状態でS3に直接着地し、IAMのスコープダウンポリシーにより、各ユーザーを特定のプレフィックスに制限します。
これをEC2で自作するには、OpenSSHの堅牢化、パッチ適用、AZ間のHA、キーローテーション、ログシッピングが必要ですが、これらすべてをTransfer Familyが吸収します。「パートナーがSFTPでファイルを送信してくる」という要件があり、最小限の運用オーバーヘッドでファイルをS3に格納したい場合に選択します。
定番のサーバーレスパターンの構成
テナントごとの時間単位メトリクスのための低オーバーヘッドな取り込み設計:センサーがAPI Gateway (HTTP API, リージョナル)にPOST → Lambdaが検証してEventBridgeに発行 → ルールがDynamoDBライターLambda(テナントIDをパーティションキー、時間バケットをソートキーとする)へ、かつ、並行して分析用の**Firehose → S3 (Parquet)**へルーティングします。新しいコンシューマーは、プロデューサーに触れることなく、追加のEventBridgeルールとしてアタッチされます。これは、SNSだけではきれいに満たせない拡張性の要件です。持続的なスループットと順序性が重要な場合(請求の照合、金融イベントストリームなど)、EventBridgeをKinesis Data Streamsに置き換え、独立したコンシューマーのために拡張ファンアウトを使用します。
陥りやすい罠:よくある誤ったパターンが失敗する理由
プライベートサブネットのLambdaからAWSサービスへのトラフィックにNATインスタンス/ゲートウェイを使用する。 NATインスタンスはスループットが単一のEC2 NICに束縛され、SPOF(単一障害点)となります。NATゲートウェイはGB単位で課金されます。どちらもAWSサービスが宛先の場合は不要です。S3/DynamoDBにはゲートウェイエンドポイントを、それ以外にはインターフェイスエンドポイントを使用してください。
レイテンシーが重要なAPIでコールドスタートを無視する。 オンデマンドではリクエスト到着時にのみコンテナがプロビジョニングされるため、バースト時にSLAを達成できません。プロビジョニング済み同時実行数はp95のバーストに合わせて設定し、厳密なSLAがないJavaワークロードにはSnapStartを使用してください。
単一の巨大なLambdaでイベント全体を受け取り、内部で分岐処理を行う。 最小権限の原則に違反し(1つのロールがすべての下流サービスの権限を持つ)、デプロイの頻度を結合させ、責務ごとのチューニングを妨げ、最も呼び出し頻度の高い分岐のレートに合わせて関数全体がスケールしてしまいます。責務ごとに分割し、EventBridgeやStep Functionsで連携させてください。
多数のLambdaから直接DBに接続する。 コンテナはプールを共有しないため、合計接続数は同時実行数と等しくなります。RDS Proxy(プーリング)、予約済み同時実行数(レート制限)、またはSQS(バッファリング)で解決してください。
バースト的なデータ取り込みに同期Lambdaを使用する。 同時実行数を超えると、API Gatewayには429が、クライアントには5xxが返されます。バースト時のS3直接通知は、イベントをサイレントにドロップします。SQSを間に挟むか、API Gateway → SQSの直接統合を使用してください。
AuthType: NONEで関数内の署名検証もないパブリックなLambda関数URL。 パブリックインターネット上で匿名のコンピューティングリソースを公開していることになります。AWSからの呼び出し元にはAWS_IAMを使用するか、サードパーティのWebhookには署名を検証してください。
組み込みの認証機能で十分な場合にカスタムLambdaオーソライザーを使用する。 レイテンシーの増加、パッチ適用が必要な関数の追加、そして署名チェックのバグがアクセスをサイレントに許可してしまうコードパスを生み出します。AWSプリンシパルにはIAM認可を、ユーザープールにはCognitoオーソライザーを選択してください。
カスタムドメインに対して誤ったリージョンのACM証明書を使用する。 エッジ最適化エンドポイントはus-east-1の証明書を、リージョンエンドポイントはAPI自体のリージョンの証明書を必要とします。
プッシュ型ソース(EventBridge, S3, SNS)に対するAWS::Lambda::Permissionの欠落。 イベントはルールに一致しますが、呼び出しはサイレントに拒否されます。これは実行ロールとは別物です。実行ロールが関数が何を実行できるかを定義するのに対し、こちらは関数を誰が呼び出せるかを管理します。
べき等性の欠如。 あらゆるレイヤーでリトライが発生します — 非同期呼び出し、SQSの可視性タイムアウト切れによる再配信、Kinesisのバッチリトライなど。決定論的な重複排除キーと条件付き書き込みがなければ、重複は避けられません。
← コンテナとオーケストレーション · すべてのドメイン · ストレージとデータライフサイクル →
これらの問題を練習する → · ExamRoll.ioで時間制限付き練習 →
Pass the whole exam — not just this question
You found this answer. Get every verified question and explanation in one place, and save hours of prep. Free to start.
試験に合格する →