機雷がなんだ! 全速前進!

SEというかプログラマというか、日々のエンジニア生活の中で体験したことなどを中心に書き残しています。

Amazon S3 ファイルのMD5ハッシュ値を効率的に計算するLambda

ちょっとした小技です。検索しても情報があまり無かったので一応書き留めておくことにします。

背景

S3にアップロードしたファイルが破損していないことを確認するため、アップロードしたファイルのMD5ハッシュ値を計算してチェックする仕組みが必要でした。S3に配置したタイミングで発火する S3 Object Lambda を用いて実現しようとしたところ、巨大なファイルをうまく処理できないという課題に遭遇しました。

課題

S3には大小さまざまなファイル(最低 0 バイトから最大 5 TB)を配置することができるため、場合によっては超巨大なファイルが処理対処となることもあり得ます。また、AWS Lambda は割り当てるメモリ量(128 MB から 10,240 MB までの任意の量のメモリを 1 MB 単位で関数に割り当て可能)によって単価が高くなるため、コストの観点からも不用意に高めることもできません。

やったこと

以下のように処理方法を変えました。

  • Before
 # S3から一気に全てダウンロードして計算する方式(メモリ不足の懸念あり)
s3_object2 = s3c.get_object(Bucket=src_bucket_name, Key=cpy_object_name)
all_body = s3_object2["Body"].read()
md5_hash_value2 = hashlib.md5(all_body).hexdigest().upper()
  • After
# S3から少しずつダウンロードしながら計算する方式(使用済みデータは捨てる)
s3_object1 = s3c.get_object(Bucket=src_bucket_name, Key=cpy_object_name)
md5 = hashlib.md5()
for chunk in s3_object1["Body"].iter_chunks(chunk_size=10240):
    md5.update(chunk)
md5_hash_value1 = md5.hexdigest().upper()

コピペで動作するサンプルコードとパフォーマンス比較計測結果をGithubにPushしておいたので実際に試してみたい人は以下をご覧ください。

github.com

まとめ

S3に格納されたオブジェクトには巨大なものもあり得るため、特別な理由がない限りは、基本的には【After】のようにMD5ハッシュ値の計算を実装すべきと考えられます。