Tutorial: Executando uma carga de trabalho paralela com o Lote do Azure usando a API .NET

Use o Lote do Azure para executar trabalhos em lote de HPC (computação de alto desempenho) e paralelos em larga escala com eficiência no Azure. Este tutorial mostra um exemplo em C# de como executar uma carga de trabalho paralela usando o Batch. Você aprenderá um fluxo de trabalho comum de um aplicativo do Batch e como interagir programaticamente com recursos do Batch e do Storage.

  • Adicionar um pacote de aplicativos à sua conta do Batch.
  • Autentique-se com contas do Batch e do Storage.
  • Carregar arquivos de entrada para o Armazenamento.
  • Criar um pool de nós de computação para executar um aplicativo.
  • Criar um trabalho e tarefas para processar os arquivos de entrada.
  • Monitorar a execução da tarefa.
  • Recuperar arquivos de saída.

Neste tutorial, você converterá arquivos de mídia MP4 para o formato MP3, em paralelo, usando a ferramenta de código aberto ffmpeg.

Se você ainda não tiver uma conta do Azure, crie uma conta gratuita antes de começar.

Pré-requisitos

Entrar no Azure

Entre no Portal do Azure.

Adicionar um pacote de aplicativos

Use o portal do Azure para adicionar o ffmpeg à sua conta do Batch como um pacote de aplicativos. Os pacotes de aplicativos ajudam a gerenciar aplicativos de tarefas e sua implantação nos nós de computação em seu pool.

  1. No portal do Azure, clique em Mais serviços>contas do Batch, e selecione o nome da sua conta do Batch.

  2. Clique em Aplicativos>Adicionar.

    Captura de tela da seção Aplicativos da conta de lote.

  3. Insira ffmpeg no campo ID do aplicativo e uma versão do pacote da 4.3.1 no campo Versão. Selecione o arquivo zip do ffmpeg que você baixou e, em seguida, selecione Enviar. O pacote de aplicativo ffmpeg foi adicionado à sua conta do Batch.

    Captura de tela dos campos de ID e versão na seção Adicionar aplicativo.

Obter credenciais da conta

Para este exemplo, você precisa fornecer credenciais para suas contas do Batch e do Storage. Uma maneira simples de obter as credenciais necessárias e no Portal do Azure. (Você também pode obter essas credenciais usando as APIs do Azure ou as ferramentas de linha de comando.)

  1. Selecione Todos os serviços>Contas do Batch, e então selecione o nome da sua conta do Batch.

  2. Para ver as credenciais do Lote, selecione Chaves. Copie os valores da conta do Batch, URL e chave de acesso primária para um editor de texto.

  3. Para ver o nome e as chaves da conta de armazenamento, selecione Conta de armazenamento. Copie os valores de Nome da conta de Armazenamento e Chave1 em um editor de texto.

Baixar e executar o aplicativo de amostra

Baixar o aplicativo de exemplo

Baixe ou clone o aplicativo de exemplo do GitHub. Para clonar o repositório do aplicativo de exemplo com um cliente Git, use o seguinte comando:

git clone https://github.com/Azure-Samples/batch-dotnet-ffmpeg-tutorial.git

Navegue até o diretório que contém o arquivo de solução do Visual Studio BatchDotNetFfmpegTutorial.sln.

Além disso, verifique se a referência do pacote do aplicativo ffmpeg na solução corresponde ao identificador e à versão do pacote ffmpeg que você carregou na sua conta do Batch. Por exemplo, ffmpeg e 4.3.1.

const string appPackageId = "ffmpeg";
const string appPackageVersion = "4.3.1";

Criar e executar o projeto de exemplo

Compile e execute o aplicativo no Visual Studio ou na linha de comando com os comandos dotnet build e dotnet run. Depois de executar o aplicativo, examine o código para saber o que cada parte do aplicativo faz. Por exemplo, no Visual Studio:

  1. Clique com o botão direito do mouse na solução no Gerenciador de Soluções e selecione Compilar Solução.

  2. Confirme a restauração de qualquer pacote NuGet, se solicitado. Se você precisar baixar pacotes ausentes, verifique se o Gerenciador de Pacotes do NuGet está instalado.

  3. Execute a solução. Quando você executa o aplicativo de exemplo, a saída do console fica mais ou menos assim. Durante a execução, você tem uma pausa em Monitoring all tasks for 'Completed' state, timeout in 00:30:00... enquanto os nós de computação do pool são iniciados.

Sample start: 11/19/2018 3:20:21 PM

Container [input] created.
Container [output] created.
Uploading file LowPriVMs-1.mp4 to container [input]...
Uploading file LowPriVMs-2.mp4 to container [input]...
Uploading file LowPriVMs-3.mp4 to container [input]...
Uploading file LowPriVMs-4.mp4 to container [input]...
Uploading file LowPriVMs-5.mp4 to container [input]...
Creating pool [WinFFmpegPool]...
Creating job [WinFFmpegJob]...
Adding 5 tasks to job [WinFFmpegJob]...
Monitoring all tasks for 'Completed' state, timeout in 00:30:00...
Success! All tasks completed successfully within the specified timeout period.
Deleting container [input]...

Sample end: 11/19/2018 3:29:36 PM
Elapsed time: 00:09:14.3418742

Acesse sua conta do Azure Batch no portal do Azure para monitorar o pool, os nós de computação, o trabalho e as tarefas. Por exemplo, para ver um mapa de calor dos nós de computação em seu pool, clique em Pools>WinFFmpegPool.

Quando as tarefas são executadas, o mapa de calor fica mais ou menos assim:

Captura de tela do mapa de calor do pool no portal do Azure.

O tempo de execução típico é de aproximadamente 10 minutos ao executar o aplicativo em sua configuração padrão. A criação de pool leva mais tempo.

Recuperar arquivos de saída

Você pode usar o Portal do Azure para baixar os arquivos MP3 de saída gerados pelas tarefas de ffmpeg.

  1. Clique em Todos os serviços>Contas de armazenamento e, depois, clique no nome da sua conta de armazenamento.
  2. Clique em Blobs>saída.
  3. Clique com o botão direito em um dos arquivos MP3 de saída e, em seguida, clique em Baixar. Siga as instruções em seu navegador para abrir ou salvar o arquivo.

Baixar o arquivo de saída

Embora não seja mostrado neste exemplo, você também pode baixar os arquivos de forma programática a partir dos nós de computação ou do contêiner de armazenamento.

Examine o código

As seções a seguir dividem o aplicativo de exemplo nas etapas que ele executa para processar uma carga de trabalho no serviço Batch. Consulte o arquivo Program.cs na solução enquanto você lê o restante deste artigo, pois nem todas as linhas de código na amostra são discutidas.

Autenticar clientes do Blob e do Batch

Para interagir com a conta de armazenamento vinculada, o aplicativo usa a Biblioteca Azure.Storage.Blobs para .NET. Usando a classe BlobServiceClient que faz referência ao Uri da conta e autenticando o Token, como DefaultAzureCredential.

// TODO: Replace <storage-account-name> with your actual storage account name
Uri accountUri = new Uri("https://<storage-account-name>.blob.core.windows.net/");
BlobServiceClient blobClient = new BlobServiceClient(accountUri, new DefaultAzureCredential());

O aplicativo cria uma referência ao BatchAccountResource por meio do ArmClient do Resource Manager para criar o pool no serviço Batch. O cliente Arm no exemplo usa a autenticação DefaultAzureCredential.

ArmClient _armClient = new ArmClient(new DefaultAzureCredential());
var batchAccountIdentifier = ResourceIdentifier.Parse(BatchAccountResourceID);
BatchAccountResource batchAccount = await _armClient.GetBatchAccountResource(batchAccountIdentifier).GetAsync();

O aplicativo cria um objeto BatchClient para criar trabalhos e tarefas no serviço Batch. O cliente do Batch no exemplo usa a autenticação com DefaultAzureCredential.

// TODO: Replace <batch-account-name> with your actual storage account name
Uri batchUri = new Uri("https://<batch-account-name>t.eastus.batch.azure.com");
BatchClient _batchClient = new BatchClient(batchUri, new DefaultAzureCredential());

Carregar arquivos de entrada

A aplicativo passa o objeto blobServerClient para o método CreateContainerIfNotExist a fim de criar um contêiner de armazenamento para os arquivos de entrada (formato MP4) e um contêiner para a saída da tarefa.

CreateContainerIfNotExist(blobClient, inputContainerName);
CreateContainerIfNotExist(blobClient, outputContainerName);

Em seguida, os arquivos serão enviados para o contêiner de entrada da pasta InputFiles local. Os arquivos no armazenamento são definidos como objetos Batch ResourceFile que o Batch pode baixar posteriormente nos nós de computação.

Dois métodos em Program.cs estão envolvidos no upload dos arquivos:

  • UploadFilesToContainerAsync: Retorna uma coleção de objetos ResourceFile e chama internamente UploadResourceFileToContainerAsync para carregar cada arquivo passado no parâmetro inputFilePaths.
  • UploadResourceFileToContainerAsync: Carrega cada arquivo como um blob no contêiner de entrada. Depois de carregar o arquivo, ele obtém uma assinatura de acesso compartilhado (SAS) para o blob e retorna um objeto ResourceFile para representá-lo.
string inputPath = Path.Combine(Environment.CurrentDirectory, "InputFiles");

List<string> inputFilePaths = new List<string>(Directory.GetFileSystemEntries(inputPath, "*.mp4",
    SearchOption.TopDirectoryOnly));

List<ResourceFile> inputFiles = await UploadFilesToContainerAsync(
  blobClient,
  inputContainerName,
  inputFilePaths);

Para obter detalhes de como carregar arquivos como blobs em uma conta de armazenamento com o .NET, confira Carregar, baixar e listar blobs usando o .NET.

Criar um pool de nós de computação

Em seguida, o exemplo cria um pool de nós de computação na conta do Batch por meio de uma chamada para CreatePoolIfNotExistAsync. Esse método definido usa o método BatchAccountResource.GetBatchAccountPools(). CreateOrUpdateAsync para definir o número de nós, o tamanho da VM e uma configuração do pool. Aqui, um objeto BatchVmConfiguration especifica um BatchImageReference em uma imagem do Windows Server publicada no Azure Marketplace. O Batch oferece suporte a uma ampla variedade de imagens de VM no Azure Marketplace, bem como a imagens de VM personalizadas.

O número de nós e o tamanho da VM são definidos usando constantes definidas. O Batch dá suporte a nós dedicados e nós de spot, e você pode usar um ou ambos em seus conjuntos. Nós dedicados são reservados para seu pool. Os nós Spot são oferecidos por um preço reduzido a partir da capacidade excedente de VMs no Azure. Nós Spot ficam indisponíveis quando o Azure não tem capacidade disponível suficiente. O exemplo, por padrão, cria um pool contendo apenas 5 nós Spot do tamanho Standard_A1_v2.

Observação

Confira as cotas do seu nó. Consulte Cotas e limites de serviço do Batch para obter instruções sobre como criar uma solicitação de cota.

O aplicativo ffmpeg é implantado nos nós de computação adicionando um BatchApplicationPackageReference à configuração do pool.

var credential = new DefaultAzureCredential();
ArmClient _armClient = new ArmClient(credential);

var batchAccountIdentifier = ResourceIdentifier.Parse(BatchAccountResourceID);
BatchAccountResource batchAccount = await _armClient.GetBatchAccountResource(batchAccountIdentifier).GetAsync();

BatchAccountPoolCollection collection = batchAccount.GetBatchAccountPools();
if (collection.Exists(poolId) == false)
{
    var poolName = poolId;
    var imageReference = new BatchImageReference()
    {
        Publisher = "MicrosoftWindowsServer",
        Offer = "WindowsServer",
        Sku = "2019-datacenter-smalldisk",
        Version = "latest"
    };
    string nodeAgentSku = "batch.node.windows amd64";


    ArmOperation<BatchAccountPoolResource> armOperation = await batchAccount.GetBatchAccountPools().CreateOrUpdateAsync(
        WaitUntil.Completed, poolName, new BatchAccountPoolData()
        {
            VmSize = "Standard_DS1_v2",
            DeploymentConfiguration = new BatchDeploymentConfiguration()
            {
                VmConfiguration = new BatchVmConfiguration(imageReference, nodeAgentSku)
            },
            ScaleSettings = new BatchAccountPoolScaleSettings()
            {
                FixedScale = new BatchAccountFixedScaleSettings()
                {
                    TargetDedicatedNodes = DedicatedNodeCount,
                    TargetLowPriorityNodes = LowPriorityNodeCount
                }
            },
            Identity = new ManagedServiceIdentity(ManagedServiceIdentityType.UserAssigned)
            {
                UserAssignedIdentities =
                {
                        [new ResourceIdentifier(ManagedIdentityId)] = new Azure.ResourceManager.Models.UserAssignedIdentity(),
                },
            },
            ApplicationPackages =
            {
                    new Azure.ResourceManager.Batch.Models.BatchApplicationPackageReference(new ResourceIdentifier(appPackageResourceID))
                    {
                        Version = appPackageVersion,
                    }
            },

        });
    BatchAccountPoolResource pool = armOperation.Value;

Criar um trabalho

Um trabalho em lote especifica um pool para executar tarefas e configurações opcionais, como prioridade e agendamento do trabalho. O exemplo cria uma tarefa por meio de uma chamada a CreateJobAsync. Esse método definido usa o método BatchClient.CreateJobAsync para criar um trabalho no seu pool.

 BatchJobCreateOptions batchJobCreateOptions = new BatchJobCreateOptions(jobId, new BatchPoolInfo { PoolId = poolId });
 await batchClient.CreateJobAsync(batchJobCreateOptions);

Criar tarefas

O exemplo cria tarefas no trabalho com uma chamada para o método AddTasksAsync, que cria uma lista de objetos BatchTask. Cada BatchTask executa ffmpeg para processar um objeto ResourceFile de entrada usando uma propriedade CommandLine. O ffmpeg já havia sido instalado em cada nó quando o pool foi criado. Aqui, a linha de comando executa ffmpeg para converter cada arquivo MP4 (vídeo) de entrada em um arquivo MP3 (áudio).

O exemplo cria um objeto OutputFile para o arquivo MP3 depois de executar a linha de comando. Os arquivos de saída de cada tarefa (um, neste caso) são carregados em um contêiner na conta de armazenamento vinculada, usando a propriedade OutputFiles da tarefa. Observe as condições definidas no objeto outputFile. Um arquivo de saída de uma tarefa é carregado no contêiner somente depois que a tarefa é concluída com êxito (OutputFileUploadCondition.TaskSuccess). Confira o exemplo de código completo no GitHub para obter mais detalhes de implementação.

Em seguida, o exemplo adiciona tarefas ao trabalho com o método CreateTaskAsync , que as enfileira para serem executadas nos nós de computação.

Substitua o caminho do arquivo do executável pelo nome da versão baixada. Este código de exemplo usa o exemplo ffmpeg-4.3.1-2020-11-08-full_build.

// Create a collection to hold the tasks added to the job:
List<BatchTaskCreateOptions> tasks = new List<BatchTaskCreateOptions>();

for (int i = 0; i < inputFiles.Count; i++)
{
    // Assign a task ID for each iteration
    string taskId = String.Format("Task{0}", i);

    // Define task command line to convert the video format from MP4 to MP3 using ffmpeg.
    // Note that ffmpeg syntax specifies the format as the file extension of the input file
    // and the output file respectively. In this case inputs are MP4.
    string appPath = String.Format("%AZ_BATCH_APP_PACKAGE_{0}#{1}%", appPackageId, appPackageVersion);
    string inputMediaFile = inputFiles[i].StorageContainerUri.ToString();
    string outputMediaFile = String.Format("{0}{1}",
        System.IO.Path.GetFileNameWithoutExtension(inputMediaFile),
        ".mp3");
    string taskCommandLine = String.Format("cmd /c {0}\\ffmpeg-4.3.1-2020-11-08-full_build\\bin\\ffmpeg.exe -i {1} {2}", appPath, inputMediaFile, outputMediaFile);

    // Create a batch task (with the task ID and command line) and add it to the task list

    BatchTaskCreateOptions batchTaskCreateOptions = new BatchTaskCreateOptions(taskId, taskCommandLine);
    batchTaskCreateOptions.ResourceFiles.Add(inputFiles[i]);

    // Task output file will be uploaded to the output container in Storage.
    // TODO: Replace <storage-account-name> with your actual storage account name
    OutputFileBlobContainerDestination outputContainer = new OutputFileBlobContainerDestination(new Uri("https://<storage-account-name>.blob.core.windows.net/output/" + outputMediaFile))
    {
        IdentityReference = inputFiles[i].IdentityReference,
    };

    OutputFile outputFile = new OutputFile(outputMediaFile,
                                           new OutputFileDestination() { Container = outputContainer },
                                           new OutputFileUploadConfig(OutputFileUploadCondition.TaskSuccess));
    batchTaskCreateOptions.OutputFiles.Add(outputFile);

    tasks.Add(batchTaskCreateOptions);
}

// Call BatchClient.CreateTaskCollectionAsync() to add the tasks as a collection rather than making a
// separate call for each. Bulk task submission helps to ensure efficient underlying API
// calls to the Batch service. 

await batchClient.CreateTaskCollectionAsync(jobId, new BatchTaskGroup(tasks));

Limpar os recursos

Depois que o aplicativo executa as tarefas, ele exclui automaticamente o contêiner de armazenamento de entrada que criou e oferece a opção de excluir o pool e o trabalho do Batch. O BatchClient tem um método para excluir um trabalho DeleteJobAsync e excluir um pool DeletePoolAsync, que são chamados se você confirmar a exclusão. Embora você não seja cobrado pelos trabalhos e pelas tarefas, será cobrado pelos nós de computação. Portanto, recomendamos que você aloque os pools conforme a necessidade. Quando você excluir o pool, todas as saídas de tarefa nos nós são excluídas. No entanto, os arquivos de saída permanecerão na conta de armazenamento.

Quando não forem mais necessário, exclua o grupo de recursos, a conta do Lote e a conta de armazenamento. Para fazer isso no Portal do Azure, selecione o grupo de recursos para a conta do Lote e clique em Excluir grupo de recursos.

Próximas etapas

Neste tutorial, você aprendeu a:

  • Adicionar um pacote de aplicativos à sua conta do Batch.
  • Autentique-se com contas do Batch e do Storage.
  • Carregar arquivos de entrada para o Armazenamento.
  • Criar um pool de nós de computação para executar um aplicativo.
  • Criar um trabalho e tarefas para processar os arquivos de entrada.
  • Monitorar a execução da tarefa.
  • Recuperar arquivos de saída.

Para obter mais exemplos de uso da API do .NET para agendar e processar workloads do Batch, consulte os exemplos em C# do Batch no GitHub.