Leistungsoptimierung für Uploads und Downloads mit .NET

Wenn eine Anwendung Daten unter Verwendung der Azure Storage-Clientbibliothek für .NET überträgt, gibt es mehrere Faktoren, die sich auf die Geschwindigkeit, die Arbeitsspeicherauslastung und sogar auf den Erfolg der Anforderung auswirken können. Um die Leistung und Zuverlässigkeit bei Datenübertragungen zu maximieren, ist es wichtig, proaktiv die Übertragungsoptionen für Clientbibliotheken basierend auf der Umgebung zu konfigurieren, in der Ihre App ausgeführt wird.

In diesem Artikel werden mehrere Überlegungen zur Optimierung von Datenübertragungsoptionen erläutert. Der Leitfaden gilt für alle APIs, die StorageTransferOptions als Parameter akzeptieren. Bei ordnungsgemäßer Optimierung kann die Clientbibliothek Daten effizient auf mehrere Anforderungen verteilen, um die Betriebsgeschwindigkeit, Arbeitsspeicherauslastung und Netzwerkstabilität zu verbessern.

Leistungsoptimierung mit StorageTransferOptions

Die ordnungsgemäße Optimierung der Werte in StorageTransferOptions ist der Schlüssel zu zuverlässiger Leistung bei Datenübertragungsvorgängen. Speicherübertragungen werden basierend auf den Eigenschaftswerten, die in einer Instanz dieser Struktur definiert sind, in mehrere Teilübertragungen unterteilt. Die maximale unterstützte Übertragungsgröße variiert je nach Vorgang und Dienstversion. Überprüfen Sie daher unbedingt die Dokumentation, um die Grenzwerte zu ermitteln. Weitere Informationen zu Grenzwerten im Zusammenhang mit Übertragungsgröße für Blob Storage finden Sie unter Skalierbarkeitsziele für Blob Storage.

Die folgenden Eigenschaften von StorageTransferOptions können basierend auf den Anforderungen Ihrer App optimiert werden:

Hinweis

Die Struktur StorageTransferOptions lässt zwar Nullwerte zu, die Clientbibliotheken verwenden jedoch Standardwerte für die einzelnen Werte, wenn kein Wert angegeben wird. Mit diesen Standardwerten lässt sich zwar in der Regel in einer Rechenzentrumsumgebung eine hohe Leistung erzielen, für Umgebungen von Privatanwendern sind sie jedoch eher nicht geeignet. Eine mangelhafte Optimierung von StorageTransferOptions kann zu übermäßig langen Vorgängen und sogar zu Anforderungstimeouts führen. Es empfiehlt sich, die Werte in StorageTransferOptions proaktiv zu testen und sie basierend auf den Anforderungen Ihrer Anwendung und Umgebung zu optimieren.

InitialTransferSize

InitialTransferSize ist die Größe der ersten Bereichsanforderung in Bytes. Eine HTTP-Bereichsanforderung ist eine partielle Anforderung, deren Größe in diesem Fall durch InitialTransferSize definiert ist. Blobs mit einer geringeren Größe werden in einer einzelnen Anforderung übertragen. Größere Blobs werden weiterhin in Blöcken mit der Größe MaximumTransferSize übertragen.

Wichtig: Der für InitialTransferSize definierte Wert wird nicht durch den für MaximumTransferSize angegebenen Wert eingeschränkt. InitialTransferSize definiert eine separate Größenbeschränkung für eine erste Anforderung, um den gesamten Vorgang auf einmal und ohne Teilübertragungen auszuführen. InitialTransferSize sollte häufig mindestens so groß sein wie der für MaximumTransferSize definierte Wert. Abhängig von der Größe der Datenübertragung kann dieser Ansatz leistungsfähiger sein, da die Übertragung im Rahmen einer einzelnen Anforderung erfolgt und den mit mehreren Anforderungen verbundenen Mehraufwand vermeidet.

Sollten Sie unsicher sein, welcher Wert für Ihre Situation am besten geeignet ist, empfiehlt es sich, InitialTransferSize auf den für MaximumTransferSize verwendeten Wert festzulegen.

Hinweis

Bei Verwendung eines BlobClient-Objekts werden Blobs, die kleiner sind als InitialTransferSize, nicht mithilfe von Put Block, sondern mithilfe von Put Blob hochgeladen.

MaximumConcurrency

MaximumConcurrency ist die maximale Anzahl von Workern, die in einer parallelen Übertragung verwendet werden können. Derzeit können Übertragungen nur in asynchronen Vorgängen parallelisiert werden. Bei synchronen Vorgängen wird dieser Wert ignoriert und eine sequenzielle Ausführung verwendet.

Die Effektivität dieses Werts hängt von den Grenzwerten für Verbindungspools in .NET ab, die in bestimmten Szenarien standardmäßig die Leistung einschränken. Weitere Informationen zu den Grenzwerten für Verbindungspools in .NET finden Sie unter Grenzwerte für Verbindungspools in .NET Framework und das neue Azure SDK für .NET.

MaximumTransferSize

MaximumTransferSize ist die maximale Länge einer Übertragung in Bytes. InitialTransferSize wird wie bereits erwähnt nicht durch diesen Wert eingeschränkt und kann größer sein als MaximumTransferSize.

Zur Gewährleistung eines effizienten Datenflusses erreichen die Clientbibliotheken möglicherweise nicht bei jeder Übertragung den Wert von MaximumTransferSize. Je nach Vorgang kann der unterstützte Maximalwert für die Übertragungsgröße variieren. Bei Blockblobs, die den Vorgang Put Block mit der Dienstversion 2019-12-12 oder mit einer höheren Version aufrufen, beträgt die maximale Blockgröße beispielsweise 4.000 MiB. Weitere Informationen zu Grenzwerten im Zusammenhang mit der Übertragungsgröße für Blob Storage finden Sie im Diagramm unter Skalierbarkeitsziele für Blob Storage.

Codebeispiel

Die Clientbibliothek enthält Überladungen für die Methoden Upload und UploadAsync, die eine StorageTransferOptions-Instanz als Teil eines BlobUploadOptions-Parameters akzeptieren. Ähnliche Überladungen sind auch für die Methoden DownloadTo und DownloadToAsync verfügbar. Hier wird ein BlobDownloadToOptions-Parameter verwendet.

Das folgende Codebeispiel zeigt, wie Sie Werte für eine StorageTransferOptions-Instanz definieren und diese Konfigurationsoptionen als Parameter an UploadAsync übergeben. Die in diesem Beispiel angegebenen Werte sind nicht als Empfehlungen zu verstehen. Zur ordnungsgemäßen Optimierung dieser Werte müssen die spezifischen Anforderungen Ihrer App berücksichtigt werden.

// 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);

In diesem Beispiel wird die Anzahl von Workern für die parallele Übertragung mithilfe der Eigenschaft MaximumConcurrency auf „2“ festgelegt. Bei dieser Konfiguration werden bis zu zwei Verbindungen gleichzeitig geöffnet, um einen parallelen Uploadvorgang zu ermöglichen. Von der anfänglichen HTTP-Bereichsanforderung wird versucht, bis zu 8 MiB an Daten hochzuladen, wie durch die Eigenschaft InitialTransferSize definiert. Beachten Sie, dass InitialTransferSize nur bei Verwendung eines suchbaren Datenstroms für Uploads gilt. Wenn das Blob kleiner als 8 MiB ist, ist für den Vorgang nur eine einzelne Anforderung erforderlich. Ist das Blob größer als 8 MiB, haben alle nachfolgenden Übertragungsanforderungen eine maximale Größe von 4 MiB, wie durch die Eigenschaft MaximumTransferSize festgelegt.

Überlegungen zur Leistung bei Uploads

Während eines Uploads teilen die Storage-Clientbibliotheken einen Uploaddatenstrom basierend auf den in der StorageTransferOptions-Instanz definierten Werten in mehrere Teiluploads auf. Jeder Teilupload verfügt über einen eigenen dedizierten Aufruf des REST-Vorgangs. Bei einem Objekt vom Typ BlobClient oder BlockBlobClient wird der Vorgang Put Block verwendet. Bei einem DataLakeFileClient-Objekt wird der Vorgang Append Data verwendet. Die Storage-Clientbibliothek verwaltet diese REST-Vorgänge parallel (abhängig von den Übertragungsoptionen), um den gesamten Upload abzuschließen.

Die Behandlung von Pufferung und InitialTransferSize durch die Clientbibliothek ist abhängig vom Suchbarkeitsstatus des Uploaddatenstroms, wie in den folgenden Abschnitten beschrieben. Ein suchbarer Datenstrom ist ein Datenstrom, der das Abfragen und Ändern der aktuellen Position in einem Datenstrom unterstützt. Weitere Informationen zu Datenströmen in .NET finden Sie in der Referenz zur Stream-Klasse.

Hinweis

Blockblobs haben eine maximale Blockanzahl von 50.000 Blöcken. Die maximale Größe Ihres Blockblobs entspricht also 50.000 mal MaximumTransferSize.

Puffern bei Uploads

Das Fortsetzen angehaltener REST-Uploadvorgänge wird von der Storage-REST-Ebene nicht unterstützt. Einzelne Übertragungen werden entweder abgeschlossen oder gehen verloren. Um Resilienz für nicht suchbare Datenstromuploads zu gewährleisten, puffern die Storage-Clientbibliotheken Daten für jeden einzelnen REST-Aufruf vor dem Start des Uploads. Neben den Einschränkungen durch die Netzwerkgeschwindigkeit ist dieses Pufferverhalten ein Grund dafür, einen kleineren Wert für MaximumTransferSize in Betracht zu ziehen, auch wenn Uploadvorgänge nacheinander ausgeführt werden. Durch Verringern des Werts von MaximumTransferSize verringert sich die maximale Datenmenge, die für die einzelnen Anforderungen bzw. für Wiederholungsversuche bei fehlerhaften Anforderungen gepuffert wird. Falls bei Datenübertragungen mit einer bestimmten Größe häufig Timeouts auftreten, verringert die Senkung des Werts von MaximumTransferSize die Pufferzeit, was wiederum die Leistung verbessern kann.

Ein weiteres Szenario mit Pufferung ist das Hochladen von Daten mit parallelen REST-Aufrufen zur Maximierung des Netzwerkdurchsatzes. Die Clientbibliotheken benötigen Quellen, aus denen sie parallel lesen können. Da Datenströme sequenziell sind, werden die Daten für jeden einzelnen REST-Aufruf vor dem Start des Uploads gepuffert. Dieses Pufferverhalten tritt auch auf, wenn der bereitgestellte Datenstrom suchbar ist.

Um das Puffern während eines asynchronen Uploadaufrufs zu vermeiden, müssen Sie einen suchbaren Datenstrom bereitstellen und MaximumConcurrency auf „1“ festlegen. Diese Strategie sollte in den meisten Situationen funktionieren. Sollte Ihr Code allerdings andere Clientbibliotheksfeatures verwenden, die eine Pufferung erfordern, kann es sein, dass trotzdem Daten gepuffert werden.

InitialTransferSize beim Hochladen

Wenn für den Upload ein suchbarer Datenstrom bereitgestellt wird, wird die Datenstromlänge anhand des Werts von InitialTransferSize überprüft. Ist die Datenstromlänge geringer als dieser Wert, wird der gesamte Datenstrom unabhängig von anderen StorageTransferOptions-Werten als einzelner REST-Aufruf hochgeladen. Andernfalls wird der Upload wie zuvor beschrieben aufgeteilt. Bei einem nicht suchbaren Datenstrom hat InitialTransferSize keine Auswirkung und wird ignoriert.

Überlegungen zur Leistung bei Downloads

Während eines Downloads teilen die Storage-Clientbibliotheken eine Downloadanforderung basierend auf den in der StorageTransferOptions-Instanz definierten Werten in mehrere Teildownloads auf. Jeder Teildownload verfügt über einen eigenen dedizierten Aufruf des REST-Vorgangs. Abhängig von den Übertragungsoptionen verwalten die Clientbibliotheken die REST-Vorgänge parallel, um den gesamten Download abzuschließen.

Puffern bei Downloads

Das gleichzeitige Empfangen mehrerer HTTP-Antworten mit Textinhalten hat Auswirkungen auf die Speicherauslastung. Von den Storage-Clientbibliotheken wird jedoch nicht explizit ein Pufferschritt für heruntergeladene Inhalte hinzugefügt. Eingehende Antworten werden der Reihe nach verarbeitet. Die Clientbibliotheken konfigurieren einen 16-KB-Puffer für das Kopieren von Datenströmen aus einem HTTP-Antwortdatenstrom in einen vom Aufrufer bereitgestellten Zieldatenstrom oder Dateipfad.

InitialTransferSize beim Herunterladen

Während eines Downloads übermitteln die Storage-Clientbibliotheken zunächst eine einzelne Downloadbereichsanforderung mithilfe von InitialTransferSize. Während dieser ersten Downloadanforderung ist den Clientbibliotheken die Gesamtgröße der Ressource bekannt. Wenn der gesamte Inhalt im Rahmen der anfänglichen Anforderung erfolgreich heruntergeladen wurde, ist der Vorgang abgeschlossen. Andernfalls übermitteln die Clientbibliotheken weiterhin Bereichsanforderungen (bis maximal MaximumTransferSize), bis der gesamte Download abgeschlossen ist.

Nächste Schritte