Ajuste de desempenho para uploads e downloads com .NET

Quando um aplicativo transfere dados usando a biblioteca de cliente do Armazenamento do Azure para .NET, há vários fatores que podem afetar a velocidade, o uso de memória e até mesmo o sucesso ou falha da solicitação. Para maximizar o desempenho e a confiabilidade das transferências de dados, é importante ser proativo na configuração das opções de transferência da biblioteca do cliente com base no ambiente em que seu aplicativo é executado.

Este artigo apresenta várias considerações para ajustar as opções de transferência de dados, e as diretrizes se aplicam a qualquer API que aceite StorageTransferOptions como parâmetro. Quando ajustada corretamente, a biblioteca do cliente pode distribuir dados de forma eficiente entre várias solicitações, o que pode resultar em maior velocidade de operação, uso de memória e estabilidade de rede.

Ajuste de desempenho com StorageTransferOptions

Ajustar corretamente os valores em StorageTransferOptions é a chave para um desempenho confiável para operações de transferência de dados. As transferências de armazenamento são particionadas em várias subtransferências com base nos valores de propriedade definidos em uma instância desta estrutura. O tamanho máximo de transferência suportado varia de acordo com a operação e a versão do serviço, portanto, certifique-se de verificar a documentação para determinar os limites. Para obter mais informações sobre limites de tamanho de transferência para armazenamento de Blob, consulte Dimensionar destinos para armazenamento de Blob.

As seguintes propriedades do StorageTransferOptions podem ser ajustadas com base nas necessidades do seu aplicativo:

Nota

Embora o StorageTransferOptions struct contenha valores anuláveis, as bibliotecas de cliente usarão padrões para cada valor individual, se não forem fornecidos. Esses padrões geralmente têm desempenho em um ambiente de data center, mas provavelmente não são adequados para ambientes de consumidores domésticos. Mal ajustado StorageTransferOptions pode resultar em operações excessivamente longas e até mesmo tempos limite de solicitação. É melhor ser proativo ao testar os valores no e ajustá-los com base nas StorageTransferOptionsnecessidades do seu aplicativo e ambiente.

InitialTransferSize

InitialTransferSize é o tamanho da primeira solicitação de intervalo em bytes. Uma solicitação de intervalo HTTP é uma solicitação parcial, com o tamanho definido por InitialTransferSize neste caso. Blobs menores que esse tamanho são transferidos em uma única solicitação. Blobs maiores que esse tamanho continuam a ser transferidos em pedaços de tamanho MaximumTransferSize.

É importante observar que o valor especificado para MaximumTransferSize não limita o valor definido para InitialTransferSize. InitialTransferSize Define uma limitação de tamanho separada para uma solicitação inicial para executar toda a operação de uma só vez, sem subtransferências. Muitas vezes, você quer InitialTransferSize ser pelo menos tão grande quanto o valor definido para MaximumTransferSize, se não maior. Dependendo do tamanho da transferência de dados, essa abordagem pode ser mais eficiente, pois a transferência é concluída com uma única solicitação e evita a sobrecarga de várias solicitações.

Se você não tiver certeza de qual valor é melhor para sua situação, uma opção segura é definir InitialTransferSize para o mesmo valor usado para MaximumTransferSize.

Nota

Ao usar um BlobClient objeto, o upload de um blob menor que o InitialTransferSize será executado usando Put Blob, em vez de Put Block.

MaximumConcurrency

MaximumConcurrency é o número máximo de trabalhadores que podem ser usados em uma transferência paralela. Atualmente, apenas operações assíncronas podem paralelizar transferências. As operações síncronas ignoram esse valor e funcionam em sequência.

A eficácia desse valor está sujeita aos limites do pool de conexões no .NET, que podem restringir o desempenho por padrão em determinados cenários. Para saber mais sobre os limites do pool de conexões no .NET, consulte Limites do pool de conexões do .NET Framework e o novo SDK do Azure para .NET.

MaximumTransferSize

MaximumTransferSize é o comprimento máximo de uma transferência em bytes. Como mencionado anteriormente, este valor não limita InitialTransferSize, que pode ser maior do que MaximumTransferSize.

Para manter os dados em movimento de forma eficiente, as bibliotecas de cliente nem sempre atingem o valor de MaximumTransferSize cada transferência. Dependendo da operação, o valor máximo suportado para o tamanho da transferência pode variar. Por exemplo, blobs de bloco que chamam a operação Put Block com uma versão de serviço de 2019-12-12 ou posterior têm um tamanho máximo de bloco de 4000 MiB. Para obter mais informações sobre limites de tamanho de transferência para armazenamento de Blob, consulte o gráfico em Dimensionar destinos para armazenamento de Blob.

Exemplo de código

A biblioteca de cliente inclui sobrecargas para os métodos e UploadAsync , que aceitam uma instância StorageTransferOptions como parte de um parâmetro BlobUploadOptions.Upload Sobrecargas semelhantes também existem para os DownloadTo métodos e DownloadToAsync usando um parâmetro BlobDownloadToOptions .

O exemplo de código a seguir mostra como definir valores para uma StorageTransferOptions instância e passar essas opções de configuração como um parâmetro para UploadAsync. Os valores fornecidos neste exemplo não pretendem ser uma recomendação. Para ajustar corretamente esses valores, você precisa considerar as necessidades específicas do seu aplicativo.

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

Neste exemplo, definimos o número de trabalhadores de transferência paralela como 2, usando a MaximumConcurrency propriedade. Esta configuração abre até duas conexões simultaneamente, permitindo que o upload aconteça em paralelo. A solicitação inicial de intervalo HTTP tenta carregar até 8 MiB de dados, conforme definido pela InitialTransferSize propriedade. Observe que InitialTransferSize só se aplica a uploads ao usar um fluxo pesquisável. Se o tamanho do blob for menor que 8 MiB, apenas uma única solicitação será necessária para concluir a operação. Se o tamanho do blob for maior que 8 MiB, todas as solicitações de transferência subsequentes terão um tamanho máximo de 4 MiB, que definimos com a MaximumTransferSize propriedade.

Considerações de desempenho para uploads

Durante um upload, as bibliotecas do cliente de armazenamento dividem um determinado fluxo de upload em vários subcarregamentos com base nos valores definidos na StorageTransferOptions instância. Cada subupload tem sua própria chamada dedicada para a operação REST. Para um BlobClient objeto ou BlockBlobClient objeto, esta operação é Put Block. Para um DataLakeFileClient objeto, esta operação é Append Data. A biblioteca do cliente de armazenamento gerencia essas operações REST em paralelo (dependendo das opções de transferência) para concluir o carregamento completo.

Dependendo se o fluxo de upload é pesquisável ou não, a biblioteca do cliente lida com buffering e InitialTransferSize de forma diferente, conforme descrito nas seções a seguir. Um fluxo pesquisável é um fluxo que suporta consultar e modificar a posição atual dentro de um fluxo. Para saber mais sobre fluxos no .NET, consulte a referência da classe Stream.

Nota

Os blobs de bloco têm uma contagem máxima de blocos de 50.000 blocos. O tamanho máximo do blob de bloco, então, é de 50.000 vezes MaximumTransferSize.

Armazenamento em buffer durante carregamentos

A camada REST de armazenamento não suporta pegar uma operação de upload REST de onde você parou; As transferências individuais são concluídas ou perdidas. Para garantir a resiliência para uploads de fluxo não pesquisáveis, as bibliotecas do cliente de armazenamento armazenam em buffer os dados para cada chamada REST individual antes de iniciar o carregamento. Além das limitações de velocidade da rede, esse comportamento de buffer é um motivo para considerar um valor menor para MaximumTransferSize, mesmo ao carregar em sequência. Diminuir o valor de MaximumTransferSize diminui a quantidade máxima de dados armazenados em buffer em cada solicitação e cada nova tentativa de uma solicitação com falha. Se você estiver enfrentando tempos limite frequentes durante transferências de dados de um determinado tamanho, reduzir o valor de reduz o tempo de MaximumTransferSize buffer e pode resultar em melhor desempenho.

Outro cenário em que o buffer ocorre é quando você está carregando dados com chamadas REST paralelas para maximizar a taxa de transferência da rede. As bibliotecas de cliente precisam de fontes das quais possam ler em paralelo e, como os fluxos são sequenciais, as bibliotecas de cliente de armazenamento armazenam em buffer os dados de cada chamada REST individual antes de iniciar o carregamento. Esse comportamento de buffer ocorre mesmo se o fluxo fornecido for pesquisável.

Para evitar buffering durante uma chamada de carregamento assíncrono, você deve fornecer um fluxo pesquisável e definir MaximumConcurrency como 1. Embora essa estratégia deva funcionar na maioria das situações, ainda é possível que o buffer ocorra se seu código estiver usando outros recursos de biblioteca de cliente que exigem buffer.

InitialTransferSize no upload

Quando um fluxo pesquisável é fornecido para upload, o comprimento do fluxo é verificado em relação ao valor de InitialTransferSize. Se o comprimento do fluxo for menor que esse valor, todo o fluxo será carregado como uma única chamada REST, independentemente de outros StorageTransferOptions valores. Caso contrário, o upload é feito em várias partes, conforme descrito anteriormente. InitialTransferSize não tem efeito sobre um fluxo não pesquisável e é ignorado.

Considerações de desempenho para downloads

Durante um download, as bibliotecas do cliente de armazenamento dividem uma determinada solicitação de download em vários subdownloads com base nos valores definidos na StorageTransferOptions instância. Cada subdownload tem sua própria chamada dedicada para a operação REST. Dependendo das opções de transferência, as bibliotecas de cliente gerenciam essas operações REST em paralelo para concluir o download completo.

Armazenamento em buffer durante downloads

Receber várias respostas HTTP simultaneamente com o conteúdo do corpo tem implicações para o uso da memória. No entanto, as bibliotecas de cliente de armazenamento não adicionam explicitamente uma etapa de buffer para o conteúdo baixado. As respostas recebidas são processadas em ordem. As bibliotecas de cliente configuram um buffer de 16 kilobytes para copiar fluxos de um fluxo de resposta HTTP para um fluxo de destino fornecido pelo chamador ou caminho de arquivo.

InitialTransferSize em download

Durante um download, as bibliotecas de cliente de armazenamento fazem uma solicitação de intervalo de download usando InitialTransferSize antes de fazer qualquer outra coisa. Durante essa solicitação de download inicial, as bibliotecas de cliente sabem o tamanho total do recurso. Se a solicitação inicial tiver baixado com êxito todo o conteúdo, a operação será concluída. Caso contrário, as bibliotecas de cliente continuarão a fazer solicitações de intervalo até MaximumTransferSize que o download completo seja concluído.

Próximos passos