Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 7890

S3 イベント通知とオブジェクトのストレージクラス変更で発生する CopyObject イベントについて - KAKEHASHI Tech Blog

$
0
0

処方箋データ基盤チームでエンジニアをしている岩佐 (孝浩) です。 カケハシには「岩佐」さんが複数名在籍しており、社内では「わささん」と呼ばれています。

私が所属する処方箋データ基盤チームは、日本全国の薬局から送信される処方箋データを S3 に保存しています。 今後ストレージコストの増加が予測されるため、S3 ライフサイクル・ルールを利用してストレージクラスを変更することにしました。 この S3 バケットには EventBridge 通知が設定されており、ふと、「ストレージクラスの変更でイベントが発生するのでは」と気になりました。

結論として、ストレージクラスを変更すると、CopyObjectイベントが発生します。 S3 バケットにイベント通知を設定している場合、このイベントを意識していないと、予期せぬ結果を引き起こす可能性があり、注意が必要です。

この投稿では、S3 バケットに EventBridge 通知が設定されている場合の動作検証と対応方法について、備忘録も兼ねて紹介します。

AWS リソース作成

まずは、検証用の AWS リソースを作成します。

S3 バケット作成

S3 バケットを作成し、EventBridge 通知を有効化します。

# S3 バケット名bucket=storage-class-event-test-$(uuidgen | tr -d - | tr '[:upper:]''[:lower:]')# S3 バケット作成
aws s3api create-bucket \--bucket$bucket\--region ap-northeast-1 \--create-bucket-configurationLocationConstraint=ap-northeast-1

# EventBridge 通知有効化
aws s3api put-bucket-notification-configuration \--bucket$bucket\--notification-configuration='{ "EventBridgeConfiguration": {} }'

検証用オブジェクトのアップロード

検証用オブジェクトとして、任意のオブジェクトをアップロードします。 この投稿では、カケハシのテックブログのページをアップロードしています。

# Download
curl -o example.html https://kakehashi-dev.hatenablog.com/entry/2024/11/14/100000# サイズ確認ls-lah example.html
# -rw-r--r--. 1 cloudshell-user cloudshell-user 133K Nov 24 08:06 example.html# Upload
aws s3 cp example.html s3://$bucket/example.html

ライフサイクル・ルールを利用してストレージクラスを変更する場合、128KB 未満のオブジェクトはストレージクラスが変更されませんので、ご注意ください。

Objects smaller than 128 KB will not transition by default to any storage class

EventBridge Rule 作成

EventBridge Rule を作成し、ターゲットとして CloudWatch Logs を設定します。

# Event Patternpattern=$(echo'{"source": ["aws.s3"],"detail-type": ["Object Created"],"detail": {"bucket": {"name": ["<BUCKET>"]    }  }}'|sed -e "s/<BUCKET>/$bucket/"| jq -r .)# Event Rule 作成rule_name=storage-class-event-test-rule
aws events put-rule \--name$rule_name\--event-pattern"$pattern"# CloudWatch Logs 作成log_group_name=/aws/events/$rule_name
aws logs create-log-group \--log-group-name$log_group_name# CloudWatch Logs ARN 取得log_group_arn=$(  aws logs describe-log-groups \    --log-group-name-prefix $log_group_name \| jq -r '.logGroups[0].arn')# Event Target 作成
aws events put-targets \--rule$rule_name\--targets"Id"="cw-logs","Arn"="$log_group_arn"

ここで設定している Event Pattern が注意すべきポイントで、後ほど動作検証します。

以下のキャプチャのとおり、Management Console で作成した場合、この Event Pattern を設定しているケースが多いと推測されるので、必要に応じて設定の見直しをお勧めします。

EventBridge Rule Event Pattern

動作検証1回目

ストレージクラス変更

この投稿では、AWS CLI で既存オブジェクトのストレージクラスを変更します。 その他の方法については、公式ドキュメントをご参照ください。

# Standard IA に変更
aws s3 cp s3://$bucket/example.html s3://$bucket/example.html \--storage-class STANDARD_IA

CloudWatch Logs 確認

EventBridge Rule のターゲットに設定した CloudWatch Logs を確認します。

log_stream_name=$(  aws logs describe-log-streams \    --log-group-name $log_group_name \    --order-by LastEventTime \    --descending \| jq -r '.logStreams[0].logStreamName')

aws logs get-log-events \--log-group-name$log_group_name\--log-stream-name$log_stream_name\
| jq '.events[].message | fromjson'

以下のようなイベントが記録されているはずです。

{"version": "0",
  "id": "12bcd22e-81e4-bba5-2037-95ab37991eaa",
  "detail-type": "Object Created",
  "source": "aws.s3",
  "account": "123456789012",
  "time": "2024-11-24T08:23:39Z",
  "region": "ap-northeast-1",
  "resources": ["arn:aws:s3:::storage-class-event-test-<UUID>"
  ],
  "detail": {"version": "0",
    "bucket": {"name": "storage-class-event-test-<UUID>"
    },
    "object": {"key": "example.html",
      "size": 136162,
      "etag": "2fb8b1f49c6b495c614f1f7a7efb8835",
      "sequencer": "006742E28B93AB9A39"
    },
    "request-id": "8TP3RRRX0ZYF0HJP",
    "requester": "123456789012",
    "source-ip-address": "xxx.xxx.xxx.xxx",
    "reason": "CopyObject"
  }}

動作検証結果

上で確認したとおり、現在設定されている Event Pattern では、ストレージクラスの変更時に発生する CopyObjectイベントも処理してしまいます。

次の条件に該当する場合、Event Pattern の見直しが必要です。

  • ストレージクラスの変更時に発生するイベントを処理した場合、データの不整合が生じる。(冪等性を考慮した設計になっていない)
  • 膨大な数のオブジェクトが、ストレージクラスの変更対象になる。
  • Object Created - CopyObjectイベントを処理する必要が無い。

Event Pattern 再設定による対応

ストレージクラスの変更時に発生する Object Created - CopyObjectイベントを処理しないように、Event Pattern に reasonを追加します。

@@ -10,6 +10,9 @@"name": [
         "storage-class-event-test-<UUID>"
       ]
-    }+    },+    "reason": [+      "PutObject"+    ]
   }
 }
# Event Patternpattern=$(echo'{"source": ["aws.s3"],"detail-type": ["Object Created"],"detail": {"bucket": {"name": ["<BUCKET>"]    },"reason": ["PutObject"    ]  }}'|sed -e "s/<BUCKET>/$bucket/"| jq -r .)

aws events put-rule \--name$rule_name\--event-pattern"$pattern"

動作検証2回目

CloudWatch Logs 再作成

ストレージクラスの変更が EventBridge Rule で処理されていないことを確認するため、事前に CloudWatch Logs を再作成しておきます。

# 削除
aws logs delete-log-group \--log-group-name$log_group_name# 作成
aws logs create-log-group \--log-group-name$log_group_name

ストレージクラス変更

Standard IAに変更したオブジェクトを Standardに戻します。

# Standard に変更
aws s3 cp s3://$bucket/example.html s3://$bucket/example.html \--storage-class STANDARD

CloudWatch Logs 確認

EventBridge Rule のターゲットに設定した CloudWatch Logs を確認します。 "logStreams": []が表示されるはずです。

aws logs describe-log-streams \--log-group-name$log_group_name\--order-by LastEventTime \--descending{"logStreams": []}

(補足) アップロード確認

念のため、オブジェクトのアップロード (PutObject) が EventBridge Rule で処理されることを確認しておきます。

# Upload
aws s3 cp example.html s3://$bucket/example-new.html

# CloudWatch Logs 確認log_stream_name=$(  aws logs describe-log-streams \    --log-group-name $log_group_name \    --order-by LastEventTime \    --descending \| jq -r '.logStreams[0].logStreamName')

aws logs get-log-events \--log-group-name$log_group_name\--log-stream-name$log_stream_name\
| jq '.events[].message | fromjson'

"reason": "PutObject"のイベントは、EventBridge Rule で処理されていることが確認できます。

{"version": "0",
  "id": "f54bb5b7-e02e-da2a-b89c-6fb667139950",
  "detail-type": "Object Created",
  "source": "aws.s3",
  "account": "123456789012",
  "time": "2024-11-24T09:59:39Z",
  "region": "ap-northeast-1",
  "resources": ["arn:aws:s3:::storage-class-event-test-<UUID>"
  ],
  "detail": {"version": "0",
    "bucket": {"name": "storage-class-event-test-<UUID>"
    },
    "object": {"key": "example-new.html",
      "size": 136162,
      "etag": "2fb8b1f49c6b495c614f1f7a7efb8835",
      "sequencer": "006742F90B0B6E1613"
    },
    "request-id": "MM7A7QD53JB1WFC5",
    "requester": "123456789012",
    "source-ip-address": "xxx.xxx.xxx.xxx",
    "reason": "PutObject"
  }}

まとめ

S3 バケットにイベント通知を設定している場合、ストレージクラスを変更すると、予期せぬイベントを処理してしまう可能性があります。

次の条件に該当する場合、Event Pattern に reasonが含まれているか確認することをお勧めします。

  • ストレージクラスの変更時に発生するイベントを処理した場合、データの不整合が生じる。(冪等性を考慮した設計になっていない)
  • 膨大な数のオブジェクトが、ストレージクラスの変更対象になる。
  • Object Created - CopyObjectイベントを処理する必要が無い。

以上、お役に立てれば幸いです。


Viewing all articles
Browse latest Browse all 7890

Trending Articles