backend
A
信頼度ランク
| S | 公式ソース確認済み |
| A | 成功実績多数・失敗例少数 |
| B | 賛否両論 |
| C | 動作未確認・セキュリティリスク高 |
| Z | 個人所感 |
S3イベント通知 — SNS/SQS/Lambda/EventBridgeの使い分け
S3イベント通知の設定方法、SNS・SQS・Lambda・EventBridgeへの連携パターン、イベントタイプの種類、ファンアウト設計、重複通知の可能性と対策を解説。
一言結論
S3イベント通知はat-least-once配信のため重複が起こりうるので処理側の冪等性が必須であり、1つのイベントを複数処理へ渡すにはSNSファンアウト、高度なフィルタリングにはEventBridgeという使い分けが設計の基本だ。
S3イベント通知の仕組み
S3バケットでオブジェクトの作成・削除・復元等のイベントが発生すると、設定した通知先にイベント情報が送信される。
通知先(デスティネーション):
- SNS(Simple Notification Service)
- SQS(Simple Queue Service)
- Lambda関数
- EventBridge(より高度なルーティングに対応)
主要なイベントタイプ
オブジェクト作成:
s3:ObjectCreated:* (全作成イベント)
s3:ObjectCreated:Put
s3:ObjectCreated:Post (マルチパートアップロード完了)
s3:ObjectCreated:Copy
s3:ObjectCreated:CompleteMultipartUpload
オブジェクト削除:
s3:ObjectRemoved:*
s3:ObjectRemoved:Delete
s3:ObjectRemoved:DeleteMarkerCreated
Glacierからの復元:
s3:ObjectRestore:Post (復元リクエスト)
s3:ObjectRestore:Completed(復元完了)
レプリケーション:
s3:Replication:OperationFailedReplication
s3:Replication:OperationMissedThreshold
Lambda連携の設定
# 1. LambdaにS3からの呼び出し権限を付与
aws lambda add-permission \
--function-name image-processor \
--statement-id s3-trigger \
--action lambda:InvokeFunction \
--principal s3.amazonaws.com \
--source-arn arn:aws:s3:::my-uploads-bucket \
--source-account 123456789012
# 2. S3バケットに通知設定を追加
aws s3api put-bucket-notification-configuration \
--bucket my-uploads-bucket \
--notification-configuration '{
"LambdaFunctionConfigurations": [{
"LambdaFunctionArn": "arn:aws:lambda:ap-northeast-1:123456789012:function:image-processor",
"Events": ["s3:ObjectCreated:*"],
"Filter": {
"Key": {
"FilterRules": [
{"Name": "prefix", "Value": "uploads/"},
{"Name": "suffix", "Value": ".jpg"}
]
}
}
}]
}'
# Lambda関数でS3イベントを処理する例
def handler(event, context):
for record in event['Records']:
bucket = record['s3']['bucket']['name']
key = record['s3']['object']['key']
size = record['s3']['object']['size']
print(f"処理開始: s3://{bucket}/{key} ({size} bytes)")
# 画像のサムネイル生成など
process_image(bucket, key)
ファンアウトパターン(SNS → 複数SQS)
一つのS3イベントを複数の処理に渡す場合:
S3イベント → SNSトピック → SQS A (画像リサイズ処理)
→ SQS B (メタデータ抽出)
→ Lambda (通知送信)
// S3通知設定(SNSへ)
{
"TopicConfigurations": [{
"TopicArn": "arn:aws:sns:ap-northeast-1:123456789012:s3-events",
"Events": ["s3:ObjectCreated:*"]
}]
}
S3通知は1つのイベントタイプに対して1つの通知先しか設定できない(同じプレフィックス/サフィックスへの重複設定は不可)。複数の処理に渡す場合はSNSを経由するファンアウトが必要だ。
EventBridgeへの転送
EventBridgeを使うとより高度なルーティングが可能だ。
# バケットのEventBridge転送を有効化
aws s3api put-bucket-notification-configuration \
--bucket my-bucket \
--notification-configuration '{
"EventBridgeConfiguration": {}
}'
// EventBridgeルール: 5MB以上のファイルアップロードのみ処理
{
"source": ["aws.s3"],
"detail-type": ["Object Created"],
"detail": {
"bucket": {
"name": ["my-bucket"]
},
"object": {
"size": [{"numeric": [">=", 5242880]}]
}
}
}
EventBridgeの利点:
- イベントのフィルタリングが細かく設定できる
- 複数の宛先に同時に送信できる(ルールを複数作成)
- クロスアカウント・クロスリージョン転送が容易
重複通知の可能性
S3のイベント通知はat-least-once delivery(少なくとも1回配信)だ。稀に重複通知が発生する可能性がある。
対策:
# DynamoDBで重複処理を防ぐ(冪等性の確保)
def handler(event, context):
for record in event['Records']:
etag = record['s3']['object']['eTag']
key = record['s3']['object']['key']
# ETAGをキーに重複チェック
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('processed-objects')
try:
table.put_item(
Item={'etag': etag, 'key': key},
ConditionExpression='attribute_not_exists(etag)'
)
except table.meta.client.exceptions.ConditionalCheckFailedException:
print(f"既に処理済み: {key}")
return
# 実際の処理
process_object(record)
試験頻出ポイント
| シナリオ | 回答 |
|---|---|
| 1つのS3イベントを複数の処理に渡したい | SNSファンアウトパターン |
| イベントを特定の条件でフィルタしたい | EventBridgeを使う |
| 重複処理を防ぎたい | 処理側で冪等性を担保(DynamoDB等) |
| プレフィックスとサフィックスの両方でフィルタ | S3通知のFilterRulesで設定可能 |
まとめ
シンプルな1対1のイベント連携にはS3ネイティブ通知(Lambda/SQS)、複数処理への分配にはSNSファンアウト、複雑なフィルタリングや高度なルーティングにはEventBridgeを使う。重複通知を前提とした冪等な処理設計が重要だ。