Tutorial: Executar uma carga de trabalho paralela com o Lote do Azure usando a API do .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 percorre um exemplo de C# para executar uma carga de trabalho paralela usando o Lote. Você conhecerá um fluxo de trabalho de aplicativo comum no Lote e como interagir programaticamente com recursos do Armazenamento e do Lote.

  • Adicionar um pacote de aplicativos à sua conta do Batch.
  • Autenticar com contas do Lote e de Armazenamento.
  • 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.

Caso você não tenha uma assinatura do Azure, crie uma conta gratuita do Azure 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 Lote 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 Lote e selecione o nome da sua conta do Lote.

  2. Clique em Aplicativos>Adicionar.

    Screenshot of the Applications section of the batch account.

  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 aplicativos ffmpeg é adicionado à sua conta do Lote.

    Screenshot of the ID and version fields in the Add application section.

Obter credenciais da conta

Para este exemplo, você precisa fornecer credenciais para suas contas do Lote e do Armazenamento. 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 Lote e, em seguida, selecione o nome de sua conta do Lote.

  2. Para ver as credenciais do Lote, selecione Chaves. Copie os valores da conta do Lote, URL, e Chave de acesso primária em 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.

Abra o arquivo da solução no Visual Studio e atualize as cadeia de caracteres de credenciais em Program.cs com os valores que você obteve para suas contas. Por exemplo:

// Batch account credentials
private const string BatchAccountName = "yourbatchaccount";
private const string BatchAccountKey  = "xxxxxxxxxxxxxxxxE+yXrRvJAqT9BlXwwo1CwF+SwAYOxxxxxxxxxxxxxxxx43pXi/gdiATkvbpLRl3x14pcEQ==";
private const string BatchAccountUrl  = "https://yourbatchaccount.yourbatchregion.batch.azure.com";

// Storage account credentials
private const string StorageAccountName = "yourstorageaccount";
private const string StorageAccountKey  = "xxxxxxxxxxxxxxxxy4/xxxxxxxxxxxxxxxxfwpbIC5aAWA8wDu+AFXZB827Mt9lybZB1nUcQbQiUrkPtilK5BQ==";

Observação

Para simplificar o exemplo, as credenciais de Conta de armazenamento e de Lote aparecem em texto não criptografado. Na prática, é recomendável que você restrinja o acesso às credenciais e faça referência a elas em seu código usando variáveis de ambiente ou um arquivo de configuração. Para obter exemplos, confira o repositório de exemplos de código do Lote do Azure.

Além disso, verifique se a referência do pacote de aplicativos do ffmpeg na solução corresponde ao identificador e à versão do pacote do ffmpeg que você carregou na sua conta do Lote. 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

Vá para sua conta do Lote no portal do Azure para monitorar o pool, os nós de computação, os trabalhos 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:

Screenshot of the pool heat map in the Azure portal.

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.

Download output file

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 separa o aplicativo de exemplo nas etapas executadas para processar uma carga de trabalho no serviço Lote. 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 de Blob e do Lote

Para interagir com a conta de armazenamento vinculada, o aplicativo usa a Biblioteca de Clientes de Armazenamento do Azure para .NET. Ele cria uma referência à conta com CloudStorageAccount, autenticando usando a autenticação de chave compartilhada. Em seguida, ele cria um CloudBlobClient.

// Construct the Storage account connection string
string storageConnectionString = String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
                                StorageAccountName, StorageAccountKey);

// Retrieve the storage account
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);

CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

O aplicativo cria um objeto BatchClient para criar e gerenciar pools, trabalhos e tarefas no serviço Lote. O cliente do Lote no exemplo usa a autenticação de chave compartilhada. O Lote também dá suporte à autenticação por meio do Microsoft Entra ID para autenticar usuários individuais ou um aplicativo autônomo.

BatchSharedKeyCredentials sharedKeyCredentials = new BatchSharedKeyCredentials(BatchAccountUrl, BatchAccountName, BatchAccountKey);

using (BatchClient batchClient = BatchClient.Open(sharedKeyCredentials))
...

Carregar arquivos de entrada

A aplicativo passa o objeto blobClient para o método CreateContainerIfNotExistAsync 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.

CreateContainerIfNotExistAsync(blobClient, inputContainerName);
CreateContainerIfNotExistAsync(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 ResourceFile do Lote que ele pode baixar mais tarde para os 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 Lote com uma chamada para CreatePoolIfNotExistAsync. Esse método definido usa o método BatchClient.PoolOperations.CreatePool para definir o número de nós, o tamanho da VM e uma configuração de pool. Aqui, um objeto VirtualMachineConfiguration especifica uma ImageReference para uma imagem do Windows Server publicada no Azure Marketplace. O Lote dá suporte a uma ampla gama de imagens de VM no Azure Marketplace, bem como imagens de VM personalizadas.

O número de nós e o tamanho da VM são definidos usando constantes definidas. O Lote dá suporte a nós dedicados e nós spot, e você pode usar um ou ambos em seus pools. Nós dedicados são reservados para o pool. Nós spot são oferecidos a um preço menor do excedente de capacidade da VM no Azure. Nós spot ficam indisponíveis quando o Azure não tem capacidade suficiente. O exemplo, por padrão, cria um pool que contém apenas cinco Nós spot em tamanho Standard_A1_v2.

Observação

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

O aplicativo ffmpeg for implantado para os nós de computação adicionando um ApplicationPackageReference à configuração do pool.

O método CommitAsync envia o pool para o serviço Lote.

ImageReference imageReference = new ImageReference(
    publisher: "MicrosoftWindowsServer",
    offer: "WindowsServer",
    sku: "2016-Datacenter-smalldisk",
    version: "latest");

VirtualMachineConfiguration virtualMachineConfiguration =
    new VirtualMachineConfiguration(
    imageReference: imageReference,
    nodeAgentSkuId: "batch.node.windows amd64");

pool = batchClient.PoolOperations.CreatePool(
    poolId: poolId,
    targetDedicatedComputeNodes: DedicatedNodeCount,
    targetLowPriorityComputeNodes: LowPriorityNodeCount,
    virtualMachineSize: PoolVMSize,
    virtualMachineConfiguration: virtualMachineConfiguration);

pool.ApplicationPackageReferences = new List<ApplicationPackageReference>
    {
    new ApplicationPackageReference {
    ApplicationId = appPackageId,
    Version = appPackageVersion}};

await pool.CommitAsync();  

Criar um trabalho

Um trabalho do Lote especifica um pool onde executar tarefas, e configurações opcionais, como uma prioridade e uma agenda para o trabalho. O exemplo cria um trabalho com uma chamada para CreateJobAsync. Esse método definido usa o método BatchClient.JobOperations.CreateJob para criar um trabalho em seu pool.

O método CommitAsync envia o trabalho para o serviço Lote. Inicialmente, o trabalho não tem nenhuma tarefa.

CloudJob job = batchClient.JobOperations.CreateJob();
job.Id = JobId;
job.PoolInformation = new PoolInformation { PoolId = PoolId };

await job.CommitAsync();

Criar tarefas

O exemplo cria tarefas no trabalho com uma chamada para o método AddTasksAsync, que cria uma lista de objetos CloudTask. Cada CloudTask executa ffmpeg para processar um objeto ResourceFile de entrada usando uma propriedade CommandLine. O ffmpeg anteriormente foi 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. Anteriormente no exemplo de código, uma URL de assinatura de acesso compartilhado (outputContainerSasUrl) foi obtida para fornecer acesso de gravação ao contêiner de saída. 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 AddTaskAsync, que os enfileira para execução 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 ffmpeg-4.3.1-2020-11-08-full_build de exemplo.

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

for (int i = 0; i < inputFiles.Count; i++)
{
    string taskId = String.Format("Task{0}", i);

    // Define task command line to convert each input file.
    string appPath = String.Format("%AZ_BATCH_APP_PACKAGE_{0}#{1}%", appPackageId, appPackageVersion);
    string inputMediaFile = inputFiles[i].FilePath;
    string outputMediaFile = String.Format("{0}{1}",
        System.IO.Path.GetFileNameWithoutExtension(inputMediaFile),
        ".mp3");
    string taskCommandLine = String.Format("cmd /c {0}\\ffmpeg-4.3.1-2020-09-21-full_build\\bin\\ffmpeg.exe -i {1} {2}", appPath, inputMediaFile, outputMediaFile);

    // Create a cloud task (with the task ID and command line)
    CloudTask task = new CloudTask(taskId, taskCommandLine);
    task.ResourceFiles = new List<ResourceFile> { inputFiles[i] };

    // Task output file
    List<OutputFile> outputFileList = new List<OutputFile>();
    OutputFileBlobContainerDestination outputContainer = new OutputFileBlobContainerDestination(outputContainerSasUrl);
    OutputFile outputFile = new OutputFile(outputMediaFile,
       new OutputFileDestination(outputContainer),
       new OutputFileUploadOptions(OutputFileUploadCondition.TaskSuccess));
    outputFileList.Add(outputFile);
    task.OutputFiles = outputFileList;
    tasks.Add(task);
}

// Add tasks as a collection
await batchClient.JobOperations.AddTaskAsync(jobId, tasks);
return tasks

Monitorar tarefas

Quando o Lote adiciona tarefas a um trabalho, o serviço as enfileira e agenda para execução em nós de computação no pool associado automaticamente. Com base nas configurações especificadas, o Lote manipula o enfileiramento, o agendamento, a repetição de todas as tarefas e outras obrigações de administração de tarefas.

Há muitas abordagens para o monitoramento da execução da tarefa. Esse exemplo define um método MonitorTasks para relatar apenas sobre estados de falha ou sucesso de tarefas e sua conclusão. O código MonitorTasks especifica um ODATADetailLevel para selecionar com eficiência apenas algumas informações sobre as tarefas. Em seguida, ele cria um TaskStateMonitor, que fornece utilitários auxiliares para monitorar os estados de tarefa. Em MonitorTasks, o exemplo aguarda até que todas as tarefas alcancem TaskState.Completed dentro de um limite de tempo. Em seguida, ele conclui o trabalho e relata as tarefas concluídas, mas com falhas de código de saída diferente de zero.

TaskStateMonitor taskStateMonitor = batchClient.Utilities.CreateTaskStateMonitor();
try
{
    await taskStateMonitor.WhenAll(addedTasks, TaskState.Completed, timeout);
}
catch (TimeoutException)
{
    batchClient.JobOperations.TerminateJob(jobId);
    Console.WriteLine(incompleteMessage);
    return false;
}
batchClient.JobOperations.TerminateJob(jobId);
 Console.WriteLine(completeMessage);
...

Limpar os recursos

Depois que ele executa as tarefas, o aplicativo exclui automaticamente o contêiner de armazenamento de entrada criado e oferece a opção de excluir o pool do Lote e o trabalho. As classes JobOperations e PoolOperations do BatchClient têm métodos de exclusão correspondentes, 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.
  • Autenticar com contas do Lote e de Armazenamento.
  • 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 cargas de trabalho em lote, consulte as amostras do C# do Lote no GitHub.