Transferir dados com a biblioteca de Movimentação de Dados

Observação

Este artigo inclui diretrizes para trabalhar com a versão 2.0.XX da biblioteca de Movimentação de Dados do Armazenamento do Azure. A versão 2.0.XX está atualmente no modo de manutenção e a biblioteca está recebendo apenas correções para problemas de integridade e segurança de dados. Nenhuma nova funcionalidade ou recursos será adicionado e novas versões do serviço de armazenamento não terão suporte na biblioteca.

Versões beta de uma biblioteca moderna de Movimentação de Dados estão em desenvolvimento no momento. Para obter mais informações, consulte a biblioteca de clientes comuns de movimentação de dados do Armazenamento do Azure para .NET no GitHub.

A biblioteca de Movimentação de Dados do Armazenamento do Azure é uma biblioteca de software livre multiplataforma para upload, download e cópia de alto desempenho de blobs e arquivos. A biblioteca de Movimentação de Dados contém métodos convenientes que não estão disponíveis na biblioteca de clientes do Armazenamento do Azure para .NET. Os métodos permitem definir o número de operações paralelas, acompanhar o progresso da transferência, facilmente retomar uma transferência cancelada e muito mais.

Essa biblioteca também usa o .NET Core, que significa que você pode usá-la ao criar aplicativos .NET para Windows, Linux e macOS. Para saber mais sobre o .NET Core, consulte a documentação do .NET Core. Essa biblioteca também funciona para aplicativos tradicionais do .NET Framework para Windows.

Este documento demonstra como criar um aplicativo de console .NET Core que é executado no Windows, no Linux e no macOS e executa os seguintes cenários:

  • Carregar arquivos e diretórios no Armazenamento de Blobs.
  • Definir o número de operações paralelas durante a transferência de dados.
  • Acompanhar o progresso de transferência de dados.
  • Retomar a transferência de dados cancelada.
  • Copiar o arquivo da URL para o Armazenamento de Blobs.
  • Copiar do Armazenamento de Blobs para o Armazenamento de Blobs.

Pré-requisitos

Instalação

  1. Visite o Guia de Instalação do .NET Core para instalar o SDK do .NET Core. Ao selecionar o seu ambiente, escolha a opção de linha de comando.
  2. Na linha de comando, crie um diretório para seu projeto. Navegue nesse diretório, digite dotnet new console -o <sample-project-name> para criar um projeto de console C#.
  3. Abra esse diretório no Visual Studio Code. Esta etapa pode ser feita rapidamente por meio da linha de comando digitando code . no Windows.
  4. Instale a extensão do C# do Marketplace do Visual Studio Code. Reinicie o Visual Studio Code.
  5. Neste ponto, você deve ver dois prompts. Um é para adicionar "ativos necessários para compilar e depurar". Clique em "sim". O outro prompt é para restaurar dependências não resolvidas. Clique em “restaurar”.
  6. Modificar launch.json em .vscode para usar o terminal externo como um console. Essa configuração deve ser lida como "console": "externalTerminal"
  7. O Visual Studio Code permite que você depure aplicativos do .NET Core. Pressione F5 para executar o aplicativo e verificar se a configuração está funcionando. Você deverá ver "Olá, Mundo" impresso no console.

Adicionar a Biblioteca de Movimentação de Dados ao seu projeto

  1. Adicione a versão mais recente da Biblioteca de Movimentação de Dados à seção dependencies do arquivo <project-name>.csproj. No momento da escrita, esta versão seria "Microsoft.Azure.Storage.DataMovement": "0.6.2"
  2. Deve ser exibido um prompt para restaurar seu projeto. Clique no botão "restaurar". Você também pode restaurar seu projeto na linha de comando digitando o comando dotnet restore na raiz do diretório do projeto.

Modifique <project-name>.csproj:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp2.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.Azure.Storage.DataMovement" Version="0.6.2" />
        </ItemGroup>
    </Project>

Configurar o esqueleto do aplicativo

A primeira coisa que fazemos é configurar o código de "esqueleto" do nosso aplicativo. Esse código nos solicita um nome de conta de armazenamento e uma chave de conta e usa essas credenciais para criar um objeto CloudStorageAccount. Esse objeto é usado para interagir com nossa conta de armazenamento em todos os cenários de transferência. O código também solicita a escolha do tipo de operação de transferência que gostaríamos de executar.

Modifique Program.cs:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;
using Microsoft.Azure.Storage.DataMovement;

namespace DMLibSample
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Enter Storage account name:");
            string accountName = Console.ReadLine();

            Console.WriteLine("\nEnter Storage account key:");
            string accountKey = Console.ReadLine();

            string storageConnectionString = "DefaultEndpointsProtocol=https;AccountName=" + accountName + ";AccountKey=" + accountKey;
            CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);

            ExecuteChoice(account);
        }

        public static void ExecuteChoice(CloudStorageAccount account)
        {
            Console.WriteLine("\nWhat type of transfer would you like to execute?\n1. Local file --> Azure Blob\n2. Local directory --> Azure Blob directory\n3. URL (e.g. Amazon S3 file) --> Azure Blob\n4. Azure Blob --> Azure Blob");
            int choice = int.Parse(Console.ReadLine());

            if(choice == 1)
            {
                TransferLocalFileToAzureBlob(account).Wait();
            }
            else if(choice == 2)
            {
                TransferLocalDirectoryToAzureBlobDirectory(account).Wait();
            }
            else if(choice == 3)
            {
                TransferUrlToAzureBlob(account).Wait();
            }
            else if(choice == 4)
            {
                TransferAzureBlobToAzureBlob(account).Wait();
            }
        }

        public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
        {

        }

        public static async Task TransferLocalDirectoryToAzureBlobDirectory(CloudStorageAccount account)
        {

        }

        public static async Task TransferUrlToAzureBlob(CloudStorageAccount account)
        {

        }

        public static async Task TransferAzureBlobToAzureBlob(CloudStorageAccount account)
        {

        }
    }
}

Carregar um arquivo local para um blob

Adicione os métodos GetSourcePath e GetBlob a Program.cs:

public static string GetSourcePath()
{
    Console.WriteLine("\nProvide path for source:");
    string sourcePath = Console.ReadLine();

    return sourcePath;
}

public static CloudBlockBlob GetBlob(CloudStorageAccount account)
{
    CloudBlobClient blobClient = account.CreateCloudBlobClient();

    Console.WriteLine("\nProvide name of Blob container:");
    string containerName = Console.ReadLine();
    CloudBlobContainer container = blobClient.GetContainerReference(containerName);
    container.CreateIfNotExistsAsync().Wait();

    Console.WriteLine("\nProvide name of new Blob:");
    string blobName = Console.ReadLine();
    CloudBlockBlob blob = container.GetBlockBlobReference(blobName);

    return blob;
}

Modifique o método TransferLocalFileToAzureBlob:

public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
{
    string localFilePath = GetSourcePath();
    CloudBlockBlob blob = GetBlob(account);
    Console.WriteLine("\nTransfer started...");
    await TransferManager.UploadAsync(localFilePath, blob);
    Console.WriteLine("\nTransfer operation complete.");
    ExecuteChoice(account);
}

Esse código nos solicita o caminho para um arquivo local, o nome de um contêiner de novo ou existente e o nome de um novo blob. O método TransferManager.UploadAsync realiza o upload usando essas informações.

Pressione F5 para executar seu aplicativo. Você pode verificar se o upload ocorreu exibindo sua conta de armazenamento com o Gerenciador de Armazenamento do Microsoft Azure.

Definir o número de operações paralelas

Um recurso oferecido pela Biblioteca de Movimentação de Dados é a definição do número de operações paralelas para aumentar a taxa de transferência de dados. Por padrão, a Biblioteca de Movimentação de Dados define o número de operações paralelas como 8 * o número de núcleos do computador.

Tenha em mente que muitas operações paralelas em um ambiente de baixa largura de banda podem sobrecarregar a conexão de rede e na verdade impedir que as operações sejam totalmente concluídas. Você precisará experimentar com essa configuração para determinar o que funciona melhor com base na largura de banda de rede disponível.

Vamos adicionar um código que nos permite definir o número de operações paralelas. Também vamos adicionar código cronometra quanto tempo demora para a transferência ser concluída.

Adicione o método SetNumberOfParallelOperations a Program.cs:

public static void SetNumberOfParallelOperations()
{
    Console.WriteLine("\nHow many parallel operations would you like to use?");
    string parallelOperations = Console.ReadLine();
    TransferManager.Configurations.ParallelOperations = int.Parse(parallelOperations);
}

Modifique o método ExecuteChoice para usar SetNumberOfParallelOperations:

public static void ExecuteChoice(CloudStorageAccount account)
{
    Console.WriteLine("\nWhat type of transfer would you like to execute?\n1. Local file --> Azure Blob\n2. Local directory --> Azure Blob directory\n3. URL (e.g. Amazon S3 file) --> Azure Blob\n4. Azure Blob --> Azure Blob");
    int choice = int.Parse(Console.ReadLine());

    SetNumberOfParallelOperations();

    if(choice == 1)
    {
        TransferLocalFileToAzureBlob(account).Wait();
    }
    else if(choice == 2)
    {
        TransferLocalDirectoryToAzureBlobDirectory(account).Wait();
    }
    else if(choice == 3)
    {
        TransferUrlToAzureBlob(account).Wait();
    }
    else if(choice == 4)
    {
        TransferAzureBlobToAzureBlob(account).Wait();
    }
}

Modifique o método TransferLocalFileToAzureBlob para usar um temporizador:

public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
{
    string localFilePath = GetSourcePath();
    CloudBlockBlob blob = GetBlob(account);
    Console.WriteLine("\nTransfer started...");
    Stopwatch stopWatch = Stopwatch.StartNew();
    await TransferManager.UploadAsync(localFilePath, blob);
    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Acompanhar o progresso de transferência

É útil saber quanto tempo durou a transferência dos dados. No entanto, ver o progresso da transferência durante a operação de transferência seria ainda melhor. Para obter esse cenário, precisamos criar um objeto TransferContext. O objeto TransferContext vem em duas formas: SingleTransferContext e DirectoryTransferContext. A primeira é para transferir um único arquivo, e a segunda é para transferir um diretório de arquivos.

Adicione os métodos GetSingleTransferContext e GetDirectoryTransferContext a Program.cs:

public static SingleTransferContext GetSingleTransferContext(TransferCheckpoint checkpoint)
{
    SingleTransferContext context = new SingleTransferContext(checkpoint);

    context.ProgressHandler = new Progress<TransferStatus>((progress) =>
    {
        Console.Write("\rBytes transferred: {0}", progress.BytesTransferred );
    });

    return context;
}

public static DirectoryTransferContext GetDirectoryTransferContext(TransferCheckpoint checkpoint)
{
    DirectoryTransferContext context = new DirectoryTransferContext(checkpoint);

    context.ProgressHandler = new Progress<TransferStatus>((progress) =>
    {
        Console.Write("\rBytes transferred: {0}", progress.BytesTransferred );
    });

    return context;
}

Modifique o método TransferLocalFileToAzureBlob para usar GetSingleTransferContext:

public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
{
    string localFilePath = GetSourcePath();
    CloudBlockBlob blob = GetBlob(account);
    TransferCheckpoint checkpoint = null;
    SingleTransferContext context = GetSingleTransferContext(checkpoint);
    Console.WriteLine("\nTransfer started...\n");
    Stopwatch stopWatch = Stopwatch.StartNew();
    await TransferManager.UploadAsync(localFilePath, blob, null, context);
    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Retomar uma transferência cancelada

Outro recurso conveniente da Biblioteca de Movimentação de Dados é a retomada de transferências canceladas. Vamos adicionar um pouco de código que permite cancelar temporariamente a transferência digitando c e, em seguida, retomar a transferência de 3 segundos mais tarde.

Modifique TransferLocalFileToAzureBlob:

public static async Task TransferLocalFileToAzureBlob(CloudStorageAccount account)
{
    string localFilePath = GetSourcePath();
    CloudBlockBlob blob = GetBlob(account);
    TransferCheckpoint checkpoint = null;
    SingleTransferContext context = GetSingleTransferContext(checkpoint);
    CancellationTokenSource cancellationSource = new CancellationTokenSource();
    Console.WriteLine("\nTransfer started...\nPress 'c' to temporarily cancel your transfer...\n");

    Stopwatch stopWatch = Stopwatch.StartNew();
    Task task;
    ConsoleKeyInfo keyinfo;
    try
    {
        task = TransferManager.UploadAsync(localFilePath, blob, null, context, cancellationSource.Token);
        while(!task.IsCompleted)
        {
            if(Console.KeyAvailable)
            {
                keyinfo = Console.ReadKey(true);
                if(keyinfo.Key == ConsoleKey.C)
                {
                    cancellationSource.Cancel();
                }
            }
        }
        await task;
    }
    catch(Exception e)
    {
        Console.WriteLine("\nThe transfer is canceled: {0}", e.Message);
    }

    if(cancellationSource.IsCancellationRequested)
    {
        Console.WriteLine("\nTransfer will resume in 3 seconds...");
        Thread.Sleep(3000);
        checkpoint = context.LastCheckpoint;
        context = GetSingleTransferContext(checkpoint);
        Console.WriteLine("\nResuming transfer...\n");
        await TransferManager.UploadAsync(localFilePath, blob, null, context);
    }

    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Até agora, nosso valor checkpoint sempre foi definido como null. Agora, se cancelarmos a transferência, recuperamos o último ponto de verificação da nossa transferência e usamos esse novo ponto de verificação em nosso contexto de transferência.

Transferir um diretório local para o armazenamento de blobs

Seria decepcionante se a Biblioteca de Movimentação de Dados pudesse transferir apenas um arquivo por vez. Felizmente, esse não é o caso. A Biblioteca de Movimentação de Dados pode transferir um diretório de arquivos e todos os subdiretórios dele. Vamos adicionar um pouco de código que nos permite fazer exatamente isso.

Primeiro, adicione o método GetBlobDirectory a Program.cs:

public static CloudBlobDirectory GetBlobDirectory(CloudStorageAccount account)
{
    CloudBlobClient blobClient = account.CreateCloudBlobClient();

    Console.WriteLine("\nProvide name of Blob container. This can be a new or existing Blob container:");
    string containerName = Console.ReadLine();
    CloudBlobContainer container = blobClient.GetContainerReference(containerName);
    container.CreateIfNotExistsAsync().Wait();

    CloudBlobDirectory blobDirectory = container.GetDirectoryReference("");

    return blobDirectory;
}

Em seguida, modifique TransferLocalDirectoryToAzureBlobDirectory:

public static async Task TransferLocalDirectoryToAzureBlobDirectory(CloudStorageAccount account)
{
    string localDirectoryPath = GetSourcePath();
    CloudBlobDirectory blobDirectory = GetBlobDirectory(account);
    TransferCheckpoint checkpoint = null;
    DirectoryTransferContext context = GetDirectoryTransferContext(checkpoint);
    CancellationTokenSource cancellationSource = new CancellationTokenSource();
    Console.WriteLine("\nTransfer started...\nPress 'c' to temporarily cancel your transfer...\n");

    Stopwatch stopWatch = Stopwatch.StartNew();
    Task task;
    ConsoleKeyInfo keyinfo;
    UploadDirectoryOptions options = new UploadDirectoryOptions()
    {
        Recursive = true
    };

    try
    {
        task = TransferManager.UploadDirectoryAsync(localDirectoryPath, blobDirectory, options, context, cancellationSource.Token);
        while(!task.IsCompleted)
        {
            if(Console.KeyAvailable)
            {
                keyinfo = Console.ReadKey(true);
                if(keyinfo.Key == ConsoleKey.C)
                {
                    cancellationSource.Cancel();
                }
            }
        }
        await task;
    }
    catch(Exception e)
    {
        Console.WriteLine("\nThe transfer is canceled: {0}", e.Message);
    }

    if(cancellationSource.IsCancellationRequested)
    {
        Console.WriteLine("\nTransfer will resume in 3 seconds...");
        Thread.Sleep(3000);
        checkpoint = context.LastCheckpoint;
        context = GetDirectoryTransferContext(checkpoint);
        Console.WriteLine("\nResuming transfer...\n");
        await TransferManager.UploadDirectoryAsync(localDirectoryPath, blobDirectory, options, context);
    }

    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Há algumas diferenças entre este método e o método de carregamento de um único arquivo. Agora estamos usando TransferManager.UploadDirectoryAsync e o método getDirectoryTransferContext criado anteriormente. Além disso, agora fornecemos um valor options para nossa operação de upload, o que permite indicar que queremos incluir subdiretórios em nosso upload.

Copiar um arquivo da URL para um blob

Agora, vamos adicionar o código que permite copiar um arquivo de uma URL para um Blob do Azure.

Modifique TransferUrlToAzureBlob:

public static async Task TransferUrlToAzureBlob(CloudStorageAccount account)
{
    Uri uri = new Uri(GetSourcePath());
    CloudBlockBlob blob = GetBlob(account);
    TransferCheckpoint checkpoint = null;
    SingleTransferContext context = GetSingleTransferContext(checkpoint);
    CancellationTokenSource cancellationSource = new CancellationTokenSource();
    Console.WriteLine("\nTransfer started...\nPress 'c' to temporarily cancel your transfer...\n");

    Stopwatch stopWatch = Stopwatch.StartNew();
    Task task;
    ConsoleKeyInfo keyinfo;
    try
    {
        task = TransferManager.CopyAsync(uri, blob, CopyMethod.ServiceSideAsyncCopy, null, context, cancellationSource.Token);
        while(!task.IsCompleted)
        {
            if(Console.KeyAvailable)
            {
                keyinfo = Console.ReadKey(true);
                if(keyinfo.Key == ConsoleKey.C)
                {
                    cancellationSource.Cancel();
                }
            }
        }
        await task;
    }
    catch(Exception e)
    {
        Console.WriteLine("\nThe transfer is canceled: {0}", e.Message);
    }

    if(cancellationSource.IsCancellationRequested)
    {
        Console.WriteLine("\nTransfer will resume in 3 seconds...");
        Thread.Sleep(3000);
        checkpoint = context.LastCheckpoint;
        context = GetSingleTransferContext(checkpoint);
        Console.WriteLine("\nResuming transfer...\n");
        await TransferManager.CopyAsync(uri, blob, CopyMethod.ServiceSideAsyncCopy, null, context, cancellationSource.Token);
    }

    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Um caso de uso importante para esse recurso é quando você precisa mover dados de outro serviço de nuvem (por exemplo, AWS) para o Azure. Contanto que você tenha uma URL que fornece acesso ao recurso, pode mover facilmente esse recurso para Blobs do Azure usando o método TransferManager.CopyAsync. Esse método também introduz um parâmetroCopyMethod. A tabela a seguir mostra as opções disponíveis para este parâmetro:

Nome do membro Valor Descrição
SyncCopy 0 Baixe dados da origem para a memória e carregue os dados da memória para o destino. No momento, está disponível apenas para a cópia de um recurso do Armazenamento do Azure para outro.
ServiceSideAsyncCopy 1 Envie uma solicitação de cópia inicial para o Armazenamento do Azure para permitir que ela faça a cópia. Monitore o progresso da operação de cópia até que a cópia seja concluída.
ServiceSideSyncCopy 2 Copie o conteúdo de cada parte com a URL Colocar Bloco de, Acrescentar Bloco da URL ou Colocar Página da URL.

Copiar um blob

Outro recurso exclusivo da Biblioteca de Movimentação de Dados é a cópia de um recurso do Armazenamento do Microsoft Azure para outro.

Modifique TransferAzureBlobToAzureBlob:

public static async Task TransferAzureBlobToAzureBlob(CloudStorageAccount account)
{
    CloudBlockBlob sourceBlob = GetBlob(account);
    CloudBlockBlob destinationBlob = GetBlob(account);
    TransferCheckpoint checkpoint = null;
    SingleTransferContext context = GetSingleTransferContext(checkpoint);
    CancellationTokenSource cancellationSource = new CancellationTokenSource();
    Console.WriteLine("\nTransfer started...\nPress 'c' to temporarily cancel your transfer...\n");

    Stopwatch stopWatch = Stopwatch.StartNew();
    Task task;
    ConsoleKeyInfo keyinfo;
    try
    {
        task = TransferManager.CopyAsync(sourceBlob, destinationBlob, CopyMethod.SyncCopy, null, context, cancellationSource.Token);
        while(!task.IsCompleted)
        {
            if(Console.KeyAvailable)
            {
                keyinfo = Console.ReadKey(true);
                if(keyinfo.Key == ConsoleKey.C)
                {
                    cancellationSource.Cancel();
                }
            }
        }
        await task;
    }
    catch(Exception e)
    {
        Console.WriteLine("\nThe transfer is canceled: {0}", e.Message);
    }

    if(cancellationSource.IsCancellationRequested)
    {
        Console.WriteLine("\nTransfer will resume in 3 seconds...");
        Thread.Sleep(3000);
        checkpoint = context.LastCheckpoint;
        context = GetSingleTransferContext(checkpoint);
        Console.WriteLine("\nResuming transfer...\n");
        await TransferManager.CopyAsync(sourceBlob, destinationBlob, CopyMethod.SyncCopy, null, context, cancellationSource.Token);
    }

    stopWatch.Stop();
    Console.WriteLine("\nTransfer operation completed in " + stopWatch.Elapsed.TotalSeconds + " seconds.");
    ExecuteChoice(account);
}

Neste exemplo, definimos o parâmetro booliano em TransferManager.CopyAsync como CopyMethod.SyncCopy para indicar que queremos fazer uma cópia síncrona. Isso significa que o recurso é baixado para o computador local primeiro e, em seguida, carregado no Blob do Azure. A opção de cópia síncrona é uma ótima maneira de garantir que a operação de cópia tenha uma velocidade consistente. Por outro lado, a velocidade de uma cópia assíncrona do lado do servidor é dependente da largura de banda de rede disponível no servidor, que pode flutuar. No entanto, a cópia síncrona pode gerar custo de saída adicional em comparação com a cópia assíncrona. A abordagem recomendada é usar essa a cópia síncrona na VM do Azure que está na mesma região que a sua conta de armazenamento de origem, a fim de evitar o custo de saída.

Agora o aplicativo de movimentação de dados está concluído. O exemplo de código completo está disponível no GitHub.

Próximas etapas

Documentação de referência da Biblioteca de Movimentação de Dados do Armazenamento do Azure.

Dica

Como gerenciar os recursos de Armazenamento de Blobs do Azure com o Gerenciador de Armazenamento do Microsoft Azure. O Gerenciador de Armazenamento do Microsoft Azure é um aplicativo independente e grátis da Microsoft que permite gerenciar recursos de armazenamento de Blob do Microsoft Azure. Com o Gerenciador de Armazenamento do Microsoft Azure, você pode criar, ler, atualizar e excluir visualmente contêineres de blobs e blobs, bem como gerenciar o acesso aos seus contêineres de blobs e blobs.