S3 Express One Zone のパフォーマンスを最適化するためのベストプラクティス - Amazon Simple Storage Service

S3 Express One Zone のパフォーマンスを最適化するためのベストプラクティス

Amazon S3 Express One Zone からオブジェクトをアップロードしたり取得したりするアプリケーションを構築する場合は、パフォーマンスを最適化するためのベストプラクティスガイドラインに従ってください。S3 Express One Zone ストレージクラスを使用するには、S3 ディレクトリバケットを作成する必要があります。S3 Express One Zone ストレージ クラスは、S3 汎用バケットでの使用はサポートされていません。

その他すべての Amazon S3 ストレージクラスと S3 汎用バケットのパフォーマンスガイドラインについては、「設計パターンのベストプラクティス: Amazon S3 のパフォーマンスの最適化」を参照してください。

大規模なワークロードで S3 Express One Zone ストレージクラスとディレクトリバケットを使用して最適なパフォーマンスとスケーラビリティを実現するには、ディレクトリバケットと汎用バケットの動作の違いを理解することが重要です。そこで、アプリケーションをディレクトリバケットの動作に合わせて調整するためのベストプラクティスをご紹介します。

ディレクトリバケットの仕組み

Amazon S3 Express One Zone ストレージクラスは、ディレクトリバケットあたり毎秒最大 2,000,000 件の GET トランザクションと最大 200,000 件の PUT トランザクション (TPS) のワークロードをサポートできます。S3 Express One Zone では、データはアベイラビリティーゾーン内の S3 ディレクトリバケットに保存されます。ディレクトリバケット内のオブジェクトは、フラットな名前空間を持つ S3 汎用バケットとは対照的に、ファイルシステムに似た階層型の名前空間内でアクセス可能です。汎用バケットとは異なり、ディレクトリバケットはキーをプレフィックスではなくディレクトリに階層的に整理します。プレフィックスは、オブジェクトキー名の先頭にある文字列です。プレフィックスを使用してデータを整理し、汎用バケットでフラットオブジェクトストレージアーキテクチャを管理できます。詳細については、「プレフィックスを使用してオブジェクトを整理する」を参照してください。

ディレクトリバケットでは、オブジェクトは階層型の名前空間に整理され、スラッシュ (/) のみが区切り文字としてサポートされます。dir1/dir2/file1.txt のようなキーを持つオブジェクトをアップロードすると、Amazon S3 によってディレクトリ dir1/dir2/ が自動的に作成および管理されます。ディレクトリは PutObject または CreateMultiPartUpload オペレーション中に作成され、DeleteObject または AbortMultiPartUpload オペレーション後に空になると自動的に削除されます。ディレクトリ内のオブジェクトとサブディレクトリの数に制限はありません。

オブジェクトがディレクトリバケットにアップロードされたときに作成されるディレクトリは、HTTP 503 (Slow Down) エラーの可能性を減らすために瞬時にスケールできます。この自動スケーリングにより、アプリケーションは必要に応じてディレクトリ内およびディレクトリ間の読み取り/書き込みリクエストを並列処理できます。S3 Express One Zone の場合、個々のディレクトリはディレクトリバケットの最大リクエストレートをサポートするように設計されています。システムがオブジェクトを自動的に分散して負荷を均等に分散するため、最適なパフォーマンスを実現するためにキープレフィックスをランダム化する必要はありませんが、その結果、キーはディレクトリバケット内で辞書順に格納されません。これは、辞書順に近いキーが同じサーバー上に配置される可能性が高くなる S3 汎用バケットとは対照的です。

ディレクトリバケットオペレーションとディレクトリインタラクションの例の詳細については、「ディレクトリバケットオペレーションとディレクトリインタラクションの例」を参照してください。

ベストプラクティス

ディレクトリバケットのパフォーマンスを最適化し、ワークロードの長期的なスケールアップを支援するためにベストプラクティスに従ってください。

多数のエントリ (オブジェクトまたはサブディレクトリ) を含むディレクトリを使用する

ディレクトリバケットは、すべてのワークロードに対してデフォルトで高いパフォーマンスを提供します。特定のオペレーションでパフォーマンスをさらに最適化するために、より多くのエントリ (オブジェクトまたはサブディレクトリ) をディレクトリに統合すると、レイテンシーが低くなり、リクエストレートが向上します。

  • PutObjectDeleteObjectCreateMultiPartUploadAbortMultiPartUpload などの変異 API オペレーションは、多数の小さなディレクトリではなく、数千のエントリを含む少数の高密度ディレクトリで実装すると、最適なパフォーマンスが得られます。

  • ListObjectsV2 オペレーションは、結果ページを生成するためにトラバースする必要があるディレクトリ数が少ないほど、パフォーマンスが向上します。

プレフィックスにエントロピーを使用しない

Amazon S3 オペレーションでは、エントロピーとは、ストレージパーティション間でワークロードを均等に分散するのに役立つプレフィックス命名におけるランダム性を指します。ただし、ディレクトリバケットは内部的に負荷分散を管理するため、パフォーマンスを最大限に高めるためにプレフィックスにエントロピーを使用することは推奨されません。これは、ディレクトリバケットの場合、エントロピーによって既に作成済みのディレクトリが再利用されず、リクエストが遅くなる可能性があるためです。

$HASH/directory/object のようなキーパターンは、多くの中間ディレクトリを作成する可能性があります。次の例では、親が異なるため、すべての job-1 は異なるディレクトリです。ディレクトリはスパースになり、ミューテーションリクエストとリストリクエストは遅くなります。この例では、すべて単一のエントリを持つ中間ディレクトリが 12 個あります。

s3://my-bucket/0cc175b9c0f1b6a831c399e269772661/job-1/file1 s3://my-bucket/92eb5ffee6ae2fec3ad71c777531578f/job-1/file2 s3://my-bucket/4a8a08f09d37b73795649038408b5f33/job-1/file3 s3://my-bucket/8277e0910d750195b448797616e091ad/job-1/file4 s3://my-bucket/e1671797c52e15f763380b45e841ec32/job-1/file5 s3://my-bucket/8fa14cdd754f91cc6554c9e71929cce7/job-1/file6

代わりに、パフォーマンスを向上させるために、$HASH コンポーネントを削除し、 job-1 を単一のディレクトリにして、ディレクトリの密度を向上させることができます。次の例では、6 つのエントリを持つ単一の中間ディレクトリを使用することで、前の例と比較してパフォーマンスを向上させることができます。

s3://my-bucket/job-1/file1 s3://my-bucket/job-1/file2 s3://my-bucket/job-1/file3 s3://my-bucket/job-1/file4 s3://my-bucket/job-1/file5 s3://my-bucket/job-1/file6

このパフォーマンス上の利点は、オブジェクトキーが最初に作成され、そのキー名にディレクトリが含まれている場合、そのオブジェクト用のディレクトリが自動的に作成されるためです。同じディレクトリにそれ以降にオブジェクトをアップロードする場合、ディレクトリを作成する必要がないため、既存のディレクトリにオブジェクトをアップロードする際のレイテンシーが軽減されます。

ListObjectsV2 呼び出し中にオブジェクトを論理的にグループ化する必要がない場合は、区切り文字/以外の区切り文字を使用してキーの部分を区切ります。

/ 区切り文字はディレクトリバケットに対して特別に扱われるため、意図的に使用する必要があります。ディレクトリバケットはオブジェクトを辞書順に並べませんが、ディレクトリ内のオブジェクトは引き続き ListObjectsV2 出力でグループ化されます。この機能が不要な場合は、区切り文字として / を別の文字に置き換えて、中間ディレクトリが作成されないようにすることができます。

例えば、以下のキーが YYYY/MM/DD/HH/ というプレフィックスパターンになっているとします。

s3://my-bucket/2024/04/00/01/file1 s3://my-bucket/2024/04/00/02/file2 s3://my-bucket/2024/04/00/03/file3 s3://my-bucket/2024/04/01/01/file4 s3://my-bucket/2024/04/01/02/file5 s3://my-bucket/2024/04/01/03/file6

ListObjectsV2 の結果でオブジェクトを時間や日でグループ化する必要はないが、月でグループ化する必要がある場合、YYYY/MM/DD-HH- というキーパターンを使用すると、ディレクトリ数が大幅に減少し、ListObjectsV2 オペレーションのパフォーマンスが向上します。

s3://my-bucket/2024/04/00-01-file1 s3://my-bucket/2024/04/00-01-file2 s3://my-bucket/2024/04/00-01-file3 s3://my-bucket/2024/04/01-02-file4 s3://my-bucket/2024/04/01-02-file5 s3://my-bucket/2024/04/01-02-file6

可能な場合は、区切りリストオペレーションを使用する

delimiter のない ListObjectsV2 リクエストは、すべてのディレクトリに対して深さ優先の再帰的トラバーサルを実行します。delimiter のある ListObjectsV2 は、prefix パラメータで指定されたディレクトリ内のエントリのみを取得するため、リクエストのレイテンシーが短縮され、1 秒あたりの集計キーが増加します。ディレクトリバケットの場合は、可能な限り区切りリストオペレーションを使用してください。区切りリストを使用することで、ディレクトリへのアクセス回数が減り、1 秒あたりのキー数が増加し、リクエストのレイテンシーが短縮されます。

例えば、ディレクトリバケット内の次のディレクトリとオブジェクトの場合。

s3://my-bucket/2024/04/12-01-file1 s3://my-bucket/2024/04/12-01-file2 ... s3://my-bucket/2024/05/12-01-file1 s3://my-bucket/2024/05/12-01-file2 ... s3://my-bucket/2024/06/12-01-file1 s3://my-bucket/2024/06/12-01-file2 ... s3://my-bucket/2024/07/12-01-file1 s3://my-bucket/2024/07/12-01-file2 ...

ListObjectsV2 のパフォーマンスを向上させるには、アプリケーションのロジックで許可されている場合は、区切りリストを使用してサブディレクトリとオブジェクトを一覧表示します。例えば、区切りリストオペレーションを実行するには、次のコマンドを実行します。

aws s3api list-objects-v2 --bucket my-bucket --prefix '2024/' --delimiter '/'

出力はサブディレクトリのリストです。

{ "CommonPrefixes": [ { "Prefix": "2024/04/" }, { "Prefix": "2024/05/" }, { "Prefix": "2024/06/" }, { "Prefix": "2024/07/" } ] }

各サブディレクトリの一覧表示のパフォーマンスを向上させるには、次の例のようなコマンドを実行します。

コマンド:

aws s3api list-objects-v2 --bucket my-bucket --prefix '2024/04' --delimiter '/'

出力:

{ "Contents": [ { "Key": "2024/04/12-01-file1" }, { "Key": "2024/04/12-01-file2" } ] }

S3 Express One Zone ストレージと コンピューティングリソースを同じロケーションに配置する

S3 Express One Zone では、各ディレクトリのバケットは、バケットの作成時に選択した単一のアベイラビリティーゾーンに保存されます。まず、コンピュートワークロードまたはリソースにローカルなアベイラビリティーゾーンに新しいディレクトリバケットを作成します。これにより、レイテンシーが非常に低い読み取りと書き込みの利用を直ちに開始できます。ディレクトリバケットは S3 バケットの一種で、コンピューティングとストレージの間のレイテンシーを低減するために AWS リージョン内のアベイラビリティーゾーンを選択できる最初の S3 バケットです。

複数のアベイラビリティーゾーンにわたってディレクトリバケットにアクセスすると、レイテンシーがわずかに増加する可能性があります。パフォーマンスを最適化するには、可能な場合は、同じアベイラビリティーゾーンにある Amazon Elastic Container Service、Amazon Elastic Kubernetes Service、Amazon Elastic Compute Cloud のインスタンスからディレクトリバケットにアクセスすることをお勧めします。

同時接続を使用して、1MB を超えるオブジェクトで高スループットを実現する

ディレクトリバケットに複数のリクエストを同時に発行し、リクエストを別々の接続に分散してアクセス可能な帯域幅を最大化することで、最高のパフォーマンスを実現できます。汎用バケットと同様に、S3 Express One Zone には、バケットへの接続数に制限はありません。同じディレクトリへの同時書き込みが多数発生した場合、個々のディレクトリのパフォーマンスを水平方向かつ自動的にスケールできます。

ディレクトリバケットへの個々の TCP 接続には、1 秒あたりにアップロードまたはダウンロードできるバイト数に対する固定の上限があります。オブジェクトが大きくなると、リクエスト時間はトランザクション処理ではなくバイトストリーミングによって支配されるようになります。複数の接続を使用して大きなオブジェクトのアップロードまたはダウンロードを並列化することで、エンドツーエンドのレイテンシーを削減できます。Java 2.x SDK を使用する場合は、マルチパートアップロード API オペレーションやバイト範囲フェッチなどのパフォーマンスの向上を利用してデータに並行してアクセスする S3 Transfer Manager の使用を検討する必要があります。

ゲートウェイ VPC エンドポイントを使用する

ゲートウェイエンドポイントは、VPC からディレクトリバケットへの直接接続を提供します。VPC にインターネットゲートウェイや NAT デバイスは必要ありません。パケットがネットワーク上で費やす時間を短縮するには、VPC にディレクトリバケット用のゲートウェイ VPC エンドポイントを設定する必要があります。詳細については、「ディレクトリバケットのネットワーク」を参照してください。

セッション認証を使用し、有効なセッショントークンを再利用する

ディレクトリバケットは、パフォーマンスが重視される API オペレーションのレイテンシーを削減するためのセッショントークン認証メカニズムを提供します。CreateSession を 1 回呼び出すだけでセッショントークンを取得でき、このトークンはその後 5 分間のすべてのリクエストで有効になります。API コールのレイテンシーを最小限に抑えるには、セッショントークンを取得し、そのトークンの有効期間全体にわたって再利用してから更新するようにしてください。

AWS SDK を使用する場合、セッショントークンの更新は SDK によって自動的に処理され、セッションの有効期限が切れたときのサービス中断を回避できます。AWS SDK を使用して CreateSession API オペレーションへのリクエストを開始および管理することをお勧めします。

CreateSession の詳細については、「CreateSession を使用したゾーンエンドポイント API オペレーションの承認」を参照してください。

CRT ベースのクライアントを使用する

AWS Common Runtime (CRT) は、C 言語で記述されたモジュール式で高性能かつ効率的なライブラリのセットで、AWS SDK の基盤として機能します。CRT は、スループットの向上、接続管理の強化、スタートアップタイムの短縮を実現します。CRT は Go を除くすべての AWS SDK で使用できます。

使用する SDK に合わせて CRT を設定する方法の詳細については、「AWS Common Runtime (CRT) libraries」、「Accelerate Amazon S3 throughput with the AWS Common Runtime」、「Introducing CRT-based S3 client and the S3 Transfer Manager in the AWS SDK for Java 2.x」、「Using S3CrtClient for Amazon S3 operations」、および「Configure AWS CRT-based HTTP clients」を参照してください。

最新バージョンの AWS SDK を使用する

AWS SDK では、Amazon S3 のパフォーマンスの最適化のために推奨されている多くのガイドラインが組み込みでサポートされています。SDK は、アプリケーション内から Amazon S3 を活用するためのシンプルな API を提供し、最新のベストプラクティスに合わせて定期的に更新されます。例えば、SDK は HTTP 503 エラーの後にリクエストを自動的に再試行し、接続レスポンスの遅延を処理します。

Java 2.x SDK を使用している場合は、S3 Transfer Manager の使用を検討する必要があります。S3 Transfer Manager は、必要に応じてバイト範囲リクエストを使用して接続を水平方向に自動的にスケーリングし、1 秒あたり数千件のリクエスト処理を実現します。バイト範囲リクエストは、S3 への同時接続を使用して同じオブジェクト内からさまざまなバイト範囲を取得できるため、パフォーマンスを向上させます。これにより、単一のオブジェクト全体のリクエストに対して高い集約スループットを実現できます。そのため、最新のパフォーマンス最適化機能を利用するには、最新バージョンの AWS SDK を使用することが重要です。

パフォーマンスのトラブルシューティング

レイテンシーの影響を受けやすいアプリケーションに対して、再試行リクエストを設定していますか。

S3 Express One Zone は、追加の調整を必要とせずに一貫したレベルのパフォーマンスを実現できるように設計されています。ただし、タイムアウト値とリトライを積極的に設定すると、レイテンシーとパフォーマンスを一定に維持できます。AWS SDK には、特定のアプリケーションの許容値に調整できる設定可能なタイムアウト値と再試行値があります。

AWS Common Runtime (CRT) ライブラリと最適な Amazon EC2 インスタンスタイプを使用していますか。

多数の読み取りおよび書き込みオペレーションを実行するアプリケーションは、そうでないアプリケーションに比べて、より多くのメモリやコンピューティング容量を必要とする可能性があります。コンピューティングを多用するワークロードのために Amazon EC2 インスタンスを起動する際は、アプリケーションが必要とする量のリソースを持つインスタンスタイプを選択します。S3 Express One Zone の高パフォーマンスストレージは、システムメモリ容量が大きく、高パフォーマンスストレージを活用できるより強力な CPU や GPU を備えた、より大規模で新しいインスタンスタイプと組み合わせるのが理想的です。また、CRT が有効になっている AWS SDK の最新バージョンを使用することをお勧めします。これにより、読み取りリクエストと書き込みリクエストの並列処理をより高速化できます。

セッションベースの認証に AWS SDK を使用していますか。

Amazon S3 では、AWS SDK と同じベストプラクティスに従うことで、HTTP REST API リクエストを使用する際のパフォーマンスを最適化することもできます。ただし、S3 Express One Zone で使用されているセッションベースの認可および認証メカニズムの場合、AWS SDK を使用して CreateSession およびそのマネージドセッショントークンを管理することを強くお勧めします。AWS SDK は CreateSession API オペレーションを使用して、ユーザーに代わってトークンの作成と更新を自動的に行います。CreateSession を使用すると、各リクエストを承認するための AWS Identity and Access Management (IAM) へのリクエストごとの往復のレイテンシーを回避できます。

ディレクトリバケットオペレーションとディレクトリインタラクションの例

以下に、ディレクトリバケットの仕組みに関する 3 つの例を示します。

例 1: ディレクトリバケットへの S3 PutObjectリクエストがディレクトリとやり取りする方法

  1. 空のバケットで PUT(<bucket>, "documents/reports/quarterly.txt") オペレーションが実行されると、バケットのルートにディレクトリ documents/ が作成され、documents/ 内にディレクトリ reports/ が作成され、reports/ 内にオブジェクト quarterly.txt が作成されます。このオペレーションでは、オブジェクトに加えて 2 つのディレクトリが作成されました。

    documents/reports/quarterly.txt の PUT オペレーション後のディレクトリ構造を示す図
  2. 次に、別のオペレーション PUT(<bucket>, "documents/logs/application.txt") が実行されると、 ディレクトリ documents/ は既に存在し、documents/ 内にディレクトリ logs/ が存在しないため新たに作成され、logs/ 内にオブジェクト application.txt が作成されます。このオペレーションでは、オブジェクトに加えて作成されたディレクトリは 1 つだけです。

    documents/logs/application.txt の PUT オペレーション後のディレクトリ構造を示す図
  3. 最後に、PUT(<bucket>, "documents/readme.txt") オペレーションが実行されると、ルート内のディレクトリ documents/ が既に存在し、オブジェクト readme.txt が作成されます。このオペレーションでは、ディレクトリは作成されません。

    documents/readme.txt の PUT オペレーション後のディレクトリ構造を示す図

例 2: ディレクトリバケットへの S3 ListObjectsV2 リクエストがディレクトリとやり取りする方法

区切り文字を指定しない S3 ListObjectsV2 リクエストの場合、バケットは深さ優先方式でトラバースされます。出力は一貫した順序で返されます。ただし、この順序はリクエスト間で同じですが、辞書順ではありません。前の例で作成したバケットとディレクトリの場合:

  1. LIST(<bucket>) が実行されると、ディレクトリ documents/ に入り、トラバースが開始されます。

  2. サブディレクトリ logs/ に入り、トラバースが開始されます。

  3. オブジェクト application.txtlogs/ 内に見つかります。

  4. logs/ 内にはこれ以上エントリが存在しません。List オペレーションは logs/ を終了し、再び documents/ に入ります。

  5. documents/ ディレクトリは引き続きトラバースされ、オブジェクト readme.txt が見つかります。

  6. documents/ ディレクトリは引き続きトラバースされ、サブディレクトリ reports/ に入り、トラバースが開始されます。

  7. オブジェクト quarterly.txtreports/ 内に見つかります。

  8. reports/ 内にはこれ以上エントリが存在しません。リストは reports/ を出て、再び documents/ に入ります。

  9. documents/ 内にはこれ以上のエントリがないので、リストは戻ります。

この例では、logs/readme.txt よりも前に順序付けられ、readme.txtreports/ よりも前に順序付けられています。

例 3: ディレクトリバケットへの S3 DeleteObject リクエストがディレクトリとやり取りする方法

DELETE オペレーション前の初期ディレクトリ構造を示す図
  1. 同じバケットで、DELETE(<bucket>, "documents/reports/quarterly.txt") オペレーションを実行すると、オブジェクト quarterly.txt が削除され、ディレクトリ reports/ が空になり、即座に削除されます。documents/ ディレクトリにはディレクトリ logs/ とオブジェクト readme.txt の両方があり、ディレクトリは空ではないため、削除されません。このオペレーションでは、1 つのオブジェクトと 1 つのディレクトリのみが削除されました。

    documents/reports/quarterly.txt に対する DELETE オペレーション後のディレクトリ構造を示す図
  2. DELETE(<bucket>, "documents/readme.txt") オペレーションが実行されると、オブジェクト readme.txt は削除されます。documents/ にはディレクトリ logs/ があり空ではないため、削除されません。このオペレーションでは、ディレクトリは削除されず、オブジェクトのみが削除されます。

    documents/readme.txt に対する DELETE オペレーション後のディレクトリ構造を示す図
  3. 最後に、オペレーション DELETE(<bucket>, "documents/logs/application.txt") が実行されると、application.txt は削除され、logs/ が空になり、即座に削除されます。これにより documents/ も空になり、これも即座に削除されます。このオペレーションでは、2 つのディレクトリと 1 つのオブジェクトが削除されます。バケットが空になりました。

    documents/logs/application.txt に対する DELETE オペレーション後のディレクトリ構造を示す図