Share via


Ottimizzazione delle prestazioni per caricamenti e download con .NET

Quando un'applicazione trasferisce i dati usando la libreria client Archiviazione di Azure per .NET, esistono diversi fattori che possono influire sulla velocità, sull'utilizzo della memoria e persino sull'esito positivo o negativo della richiesta. Per ottimizzare le prestazioni e l'affidabilità per i trasferimenti di dati, è importante essere proattivi nella configurazione delle opzioni di trasferimento della libreria client in base all'ambiente in cui viene eseguita l'app.

Questo articolo illustra diverse considerazioni per l'ottimizzazione delle opzioni di trasferimento dei dati e le indicazioni si applicano a qualsiasi API accettata StorageTransferOptions come parametro. Se ottimizzata correttamente, la libreria client può distribuire in modo efficiente i dati tra più richieste, con conseguente miglioramento della velocità operativa, dell'utilizzo della memoria e della stabilità di rete.

Ottimizzazione delle prestazioni con Archiviazione TransferOptions

L'ottimizzazione corretta dei valori in Archiviazione TransferOptions è fondamentale per ottenere prestazioni affidabili per le operazioni di trasferimento dei dati. Archiviazione trasferimenti vengono partizionati in diverse sottotrasferizioni in base ai valori delle proprietà definiti in un'istanza di questo struct. Le dimensioni massime di trasferimento supportate variano in base all'operazione e alla versione del servizio, quindi assicurarsi di controllare la documentazione per determinare i limiti. Per altre informazioni sui limiti delle dimensioni di trasferimento per l'archiviazione BLOB, vedere Destinazioni di scalabilità per l'archiviazione BLOB.

Le proprietà seguenti di StorageTransferOptions possono essere ottimizzate in base alle esigenze dell'app:

Nota

Mentre lo StorageTransferOptions struct contiene valori nullable, le librerie client useranno le impostazioni predefinite per ogni singolo valore, se non specificato. Queste impostazioni predefinite sono in genere efficienti in un ambiente data center, ma non sono adatte per gli ambienti consumer domestici. L'ottimizzazione non corretta StorageTransferOptions può comportare operazioni eccessivamente lunghe e persino timeout delle richieste. È consigliabile essere proattivi nel testare i valori in StorageTransferOptionse ottimizzarli in base alle esigenze dell'applicazione e dell'ambiente.

InitialTransferSize

InitialTransferSize è la dimensione della prima richiesta di intervallo in byte. Una richiesta di intervallo HTTP è una richiesta parziale, con le dimensioni definite da InitialTransferSize in questo caso. I BLOB inferiori a queste dimensioni vengono trasferiti in una singola richiesta. I BLOB maggiori di queste dimensioni continuano a essere trasferiti in blocchi di dimensioni MaximumTransferSize.

È importante notare che il valore specificato per MaximumTransferSizenon limita il valore definito per InitialTransferSize. InitialTransferSize definisce una limitazione delle dimensioni separata per una richiesta iniziale per eseguire l'intera operazione contemporaneamente, senza subtransfer. È spesso il caso in cui si vuole InitialTransferSize essere almeno grandi quanto il valore definito per MaximumTransferSize, se non è più grande. A seconda delle dimensioni del trasferimento dei dati, questo approccio può essere più efficiente, poiché il trasferimento viene completato con una singola richiesta ed evita il sovraccarico di più richieste.

Se non si è certi del valore migliore per la situazione, un'opzione sicura consiste nell'impostare InitialTransferSize sullo stesso valore usato per MaximumTransferSize.

Nota

Quando si usa un BlobClient oggetto , il caricamento di un BLOB più piccolo rispetto a InitialTransferSize verrà eseguito usando Put Blob, anziché Put Block.

MaximumConcurrency

MaximumConcurrency è il numero massimo di ruoli di lavoro che possono essere usati in un trasferimento parallelo. Attualmente, solo le operazioni asincrone possono parallelizzare i trasferimenti. Le operazioni sincrone ignorano questo valore e funzionano in sequenza.

L'efficacia di questo valore è soggetta ai limiti del pool di connessioni in .NET, che può limitare le prestazioni per impostazione predefinita in determinati scenari. Per altre informazioni sui limiti del pool di connessioni in .NET, vedere Limiti del pool di Connessione ion di .NET Framework e il nuovo Azure SDK per .NET.

MaximumTransferSize

MaximumTransferSize è la lunghezza massima di un trasferimento in byte. Come accennato in precedenza, questo valore non limita InitialTransferSize, che può essere maggiore di MaximumTransferSize.

Per mantenere in modo efficiente lo spostamento dei dati, le librerie client potrebbero non raggiungere sempre il MaximumTransferSize valore per ogni trasferimento. A seconda dell'operazione, il valore massimo supportato per le dimensioni del trasferimento può variare. Ad esempio, i BLOB in blocchi che chiamano l'operazione Put Block con una versione del servizio 2019-12-12 o successiva hanno una dimensione massima del blocco di 4000 MiB. Per altre informazioni sui limiti delle dimensioni di trasferimento per l'archiviazione BLOB, vedere il grafico Destinazioni di scalabilità per l'archiviazione BLOB.

Esempio di codice

La libreria client include overload per i Upload metodi eUploadAsync, che accettano un'istanza di Archiviazione TransferOptions come parte di un parametro BlobUploadOptions. Esistono anche overload simili per i DownloadTo metodi e DownloadToAsync usando un parametro BlobDownloadToOptions .

Nell'esempio di codice seguente viene illustrato come definire i valori per un'istanza StorageTransferOptions e passare queste opzioni di configurazione come parametro a UploadAsync. I valori forniti in questo esempio non devono essere consigliati. Per ottimizzare correttamente questi valori, è necessario considerare le esigenze specifiche dell'app.

// 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 questo esempio viene impostato il numero di ruoli di lavoro di trasferimento paralleli su 2, usando la MaximumConcurrency proprietà . Questa configurazione si apre contemporaneamente a due connessioni, consentendo il caricamento in parallelo. La richiesta di intervallo HTTP iniziale tenta di caricare fino a 8 MiB di dati, come definito dalla InitialTransferSize proprietà . Si noti che InitialTransferSize si applica solo per i caricamenti quando si usa un flusso ricercabile. Se le dimensioni del BLOB sono inferiori a 8 MiB, è necessaria solo una singola richiesta per completare l'operazione. Se le dimensioni del BLOB sono maggiori di 8 MiB, tutte le richieste di trasferimento successive hanno una dimensione massima di 4 MiB, impostata con la MaximumTransferSize proprietà .

Considerazioni sulle prestazioni per i caricamenti

Durante un caricamento, le librerie client Archiviazione suddivideno un determinato flusso di caricamento in più sottoupload in base ai valori definiti nell'istanzaStorageTransferOptions. Ogni sottoupload ha una propria chiamata dedicata all'operazione REST. Per un oggetto o BlockBlobClient un BlobClient oggetto, questa operazione è Put Block. Per un DataLakeFileClient oggetto, questa operazione è Append Data. La libreria client Archiviazione gestisce queste operazioni REST in parallelo (a seconda delle opzioni di trasferimento) per completare il caricamento completo.

A seconda che il flusso di caricamento sia ricercabile o non ricercabile, la libreria client gestisce il buffering e InitialTransferSize in modo diverso, come descritto nelle sezioni seguenti. Un flusso ricercabile è un flusso che supporta l'esecuzione di query e la modifica della posizione corrente all'interno di un flusso. Per altre informazioni sui flussi in .NET, vedere le informazioni di riferimento sulla classe Stream.

Nota

I BLOB in blocchi hanno un numero massimo di blocchi di 50.000 blocchi. Le dimensioni massime del BLOB in blocchi, quindi, sono 50.000 volte MaximumTransferSize.

Memorizzazione nel buffer durante i caricamenti

Il livello REST Archiviazione non supporta la raccolta di un'operazione di caricamento REST in cui è stata interrotta. I singoli trasferimenti vengono completati o persi. Per garantire la resilienza per i caricamenti di flussi non ricercabili, i dati del buffer delle librerie client Archiviazione per ogni singola chiamata REST prima di avviare il caricamento. Oltre alle limitazioni della velocità di rete, questo comportamento di buffering è un motivo per considerare un valore più piccolo per MaximumTransferSize, anche quando si carica in sequenza. La riduzione del valore di MaximumTransferSize riduce la quantità massima di dati memorizzati nel buffer per ogni richiesta e ogni nuovo tentativo di una richiesta non riuscita. Se si verificano timeout frequenti durante i trasferimenti di dati di una determinata dimensione, riducendo il valore di riduce il tempo di MaximumTransferSize memorizzazione nel buffer e può comportare prestazioni migliori.

Un altro scenario in cui si verifica il buffering è quando si caricano dati con chiamate REST parallele per ottimizzare la velocità effettiva di rete. Le librerie client necessitano di origini che possono leggere in parallelo e poiché i flussi sono sequenziali, le librerie client Archiviazione memorizzano nel buffer i dati per ogni singola chiamata REST prima di avviare il caricamento. Questo comportamento di buffering si verifica anche se il flusso fornito è ricercabile.

Per evitare il buffering durante una chiamata di caricamento asincrona, è necessario fornire un flusso ricercabile e impostare su MaximumConcurrency 1. Anche se questa strategia dovrebbe funzionare nella maggior parte delle situazioni, è comunque possibile che il buffering si verifichi se il codice usa altre funzionalità della libreria client che richiedono il buffering.

InitialTransferSize al caricamento

Quando viene fornito un flusso ricercabile per il caricamento, la lunghezza del flusso viene verificata rispetto al valore di InitialTransferSize. Se la lunghezza del flusso è minore di questo valore, l'intero flusso viene caricato come singola chiamata REST, indipendentemente dagli altri StorageTransferOptions valori. In caso contrario, il caricamento viene eseguito in più parti, come descritto in precedenza. InitialTransferSize non ha alcun effetto su un flusso non ricercabile e viene ignorato.

Considerazioni sulle prestazioni per i download

Durante un download, le librerie client Archiviazione suddivideno una determinata richiesta di download in più download secondari in base ai valori definiti nell'istanzaStorageTransferOptions. Ogni sottodownload ha una propria chiamata dedicata all'operazione REST. A seconda delle opzioni di trasferimento, le librerie client gestiscono queste operazioni REST in parallelo per completare il download completo.

Memorizzazione nel buffer durante i download

La ricezione simultanea di più risposte HTTP con il contenuto del corpo ha implicazioni per l'utilizzo della memoria. Tuttavia, le librerie client Archiviazione non aggiungono in modo esplicito un passaggio del buffer per il contenuto scaricato. Le risposte in ingresso vengono elaborate in ordine. Le librerie client configurano un buffer da 16 kilobyte per la copia di flussi da un flusso di risposta HTTP a un flusso di destinazione o a un percorso di file fornito dal chiamante.

InitialTransferSize al download

Durante un download, le librerie client Archiviazione effettuano una richiesta di intervallo di download usando InitialTransferSize prima di eseguire qualsiasi altra operazione. Durante questa richiesta di download iniziale, le librerie client conoscono le dimensioni totali della risorsa. Se la richiesta iniziale ha scaricato tutto il contenuto, l'operazione viene completata. In caso contrario, le librerie client continuano a effettuare richieste di intervallo fino al MaximumTransferSize completamento del download completo.

Passaggi successivi