Amazon Web Services ブログ

スケーラブルなチェックサムの構築

メディア&エンターテインメント業界のお客様は様々なフォーマットのデジタルアセットに触れています。一般的なアセットには、デジタルカメラネガティブ、フィルムスキャン、ポストプロダクションレンダリングなどがあり、これらはすべてビジネスに不可欠です。アセットがワークフローの中で、あるステップから次のステップに進む時に、お客様は、ネットワークの破損やハードドライブの故障、その他意図しない問題により、そのファイルが変更されていないことを確認したいと望んでいます。現在、業界ではチェックサムと呼ばれる、ファイルをバイト単位でスキャンし、そのファイル固有のフィンガープリントを生成するアルゴリズムが使用されています。

チェックサムを利用すると、ユーザーはコピー時にアセットが変更されていないことを確認出来ます。ファイルに対してチェックサムを実行するには、アルゴリズムを使ってファイル内のすべてのバイトを順番に反復処理し、計算機を利用してチェックサムを計算する必要があります。ファイルのサイズが大きくなると、チェックサムの計算にかかる合計時間が長くなり、従来の方法ではコストが高くなります。

本 Blog 記事では、ファイルの各々の異なる部分にチェックサムの計算を分割する異なるアプローチについて取り上げます。ファイルの各部分は、分割していない一連のファイルに対するチェックサムの計算とは異なる、一意のチェックサム値を持ちます。このアプローチにより、チェックサムを同時に計算することが可能になり、完了までの合計時間を削減することができます。 Amazon Simple Storage Service (Amazon S3) は、以前は存在しなかった、新しいチェックサム機能を使って、オブジェクトの一部分にアクセスできるようにします。

Amazon S3 へのファイルのアップロード速度を向上させるために、大きいオブジェクトは、S3 の multipart API call を用いて「パート」として知られている小さい要素に切り分けます。Amazon S3 は独立した各パートに対して MD5 ダイジェストを計算します。MD5 ダイジェストは最終的なオブジェクトの ETag を決定するために使用されます。Amazon S3 は MD5 ダイジェストのバイトを連結し、これらの連結値の MD5 ダイジェストを計算します。ETag 作成の最後のステップで、Amazon S3 は Etag の末尾にダッシュとパートの合計数を追加します。

オブジェクトの整合性検証を実行するための従来の方法は、ファイルのサイズに直接影響されます。Amazon Elastic Compute Cloud (Amazon EC2) i3en.2xlarge インスタンスで 1TB のデータの SHA256 チェックサムを計算するには、86 分の時間がかかります。2 つの変数がこの計算時間に影響します。1 つ目は計算能力です。CPU はコアを追加することで水平方向にスケーリングします。これは、オブジェクトを複数のパートに分割する機能で威力を発揮し、整合性チェックを並列化することでアプローチを最新化できます。計算時間に影響する変数の 2 つ目は、基盤となるストレージです。チェッサムの計算は可能な限り迅速なファイルの読み取りを必要とします。Amazon EC2 i3 インスタンスは低いレイテンシーと高い I/O パフォーマンスを提供するストレージ最適化されたインスタンスです。

マルチパートアップロードとチェックサム

チェックサムをファイルの複数のパートに分割すると、いくつかの利点が得られます。

  • 複数のコア、または複数のプロセスにわたってジョブを並列化
  • レジューム可能なプロセスの作成。計算に失敗した場合、失敗したパートのチェックサムを計算し、すでに計算されたパートをスキップできます
  • 複数のパートを同時にアップロードして、スループットを上げ、転送時間を短縮することができます

前の例では、1TB のファイルの処理に 86 分かかっていましたが、もしチェックサムを計算するプロセスが失敗すると、すべての進捗が失われ、再度開始する必要があります。各パートを独立して計算することで、各パートの状態を保存し、失敗があれば失敗したパートを復旧します。

マルチパートアップロートにおけるチェックサムの計算

aws-sdk-go-v2 を利用して、ファイルのマルチパートアップロードを作成し、ファイルの各パートを反復処理できます。新しいチェックサム機能を利用するには、 ChecksumAlgorithm パラメーターを渡すと、SDK は Amazon S3 へのアップロード時にチェックサムを計算します。

client.UploadPart(ctx, &s3.UploadPartInput{
    ChecksumAlgorithm: types.ChecksumAlgorithmSha256,
    Bucket:            &bucket,
    Key:               &key,
    PartNumber:        partNum,
    UploadId:          &uploadId,
    Body:              &limitedReader,
})

事前に計算されたチェックサムを作成することで、オブジェクトの整合性について心配することなく、送信元から送信先に移動することができます。新しい UploadPart API は、オブジェクトのパートに対する新しい属性として、事前に計算された値を受け入れます。事前計算された値を SDK に渡せば、この計算はスキップされます。Amazon S3 は、パートを受け取った時点でチェックサムを計算し、クライアントから提供された値を比較します。チェックサムが一致した場合、アップロードは意図したとおり完了し、そうでない場合には、クライアントはエラーを受け取ってリトライすることが出来ます。

GetObjectAttributes

新機能と共に Amazon S3 API call s3.GetObjectAttributes を導入しました。この新しい API は、アップロード中に計算されたパートのチェックサムなどを含めたオブジェクトのメタデータから取得できる属性のリストを取得します。この API が取得できるオプションは次のとおりです:ETag, Checksum, ObjectParts, StorageClass, ObjectSize.

client.GetObjectAttributes(ctx, &s3.GetObjectAttributesInput{
    Bucket: &bucket,
    Key:    &key,
    ObjectAttributes: []types.ObjectAttributes{
        types.ObjectAttributesChecksum,
       types.ObjectAttributesObjectParts,
    },
})

レスポンスの例は次のとおりです。

{
    "LastModified": "Fri, 25 Feb 2022 06:51:56 GMT",
    "VersionId": "9G.W.8LpAqXETuNaRra1mGnRHU2oBKjG",
    "ETag": "7931c2b8a6c796c7abb378bb546467cb-4",
    "ObjectParts": {
        "TotalPartsCount": 4,
        "PartNumberMarker": 0,
        "NextPartNumberMarker": 4,
        "MaxParts": 1000,
        "IsTruncated": false,
        "Parts": [
            {
                "PartNumber": 1,
                "Size": 16777216,
                "ChecksumSHA256": "Y17ezXQs3T0uBd1IfCd5+b0Z3S44Gfx5IuCN431af7I="
            },
            {
                "PartNumber": 2,
                "Size": 16777216,
                "ChecksumSHA256": "IO5OIm9O4H4UKCMYKqZ3g3sK1GK713lABEmOU991MC8="
            },
            {
                "PartNumber": 3,
                "Size": 16777216,
                "ChecksumSHA256": "yWHu1DARkVxDJ6fJyuD9DmdNIamLjAKE26jM8cRUVQM="
            },
            {
                "PartNumber": 4,
                "Size": 5000192,
                "ChecksumSHA256": "XxUYpRqbSiFjDrXJTrDdzJBmTNYblVqWQ6xkB5LGLlM="
            }
        ]
    }
}

これは、S3 API の中で大きな影響を与える変更です。以前は ETag には各パートのチェックサムから計算した最後のチェックサムしか含まれておらず、どのパートが変更されたかを判断できませんでした。新しい API では、個々のパートのチェックサムとそのサイズを精査できます。

Concurrency(同時並行性)

aws-sdk-go-v2 は Amazon S3 Transfer Manager ライブラリがあり、複雑さのほとんどを開発者から抽象化することで、マルチパートアップロードの作成を簡素化します。新しいUploader を初期化した後、クライアントはChecksumAlgorithm パラメーターを含めて、アップロードするすべてのパートのチェックサムを生成できます。水面下で、Transfer Manager はマルチパートアップロードを作成し、Trailing Checksums を使用してパートのチェックサムを計算し、それらのチェックサムをアップロードリクエストに追加します。これによって、両方の操作を 1 つのパスで実行できるため、時間を節約できます。

uploader := manager.NewUploader(client, func(u *manager.Uploader) {
    u.PartSize = 100 * 1024 * 1024 // 100MB per part
   u.Concurrency = 64 // how many workers transfer manager will use
})
uploader.Upload(ctx, &s3.PutObjectInput{
    ChecksumAlgorithm: types.ChecksumAlgorithmSha256,
    Bucket:            &bucket,
    Key:               &key,
    Body:              &reader,
})

Amazon S3 Transfer Manager では、PartSize や Concurrency など、開発者がカスタマイズできるいくつかのオプションがあります。これを念頭に置いて、Amazon S3 Transfer Manager を使用して、1TB のオブジェクトをそれぞれ 100MB の 10,000 個のパートに分割するように設定されたアップローダーを作成できます。I/O を向上させるテストのために、すべてのエフェメラル NVMe ドライブで RAID を組んだ Amazon EC2 i3.16xlarge インスタンスでは、SHA256 の計算と Amazon S3 へのアップロードは、 7 分 57 秒で完了しました。

おわりに

Amazon S3 マルチパートアップロードを利用すると、お客様はオブジェクトの整合性チェックを並列化するために必要な基盤を構築できます。加えて、新しいチェックサムが導入されたことで、お客様は現在のワークフローで使用しているのと同じアルゴリズムを引き続き使用できます。マルチパートファイルをサポートするワークフローをモダナイズすることで、お客様は、整合性チェックを並列化し、マルチコアインスタンスを活用し、時間を大幅に短縮し、そして、デジタル資産の規模が拡大し続けてもスケール可能なソリューションを構築できます。


参考リンク

AWS Media Services
AWS Media & Entertainment Blog (日本語)
AWS Media & Entertainment Blog (英語)
AWS のメディアチームの問い合わせ先: awsmedia@amazon.co.jp
※ 毎月のメルマガをはじめました。最新のニュースやイベント情報を発信していきます。購読希望は上記宛先にご連絡ください。

翻訳は SA 石井が担当しました。原文はこちらをご覧ください。