Tutoriel : Exécuter une charge de travail parallèle avec Azure Batch à l’aide de l’API .NET

Utilisez Azure Batch pour exécuter des programmes de traitement par lots de calcul haute performance (HPC) en parallèle, efficacement et à grande échelle dans Azure. Ce didacticiel vous permet de découvrir un exemple d’exécution C# d’une charge de travail parallèle utilisant Batch. Vous découvrez un workflow d’application Batch courant et comment interagir par programme avec les ressources de stockage et Batch.

  • Ajouter un package d’application à votre compte Batch.
  • S’authentifier avec des comptes de stockage et Batch.
  • Charger des fichiers d’entrée sur le stockage.
  • Créer un pool de nœuds de calcul pour exécuter une application.
  • Créer un travail et des tâches pour traiter les fichiers d’entrée.
  • Surveiller l’exécution d’une tâche.
  • Récupérer les fichiers de sortie.

Dans ce tutoriel, vous convertissez des fichiers multimédias MP4 au format MP3, en parallèle, à l’aide de l’outil open source ffmpeg.

Si vous n’avez pas d’abonnement Azure, créez un compte gratuit Azure avant de commencer.

Prérequis

Connexion à Azure

Connectez-vous au portail Azure.

Ajouter un package d’application

Utiliser le portail Azure pour ajouter ffmpeg à votre compte Batch en tant que package d’application. Les packages d’application permettent de gérer les applications de tâche et leur déploiement sur les nœuds de calcul dans votre pool.

  1. Dans le portail Azure, cliquez sur Plus de services>Comptes Batch, puis sélectionnez le nom de votre compte Batch.

  2. Cliquez sur Applications>Ajouter.

    Screenshot of the Applications section of the batch account.

  3. Entrez ffmpeg dans le champ ID d’application et la version de package 4.3.1 dans le champ Version. Sélectionnez le fichier zip ffmpeg que vous avez téléchargé, puis sélectionnez Envoyer. Le package d’application ffmpeg est ajouté à votre compte Batch.

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

Obtenir les informations d’identification du compte

Dans le cadre de cet exemple, vous devez fournir les informations d’identification de vos comptes Azure Batch et de stockage. Pour obtenir rapidement les informations d’identification nécessaires, dirigez-vous vers le portail Azure. (Vous pouvez aussi les obtenir avec les API Azure ou des outils en ligne de commande.)

  1. Sélectionnez Tous les services>Comptes Batch, puis le nom de votre compte Batch.

  2. Pour voir les informations d’identification Batch, sélectionnez Clés. Copiez les valeurs des champs Compte Batch, URL et Clé d’accès principale dans un éditeur de texte.

  3. Pour voir le nom et les clés du compte de stockage, sélectionnez Compte de stockage. Copiez les valeurs des champs Nom du compte de stockage et Clé1 dans un éditeur de texte.

Télécharger et exécuter l’exemple d’application

Télécharger l’exemple d’application

Téléchargez ou clonez l’exemple d’application à partir de GitHub. Pour cloner le référentiel d’exemple d’application avec un client Git, utilisez la commande suivante :

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

Accédez au répertoire qui contient le fichier de la solution Visual Studio BatchDotNetFfmpegTutorial.sln.

Ouvrez le fichier de la solution dans Visual Studio et mettez à jour les chaînes d’informations d’identification dans Program.cs avec les valeurs obtenues pour vos comptes. Par exemple :

// 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==";

Notes

Pour simplifier l’exemple, les informations d’identification Batch et du compte de stockage sont affichées en texte clair. Dans la pratique, nous vous recommandons de limiter l’accès aux informations d’identification et d’y faire référence dans votre code à l’aide de variables d’environnement ou d’un fichier de configuration. Pour obtenir des exemples, consultez le référentiel d’exemples de code Azure Batch.

Vérifiez également que la référence du package d’application ffmpeg de la solution correspond à l’identificateur et à la version du package ffmpeg chargée sur votre compte Batch. Par exemple : ffmpeg et 4.3.1.

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

Créer et exécuter l’exemple de projet

Générez et exécutez l’application dans Visual Studio ou sur la ligne de commande avec les commandes dotnet build et dotnet run. Après avoir exécuté l’application, passez en revue le code pour savoir ce que fait chaque partie de l’application. Par exemple, dans Visual Studio :

  1. Cliquez avec le bouton droit sur la solution dans l’Explorateur de solutions, puis sélectionnez Générer la solution.

  2. Si vous y êtes invité, confirmez la restauration de tous les packages NuGet. Si vous devez télécharger des packages manquants, vérifiez que le Gestionnaire de Package NuGet est installé.

  3. Exécutez la solution. Lorsque vous exécutez l’exemple d’application, la sortie de la console est identique à ce qui suit. Pendant l’exécution, l’étape Monitoring all tasks for 'Completed' state, timeout in 00:30:00... fait l’objet d’une pause correspondant au démarrage des nœuds de calcul du pool.

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

Accédez à votre compte Batch dans le portail Azure pour surveiller le pool, les nœuds de calcul, les travaux et les tâches. Par exemple, pour voir une carte thermique des nœuds de calcul de votre pool, cliquez sur Pools>WinFFmpegPool.

Lorsque les tâches sont en cours d’exécution, la carte thermique est similaire à ce qui suit :

Screenshot of the pool heat map in the Azure portal.

Le temps d’exécution standard est d’environ 10 minutes lorsque l’application fonctionne dans sa configuration par défaut. La création d’un pool est l’opération la plus longue.

Récupérer les fichiers de sortie

Vous pouvez utiliser le portail Azure pour télécharger les fichiers de sortie MP3 générés par les tâches ffmpeg.

  1. Cliquez sur Tous les services>Comptes de stockage, puis sur le nom de votre compte de stockage.
  2. Cliquez sur BLOB>sortie.
  3. Cliquez avec le bouton droit sur l’un des fichiers de sortie MP3 puis cliquez sur Télécharger. Suivez les invites dans votre navigateur pour ouvrir ou enregistrer le fichier.

Download output file

Même si ce n’est pas montré dans cet exemple, vous pouvez aussi télécharger les fichiers par programmation depuis les nœuds de calcul ou depuis le conteneur de stockage.

Vérifier le code

Dans les sections suivantes, nous examinons l’exemple d’application en nous servant des opérations qu’elle effectue pour traiter une charge de travail dans le service Batch. Référez-vous au fichier Program.cs dans la solution quand vous lisez le reste de cet article, car certaines lignes de code de cet exemple ne sont pas expliquées ici.

Authentifier les clients Blob et Batch

Pour interagir avec le compte de stockage lié, l’application utilise la bibliothèque cliente de stockage Azure pour .NET. Elle crée une référence au compte avec CloudStorageAccount avec authentification de la clé partagée. Ensuite, elle crée un 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();

L’application crée un objet BatchClient pour créer et gérer des pools, des travaux et des tâches dans le service Batch. Le client Batch dans l’exemple utilise l’authentification de la clé partagée. Batch prend également en charge l’authentification via Microsoft Entra ID pour authentifier des utilisateurs ou une application sans assistance.

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

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

Charger des fichiers d’entrée

L’application transmet l’objet blobClient à la méthode CreateContainerIfNotExistAsync pour créer un conteneur de stockage pour les fichiers d’entrée (format MP4) et un conteneur pour la sortie de la tâche.

CreateContainerIfNotExistAsync(blobClient, inputContainerName);
CreateContainerIfNotExistAsync(blobClient, outputContainerName);

Ensuite, les fichiers sont chargés dans le conteneur d’entrée à partir du dossier InputFiles local. Les fichiers de stockage sont définis en tant qu’objets Batch ResourceFile que Batch peut télécharger ultérieurement sur les nœuds de calcul.

Deux méthodes de Program.cs sont impliquées dans le chargement des fichiers :

  • UploadFilesToContainerAsync : retourne une collection d’objets ResourceFile et appelle UploadResourceFileToContainerAsync en interne pour charger chaque fichier transmis dans le paramètre inputFilePaths.
  • UploadResourceFileToContainerAsync: charge chaque fichier en tant qu’objet blob dans le conteneur d’entrée. Après le chargement du fichier, la méthode obtient une signature d’accès partagé (SAP) pour l’objet blob et renvoie un objet ResourceFile pour la représenter.
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);

Pour plus d’informations sur le chargement de fichiers en tant qu’objets blob sur un compte de stockage avec .NET, consultez Upload, download, and list blobs using .NET (Charger, télécharger et répertorier des objets blob à l’aide de .NET).

Créer un pool de nœuds de calcul

Ensuite, l’exemple crée un pool de nœuds de traitement dans le compte Batch, avec un appel à CreatePoolIfNotExistAsync. Cette méthode définie utilise la méthode BatchClient.PoolOperations.CreatePool pour définir le nombre de nœuds, la taille de la machine virtuelle et une configuration de pool. Ici, un objet VirtualMachineConfiguration spécifie une référence ImageReference à une image Windows Server publiée dans la Place de marché Microsoft Azure. Azure Batch prend en charge une large plage de machine virtuelle dans la Place de marché Microsoft Azure, ainsi que des images de machines virtuelles personnalisées.

Le nombre de nœuds et la taille de machine virtuelle sont définis à l’aide de constantes définies. Azure Batch prend en charge les nœuds dédiés et les nœuds de faible priorité que vous pouvez utiliser dans vos pools. Les nœuds dédiés sont réservés à votre pool. Les nœuds de faible priorité sont proposés à prix réduit à partir de la capacité de machine virtuelle excédentaire dans Azure. Les nœuds de faible priorité deviennent indisponibles si la capacité d’Azure est insuffisante. L’exemple par défaut crée un pool contenant seulement 5 nœuds de faible priorité taille Standard_A1_v2.

Notes

Veillez à vérifier vos quotas de nœud. Consultez l’article Quotas et limites du service Batch pour obtenir des instructions sur la création d’une demande de quota.

L’application ffmpeg est déployée sur les nœuds de calcul en ajoutant un ApplicationPackageReference à la configuration du pool.

La méthode CommitAsync soumet le pool au service Batch.

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

Créer un travail

Un programme de traitement par lots spécifie un pool pour exécuter des tâches et des paramètres facultatifs tels qu’une priorité et un calendrier pour le travail. L’exemple crée un travail avec un appel à CreateJobAsync. Cette méthode définie utilise la méthode BatchClient.JobOperations.CreateJob pour créer un travail sur le pool.

La méthode CommitAsync soumet le travail au service Batch. Dans un premier temps, le travail n’a aucune tâche.

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

await job.CommitAsync();

Créer des tâches

L’exemple crée des tâches dans le travail avec un appel à la méthode AddTasksAsync, ce qui crée une liste d’objets CloudTask. Chaque CloudTask exécute ffmpeg pour traiter un objet ResourceFile d’entrée à l’aide de la propriété CommandLine. ffmpeg a été précédemment installé sur chaque nœud lors de la création du pool. Ici, la ligne de commande exécute ffmpeg pour convertir chaque fichier (vidéo) MP4 en fichier MP3 (audio).

L’exemple crée un objet OutputFile pour le fichier MP3 après l’exécution de la ligne de commande. Les fichiers de sortie de chaque tâche (un, dans ce cas) sont chargés sur un conteneur dans le compte de stockage lié, à l’aide de la propriété OutputFiles. Précédemment dans l’exemple de code, une URL de signature d’accès partagé (outputContainerSasUrl) a été obtenue pour fournir un accès en écriture au conteneur de sortie. Notez les conditions définies sur l’objet outputFile. Un fichier de sortie d’une tâche est chargé sur le conteneur seulement une fois la tâche terminée avec succès (OutputFileUploadCondition.TaskSuccess). Pour plus de détails sur l’implémentation, consultez l’exemple de code complet sur GitHub.

Ensuite, l’exemple ajoute des tâches au travail avec la méthode AddTaskAsync, qui les met en file d’attente afin de les exécuter sur les nœuds de calcul.

Remplacez le chemin d’accès du fichier exécutable par le nom de la version que vous avez téléchargée. Cet exemple de code utilise l’exemple ffmpeg-4.3.1-2020-11-08-full_build.

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

Surveiller les tâches

Lorsque Batch ajoute des tâches à un travail, le service les met automatiquement en file d’attente et planifie leur exécution sur les nœuds de calcul dans le pool associé. Selon les paramètres que vous spécifiez, Batch gère l’ensemble des opérations de mise en file d’attente, de planification, de ré-exécution et d’administration des tâches.

Il existe plusieurs approches pour l’exécution de la tâche d’analyse. Cet exemple définit une méthode MonitorTasks pour signaler uniquement l’achèvement d’une tâche ou son échec ou les états réussis. Le code MonitorTasks spécifie un ODATADetailLevel pour sélectionner efficacement uniquement un minimum d’informations sur les tâches. Ensuite, il crée un TaskStateMonitor, qui fournit des utilitaires d’assistance pour l’analyse des états de la tâche. Dans MonitorTasks, l’exemple attend que toutes les tâches atteignent TaskState.Completed dans un délai imparti. Puis, il met fin au travail et signale toutes les tâches terminées, mais pouvant avoir subi une défaillance, telle qu’un code de sortie différent de zéro.

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

Nettoyer les ressources

Après avoir exécuté les tâches, l’application supprime automatiquement le conteneur de stockage d’entrée créé et vous donne la possibilité de supprimer le travail et le pool Azure Batch. Les classes JobOperations et PoolOperations de BatchServiceClient disposent toutes deux de méthodes de suppression correspondantes, appelées si l’utilisateur confirme la suppression. Bien que vous ne soyez pas facturé pour les travaux et les tâches à proprement parler, les nœuds de calcul vous sont facturés. Par conséquent, nous vous conseillons d’affecter les pools uniquement en fonction des besoins. Lorsque vous supprimez le pool, toutes les sorties de tâche sur les nœuds sont supprimées. Toutefois, les fichiers de sortie restent dans le compte de stockage.

Lorsque vous n’en avez plus besoin, supprimez le groupe de ressources, le compte Batch et le compte de stockage. Pour ce faire, dans le portail Azure, sélectionnez le groupe de ressources pour le compte Batch, puis cliquez sur Supprimer le groupe de ressources.

Étapes suivantes

Dans ce didacticiel, vous avez appris à :

  • Ajouter un package d’application à votre compte Batch.
  • S’authentifier avec des comptes de stockage et Batch.
  • Charger des fichiers d’entrée sur le stockage.
  • Créer un pool de nœuds de calcul pour exécuter une application.
  • Créer un travail et des tâches pour traiter les fichiers d’entrée.
  • Surveiller l’exécution d’une tâche.
  • Récupérer les fichiers de sortie.

Pour plus d’exemples d’utilisation de l’API .NET pour planifier et traiter les charges de travail Batch, consultez les exemples C# Batch sur GitHub.