.NET を使用したアップロードとダウンロードのパフォーマンス チューニング

アプリケーションが .NET 用 Azure Storage クライアント ライブラリを使ってデータを転送する場合、要求の速度、メモリ使用量、さらには成功または失敗に影響を与える可能性のあるいくつかの要因があります。 データ転送のパフォーマンスと信頼性を最大にするには、アプリが実行される環境に基づいて、クライアント ライブラリ転送オプションを事前に構成することが重要です。

この記事では、データ転送オプションのチューニングに関するいくつかの考慮事項について説明します。このガイダンスは、StorageTransferOptions をパラメーターとして受け入れるすべての API に適用されます。 クライアント ライブラリを適切にチューニングすると、複数の要求にデータを効率的に分散できるため、操作速度、メモリ使用量、ネットワークの安定性が向上する可能性があります。

StorageTransferOptions でのパフォーマンス チューニング

StorageTransferOptions の値を適切にチューニングすることは、データ転送操作の信頼性の高いパフォーマンスにとって重要です。 ストレージ転送は、この構造体のインスタンスで定義されているプロパティ値に基づいて、複数のサブ転送にパーティション分割されます。 サポートされる最大転送サイズは、操作とサービスのバージョンによって異なるため、ドキュメントを調べて制限を確認してください。 Blob Storage での転送サイズの制限について詳しくは、「BLOB ストレージのスケール ターゲット」をご覧ください。

StorageTransferOptions の次のプロパティは、アプリのニーズに基づいてチューニングできます。

Note

StorageTransferOptions 構造体には null 許容値が含まれていますが、クライアント ライブラリでは、指定されていない各個別値については既定値が使われます。 通常、これらの既定値は、データ センター環境でのパフォーマンスは優れていますが、ホーム コンシューマー環境には適していない可能性があります。 StorageTransferOptions のチューニングが不十分な場合、操作が非常に長くなる可能性があり、要求がタイムアウトすることさえあります。 StorageTransferOptions の値を事前にテストし、アプリケーションと環境のニーズに基づいてチューニングすることをお勧めします。

InitialTransferSize

InitialTransferSize は、最初の範囲要求のサイズ (バイト単位) です。 HTTP 範囲要求は部分的な要求であり、この場合は InitialTransferSize によって定義されたサイズです。 このサイズより小さい BLOB は、1 つの要求で転送されます。 このサイズより大きい BLOB は、サイズ MaximumTransferSize のチャンクで転送され続けます。

MaximumTransferSize で指定する値により、InitialTransferSize に対して定義する値は "制限されない" ことに注意してください。 InitialTransferSize では、操作全体をサブ転送なしで一度に実行するための、最初の要求に対する個別のサイズ制限を定義します。 多くの場合、InitialTransferSize は、MaximumTransferSize に対して定義した値より大きくはないにしても、"少なくとも" それと同じ大きさにする必要があります。 データ転送のサイズによっては、このようにすると、転送が 1 つの要求で完了し、複数の要求のオーバーヘッドが回避されるため、パフォーマンスが向上する可能性があります。

状況に最適な値がわからない場合は、MaximumTransferSize に使われているのと同じ値に InitialTransferSize を設定するのが安全なオプションです。

Note

BlobClient オブジェクトを使うと、InitialTransferSize より小さい BLOB のアップロードは、Put Block ではなく Put Blob を使って実行されます。

MaximumConcurrency

MaximumConcurrency は、並列転送で使用できるワーカーの最大数です。 現在、転送を並列化できるのは非同期操作のみです。 同期操作では、この値は無視され、順番に実行されます。

この値の有効性は、.NET での接続プールの制限次第であり、特定のシナリオでは既定値によってパフォーマンスが制限される可能性があります。 .NET での接続プールの制限について詳しくは、「.NET Framework での接続プールの制限と .NET 用の新しい Azure SDK」をご覧ください。

MaximumTransferSize

MaximumTransferSize は、転送の最大長 (バイト単位) です。 前に説明したように、この値によって InitialTransferSize が制限されることは "なく"、MaximumTransferSize より大きくできます。

データ移動の効率性を維持するため、クライアント ライブラリではすべての転送で MaximumTransferSize 値に常に達するとは限りません。 転送サイズでサポートされる最大値は、操作によって異なる場合があります。 たとえば、2019-12-12 以降のサービス バージョンで Put Block 操作を呼び出すブロック BLOB の最大ブロック サイズは 4000 MiB です。 Blob Storage での転送サイズの制限について詳しくは、「BLOB ストレージのスケール ターゲット」の表をご覧ください。

コードの例

クライアント ライブラリの Upload メソッドと UploadAsync メソッドには、BlobUploadOptions パラメーターの一部として StorageTransferOptions インスタンスを受け取るオーバーロードが含まれます。 BlobDownloadToOptions パラメーターを使用する DownloadTo メソッドと DownloadToAsync メソッドにも、同様のオーバーロードが存在します。

次のコード例では、StorageTransferOptions インスタンスの値を定義し、これらの構成オプションをパラメーターとして UploadAsync に渡す方法を示します。 このサンプルで提供される値は、推奨を意図したものではありません。 これらの値を適切にチューニングするには、アプリの特定のニーズを考慮する必要があります。

// Specify the StorageTransferOptions
BlobUploadOptions options = new BlobUploadOptions
{
    TransferOptions = new StorageTransferOptions
    {
        // Set the maximum number of parallel transfer workers
        MaximumConcurrency = 2,

        // Set the initial transfer length to 8 MiB
        InitialTransferSize = 8 * 1024 * 1024,

        // Set the maximum length of a transfer to 4 MiB
        MaximumTransferSize = 4 * 1024 * 1024
    }
};

// Upload data from a stream
await blobClient.UploadAsync(stream, options);

この例では、MaximumConcurrency プロパティを使って、並列転送ワーカーの数を 2 に設定しています。 この構成では、最大 2 つの接続が同時に開かれ、アップロードを並列で実行できます。 最初の HTTP 範囲要求では、InitialTransferSize プロパティで定義されている最大 8 MiB のデータのアップロードが試みられます。 シーク可能ストリームを使っているときは、InitialTransferSize はアップロードのみに適用されることに注意してください。 BLOB のサイズが 8 MiB 未満の場合、操作を完了するために必要な要求は 1 つだけです。 BLOB のサイズが 8 MiB を超える場合は、後続のすべての転送要求の最大サイズは、MaximumTransferSize プロパティで設定されている 4 MiB です。

アップロードのパフォーマンスに関する考慮事項

アップロードでは、ストレージ クライアント ライブラリは、StorageTransferOptions インスタンスで定義されている値に基づいて、特定のアップロード ストリームを複数のサブアップロードに分割します。 REST 操作は、サブアップロードごとに専用の呼び出しで行われます。 BlobClient オブジェクトまたは BlockBlobClient オブジェクトの場合、この操作は Put Block です。 DataLakeFileClient オブジェクトの場合は、この操作は Append Data です。 ストレージ クライアント ライブラリによって、これらの REST 操作が (転送オプションに応じて) 並列に管理されて、完全なアップロードが実行されます。

以下のセクションで説明するように、アップロード ストリームがシーク可能かシーク不可能かに応じて、クライアント ライブラリによるバッファーリングと InitialTransferSize の処理方法が異なります。 シーク可能なストリームとは、ストリーム内の現在位置でのクエリと変更をサポートするストリームです。 .NET でのストリームについて詳しくは、Stream クラスのリファレンスをご覧ください。

Note

ブロック BLOB の最大ブロック数は 50,000 ブロックです。 したがって、ブロック BLOB の最大サイズは MaximumTransferSize の 50,000 倍です。

アップロードの間のバッファーリング

Storage REST レイヤーでは、中断した REST アップロード操作の取得はサポートされていません。転送ごとに完了するか、失われます。 シーク不可能なストリーム アップロードの回復性を確保するため、ストレージ クライアント ライブラリは、アップロードを始める前に、個々の REST 呼び出しごとにデータをバッファーに格納します。 ネットワーク速度の制限だけでなく、このバッファーリング動作も、順番にアップロードする場合であっても、MaximumTransferSize の値を小さくすることを検討すべき理由です。 MaximumTransferSize の値を小さくすると、各要求および失敗した要求の各再試行でバッファーに格納されるデータの最大量が減ります。 あるサイズのデータ転送中にタイムアウトが頻繁に発生する場合は、MaximumTransferSize の値を小さくすると、バッファーリング時間が短縮され、パフォーマンスが向上する可能性があります。

バッファーリングが発生するもう 1 つのシナリオは、ネットワーク スループットを最大にするため、並列 REST 呼び出しでデータをアップロードする場合です。 クライアント ライブラリには並列で読み取ることができるソースが必要であり、ストリームは順次であるため、ストレージ クライアント ライブラリは、アップロードを始める前に、個々の REST 呼び出しのデータをバッファーに格納します。 このバッファーリング動作は、指定したストリームがシーク可能な場合でも発生します。

非同期アップロード呼び出しの間のバッファーリングを回避するには、シーク可能なストリームを指定し、MaximumConcurrency を 1 に設定する必要があります。 この方法はほとんどの状況で機能しますが、バッファーリングを必要とする他のクライアント ライブラリ機能がコードで使われている場合は、やはりバッファーリングが発生する可能性があります。

アップロードでの InitialTransferSize

シーク可能なストリームをアップロードに指定すると、ストリームの長さが InitialTransferSize の値と照合されます。 ストリームの長さがこの値より小さい場合は、StorageTransferOptions の他の値に関係なく、ストリーム全体が 1 つの REST 呼び出しとしてアップロードされます。 それ以外の場合は、前に説明したように、アップロードは複数の部分で行われます。 InitialTransferSize は、シーク不可能なストリームには影響を与えず、無視されます。

ダウンロードのパフォーマンスに関する考慮事項

ダウンロードでは、ストレージ クライアント ライブラリは、StorageTransferOptions インスタンスで定義されている値に基づいて、特定のダウンロード要求を複数のサブダウンロードに分割します。 REST 操作は、サブダウンロードごとに専用の呼び出しで行われます。 転送オプションに応じて、クライアント ライブラリにより、これらの REST 操作が並列に管理されて、完全なダウンロードが実行されます。

ダウンロードの間のバッファーリング

本文の内容で同時に複数の HTTP 応答を受信すると、メモリの使用量に影響します。 しかし、ストレージ クライアント ライブラリでは、ダウンロードされるコンテンツのバッファー ステップは明示的に追加されません。 着信した応答は順番に処理されます。 クライアント ライブラリは、HTTP 応答ストリームから、呼び出し元が提供する宛先ストリームまたはファイル パスへのストリームのコピー用に、16 KB のバッファーを構成します。

ダウンロードでの InitialTransferSize

ダウンロードの間に、ストレージ クライアント ライブラリは、他の操作を行う前に、InitialTransferSize を使ってダウンロード範囲要求を 1 回行います。 この最初のダウンロード要求中に、クライアント ライブラリはリソースの合計サイズを把握します。 最初の要求ですべてのコンテンツが正常にダウンロードされた場合、操作は完了します。 そうでない場合、クライアント ライブラリは、完全なダウンロードが完了するまで、最大 MaximumTransferSize の範囲要求を実行し続けます。

次のステップ