Tutorial: Executar uma carga de trabalho paralela com o Azure Batch através da API .NET

Utilize o Azure Batch para executar trabalhos de lote de computação de alto desempenho (HPC) e paralelos em larga escala de forma eficaz no Azure. Este tutorial guia-o por um exemplo C# de execução de uma carga de trabalho paralela com o Batch. Obteve mais informações sobre um fluxo de trabalho de aplicações do Batch comum e como interagir programaticamente com recursos do Batch e de Armazenamento.

  • Adicione um pacote de aplicativos à sua conta do Batch.
  • Autentique-se com contas de lote e armazenamento.
  • Carregue arquivos de entrada para o armazenamento.
  • Crie um pool de nós de computação para executar um aplicativo.
  • Crie um trabalho e tarefas para processar arquivos de entrada.
  • Monitore a execução da tarefa.
  • Recupere arquivos de saída.

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

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

Pré-requisitos

  • Visual Studio 2017 ou posterior, ou SDK do .NET Core para Linux, macOS ou Windows.

  • Uma conta do Batch e uma conta de Armazenamento do Microsoft Azure associada. Para criar essas contas, consulte os guias de início rápido em lote para o portal do Azure ou a CLI do Azure.

  • Faça o download da versão apropriada do ffmpeg para o seu caso de uso para o seu computador local. Este tutorial e o aplicativo de exemplo relacionado usam a versão de compilação completa do Windows de 64 bits do ffmpeg 4.3.1. Para este tutorial, você só precisa do arquivo zip. Não tem de deszipar o ficheiro ou instalá-lo localmente.

Iniciar sessão no Azure

Inicie sessão no portal do Azure.

Adicionar um pacote de aplicação

Utilize o portal do Azure para adicionar o ffmpeg à sua conta do Batch como um pacote de aplicação. Os pacotes de aplicação ajudam a gerir aplicações de tarefas e a respetiva implementação em nós de computação do conjunto.

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

  2. Clique em Aplicações>Adicionar.

    Captura de ecrã da secção Aplicações da conta em lote.

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

    Captura de ecrã dos campos ID e versão na secção Adicionar aplicação.

Obter credenciais da conta

Neste exemplo, tem de apresentar as credenciais para as contas do Batch e de Armazenamento. É uma forma simples de obter as credenciais necessárias no portal do Azure. (Também pode obter estas credenciais com as APIs do Azure ou as ferramentas de linha de comandos.)

  1. Selecione Todas as contas de Lote de serviços>e, em seguida, selecione o nome da sua conta de Lote.

  2. Para ver as credenciais do lote, selecione Chaves. Copie os valores da conta do Batch, o URL e a 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 do Nome da conta de armazenamento e Chave1 para um editor de texto.

Baixe e execute o aplicativo de exemplo

Transferir a aplicação de exemplo

Transfira ou clonar a aplicação de exemplo a partir do GitHub. Para clonar o repositório de aplicações de exemplo com um cliente Git, utilize 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, certifique-se de que a referência do pacote de aplicativo ffmpeg na solução corresponda ao identificador e à versão do pacote ffmpeg que você carregou para sua conta em lote. Por exemplo, ffmpeg e 4.3.1.

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

Compilar e executar o projeto de exemplo

Crie e execute a aplicação no Visual Studio ou na linha de comandos com os comandos dotnet build e dotnet run. Depois de executar a aplicação, reveja o código para saber o que faz cada parte da aplicação. Por exemplo, no Visual Studio:

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

  2. Confirme o restauro de quaisquer pacotes NuGet, se lhe for pedido. Se precisar de transferir pacotes em falta, certifique-se de que o NuGet Package Manager está instalado.

  3. Execute a solução. Quando executar a aplicação de exemplo, o resultado da consola é semelhante ao seguinte. Durante a execução, ocorre uma pausa em Monitoring all tasks for 'Completed' state, timeout in 00:30:00... enquanto os nós de computação do conjunto 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

Aceda à conta do Batch no portal do Azure para monitorizar o conjunto, os nós de computação, o trabalho e as tarefas. Por exemplo, para ver um mapa érmico dos nós de computação no conjunto, clique em Conjuntos>WinFFmpegPool.

Quando as tarefas estiverem em execução, o mapa térmico é semelhante ao seguinte:

Captura de ecrã do mapa de calor do pool no portal do Azure.

O tempo de execução normal é de aproximadamente 10 minutos quando executa a aplicação na configuração predefinida. A criação do conjunto demora mais tempo.

Obter ficheiros de saída

Pode utilizar o portal do Azure para transferir os ficheiros MP3 de saída gerados pelas tarefas ffmpeg.

  1. Clique em Todos os serviços>Contas de armazenamento e, em seguida, clique no nome da sua conta de armazenamento.
  2. Clique em Blobs>saída.
  3. Clique com o botão direito do rato em um dos ficheiros MP3 de saída e, em seguida, clique em Transferir. Siga as instruções no seu browser para abrir ou guardar o ficheiro.

Transfira o ficheiro de saída

Apesar de não estar mostrado neste exemplo, também pode transferir os ficheiros programaticamente a partir dos nós de computação ou do contentor de armazenamento.

Rever o código

As secções seguintes dividem a aplicação de exemplo nos passos que executa para processar uma carga de trabalho no serviço Batch. Consulte o Program.cs de arquivo na solução enquanto lê o restante deste artigo, já que nem todas as linhas de código no exemplo são discutidas.

Autenticar clientes Blob e Batch

Para interagir com a conta de armazenamento vinculada, o aplicativo usa a Biblioteca Azure.Storage.Blobs para .NET. Usando a classe BlobServiceClient que usa uma referência ao Uri da conta e autenticando 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 gerenciador de recursos 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 Batch no exemplo usa a autenticação 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 ficheiros de entrada

A aplicação transmite o objeto blobServerClient ao método CreateContainerIfNotExistc para criar um contentor de armazenamento para os ficheiros de entrada (formato MP4) e um contentor para o resultado da tarefa.

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

Em seguida, os arquivos são carregados para o contêiner de entrada da pasta InputFiles local. Os ficheiros no armazenamento estão definidos como objetos ResourceFile que o Batch pode transferir 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 ResourceFile objetos e chamadas UploadResourceFileToContainerAsync internas para carregar cada arquivo que é passado no inputFilePaths parâmetro.
  • UploadResourceFileToContainerAsync: carrega cada ficheiro como um blob para o contentor de entrada. Depois de carregar o arquivo, ele obtém uma assinatura de acesso compartilhado (SAS) para o blob e retorna um ResourceFile objeto 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 mais informações sobre como carregar ficheiros como blobs para uma conta de armazenamento com o .NET, veja Carregar, transferir e listar blobs com o .NET.

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

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

O número de nós e o tamanho da VM são definidos através de constantes definidas. O Batch suporta nós dedicados e nós Spot, e você pode usar um ou ambos em seus pools. Os nós dedicados estão reservados para o conjunto. Os nós spot são oferecidos a um preço reduzido a partir da capacidade excedente da VM no Azure. Os nós spot ficam indisponíveis se o Azure não tiver capacidade suficiente. O exemplo por padrão cria um pool contendo apenas 5 nós Spot em tamanho Standard_A1_v2.

Nota

Certifique-se de verificar suas cotas de nó. Consulte Cotas e limites de serviço em lote para obter instruções sobre como criar uma solicitação de cota.

A aplicação ffmpeg é implementada nos nós de computação ao adicionar ApplicationPackageReference à configuração do conjunto.

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(appPacakgeResourceID))
                    {
                        Version = appPackageVersion,
                    }
            },

        });
    BatchAccountPoolResource pool = armOperation.Value;

Criar um trabalho

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

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

Criar tarefas

O exemplo cria tarefas no trabalho com uma chamada para o AddTasksAsync método, que cria uma lista de objetos BatchTask . Cada BatchTask executa o ffmpeg para processar um objeto de entrada ResourceFile através de uma propriedade CommandLine. O ffmpeg foi instalado anteriormente em cada nó quando o conjunto foi criado. Aqui, a linha de comandos executa o ffmpeg para converter cada ficheiro MP4 (vídeo) de entrada num ficheiro MP3 (áudio).

O exemplo cria um objeto OutputFile para o ficheiro MP3 depois de executar a linha de comandos. Os ficheiros de saída de cada tarefa (um, neste caso) são carregados para um contentor na conta de armazenamento associada através da propriedade OutputFiles da tarefa. Observe as outputFile condições definidas no objeto. Um arquivo de saída de uma tarefa só é carregado no contêiner depois que a tarefa é concluída com êxito (OutputFileUploadCondition.TaskSuccess). Consulte 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 que você baixou. 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<BatchTaskCreateContent> tasks = new List<BatchTaskCreateContent>();

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].StorageContainerUrl;
    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

    BatchTaskCreateContent batchTaskCreateContent = new BatchTaskCreateContent(taskId, taskCommandLine);
    batchTaskCreateContent.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("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));
    batchTaskCreateContent.OutputFiles.Add(outputFile);

    tasks.Add(batchTaskCreateContent);
}

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

Clean up resources (Limpar recursos)

Depois de executar as tarefas, a aplicação elimina automaticamente o contentor de armazenamento de entrada que criou e dá-lhe a opção de eliminar o conjunto 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. Apesar de os próprios trabalhos e tarefas não lhe serem cobrados, os nós de computação são cobrados. Assim, recomendamos que atribua conjuntos apenas conforme necessário. Quando eliminar o conjunto, todos os resultados da tarefa nos nós são eliminados. No entanto, os ficheiros de saída permanecem na conta de armazenamento.

Quando já não forem necessários, elimine o grupo de recursos, a conta do Batch e a conta de armazenamento. Para tal, no portal do Azure, selecione o grupo de recursos da conta do Batch e clique em Eliminar grupo de recursos.

Próximos passos

Neste tutorial, ficou a saber como:

  • Adicione um pacote de aplicativos à sua conta do Batch.
  • Autentique-se com contas de lote e armazenamento.
  • Carregue arquivos de entrada para o armazenamento.
  • Crie um pool de nós de computação para executar um aplicativo.
  • Crie um trabalho e tarefas para processar arquivos de entrada.
  • Monitore a execução da tarefa.
  • Recupere arquivos de saída.

Para obter mais exemplos de como usar a API do .NET para agendar e processar cargas de trabalho em lote, consulte os exemplos de C# em lote no GitHub.