Esercitazione: Eseguire un carico di lavoro parallelo con Azure Batch usando l'API .NET
Usare Azure Batch per eseguire in modo efficiente processi batch paralleli e HPC (High Performance Computing) su larga scala in Azure. Questa esercitazione illustra un esempio C# di esecuzione di un carico di lavoro parallelo usando Batch. Vengono fornite informazioni su un flusso di lavoro dell'applicazione Batch comune e su come interagire a livello di codice con le risorse di Archiviazione e Batch. Si apprenderà come:
- Aggiungere un pacchetto dell'applicazione all'account Batch
- Eseguire l'autenticazione con gli account di archiviazione e Batch
- Caricare i file di input nella risorsa di archiviazione
- Creare un pool di nodi di calcolo per eseguire un'applicazione
- Creare un processo e le attività per elaborare i file di input
- Monitorare l'esecuzione delle attività
- Recuperare i file di output
In questa esercitazione file multimediali MP4 vengono convertiti in parallelo in formato MP3 usando lo strumento open source ffmpeg.
Se non si ha una sottoscrizione di Azure, creare un account Azure gratuito prima di iniziare.
Prerequisiti
Visual Studio 2017 o versione successiva o .NET Core 2.1 SDK per Linux, macOS o Windows.
Un account Batch e un account di archiviazione di Azure collegato. Per creare questi account, vedere le guide introduttive di Batch usando il portale di Azure o l'interfaccia della riga di comando di Azure.
Scaricare la versione appropriata di ffmpeg per il caso d'uso nel computer locale. Questa esercitazione e l'app di esempio correlata usano la versione a 64 bit di ffmpeg 4.3.1. Per questa esercitazione è necessario solo il file ZIP. Non è necessario decomprimere il file o installarlo in locale.
Accedere ad Azure
Accedere al portale di Azure all'indirizzo https://portal.azure.com.
Aggiungere un pacchetto dell'applicazione
Usare il portale di Azure per aggiungere ffmpeg all'account Batch come pacchetto dell'applicazione. I pacchetti dell'applicazione aiutano a gestire le applicazioni di attività e la loro distribuzione nei nodi di calcolo del pool.
- Nel portale di Azure fare clic su Altri servizi>Account Batch e quindi fare clic sul nome dell'account Batch.
- Fare clic su Applicazioni>Aggiungi.
- Per ID applicazione immettere ffmpeg e specificare 4.3.1 come versione del pacchetto. Selezionare il file ZIP ffmpeg scaricato in precedenza e quindi fare clic su OK. Il pacchetto dell'applicazione ffmpeg viene aggiunto all'account Batch.
Ottenere le credenziali dell'account
Per questo esempio, è necessario fornire le credenziali per gli account di archiviazione e Batch. Un modo semplice per ottenere le credenziali necessarie consiste nell'usare il portale di Azure. È anche possibile ottenere le credenziali usando le API di Azure o gli strumenti da riga di comando.
Selezionare Tutti i servizi>Account Batch e quindi selezionare il nome dell'account Batch.
Per visualizzare le credenziali di Batch, selezionare Chiavi. Copiare i valori di Account Batch, URL e Chiave di accesso primaria in un editor di testo.
Per visualizzare il nome e le chiavi dell'account di archiviazione, selezionare Account di archiviazione. Copiare i valori dei campi Nome account di archiviazione e Key1 in un editor di testo.
Scaricare ed eseguire l'esempio
Scaricare l'esempio
Scaricare o clonare l'app di esempio da GitHub. Per clonare il repository dell'app di esempio con un client Git, usare il comando seguente:
git clone https://github.com/Azure-Samples/batch-dotnet-ffmpeg-tutorial.git
Passare alla directory contenente il file di soluzione Visual Studio BatchDotNetFfmpegTutorial.sln
.
Aprire il file di soluzione in Visual Studio e aggiornare le stringhe delle credenziali in Program.cs
con i valori ottenuti per gli account. Ad esempio:
// Batch account credentials
private const string BatchAccountName = "mybatchaccount";
private const string BatchAccountKey = "xxxxxxxxxxxxxxxxE+yXrRvJAqT9BlXwwo1CwF+SwAYOxxxxxxxxxxxxxxxx43pXi/gdiATkvbpLRl3x14pcEQ==";
private const string BatchAccountUrl = "https://mybatchaccount.mybatchregion.batch.azure.com";
// Storage account credentials
private const string StorageAccountName = "mystorageaccount";
private const string StorageAccountKey = "xxxxxxxxxxxxxxxxy4/xxxxxxxxxxxxxxxxfwpbIC5aAWA8wDu+AFXZB827Mt9lybZB1nUcQbQiUrkPtilK5BQ==";
Nota
Per semplificare l'esempio, le credenziali dell'account di archiviazione e Batch vengono visualizzate in testo non crittografato. In pratica, è consigliabile limitare l'accesso alle credenziali e fare riferimento a esse nel codice usando variabili di ambiente o un file di configurazione. Per alcuni esempi, vedere l'archivio degli esempi di codice di Azure Batch.
Assicurarsi inoltre che il riferimento al pacchetto dell'applicazione ffmpeg nella soluzione corrisponda all'identificatore e alla versione del pacchetto ffmpeg caricato nell'account Batch. Ad esempio, ffmpeg
e 4.3.1
.
const string appPackageId = "ffmpeg";
const string appPackageVersion = "4.3.1";
Compilare ed eseguire il progetto di esempio
Compilare ed eseguire l'applicazione in Visual Studio oppure eseguire i comandi dotnet build
e dotnet run
dalla riga di comando. Dopo l'esecuzione dell'applicazione, esaminare il codice per comprendere le operazioni eseguite da ogni parte dell'applicazione. Ad esempio, in Visual Studio:
In Esplora soluzioni fare clic con il pulsante destro del mouse sulla soluzione e scegliere Compila soluzione.
Confermare il ripristino di eventuali pacchetti NuGet, se richiesto. Se è necessario scaricare i pacchetti mancanti, verificare che lo strumento Gestione pacchetti NuGet sia installato.
Eseguire quindi lo strumento. Quando si esegue l'applicazione di esempio, l'output della console è simile al seguente. Durante l'esecuzione si verifica una pausa in corrispondenza di Monitoring all tasks for 'Completed' state, timeout in 00:30:00...
mentre vengono avviati i nodi di calcolo del 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
Passare all'account Batch nel portale di Azure per monitorare il pool, i nodi di calcolo, il processo e le attività. Per visualizzare, ad esempio, una mappa termica dei nodi di calcolo nel pool, fare clic su Pool>WinFFmpegPool.
Quando le attività sono in esecuzione, la mappa termica è simile all'esempio seguente:
Quando si esegue l'applicazione con la configurazione predefinita, il tempo di esecuzione tipico è di circa 10 minuti. La maggior parte del tempo è necessaria per la creazione del pool.
Recuperare i file di output
È possibile usare il portale di Azure per scaricare i file MP3 di output generati dalle attività ffmpeg.
- Fare clic su Tutti i servizi> Accountdi archiviazione e quindi sul nome dell'account di archiviazione.
- Fare clic su Output BLOB>.
- Fare clic con il pulsante destro del mouse su uno dei file MP3 di output e quindi scegliere Scarica. Seguire i prompt nel browser per aprire o salvare il file.
Anche se non viene mostrato in questo esempio, è anche possibile scaricare i file a livello di codice dai nodi di calcolo o dal contenitore di archiviazione.
Esaminare il codice
Nelle sezioni seguenti si esamineranno in dettaglio i singoli passaggi eseguiti dall'applicazione di esempio per l'elaborazione di un carico di lavoro nel servizio Batch. Fare riferimento al file Program.cs
nella soluzione mentre si legge la parte restante di questo articolo, perché non vengono illustrate tutte le righe di codice dell'esempio.
Autenticare i client BLOB e Batch
Per interagire con l'account di archiviazione collegato, l'app usa la libreria client di Archiviazione di Azure per .NET. Crea un riferimento all'account con CloudStorageAccount ed esegue l'autenticazione usando l'autenticazione con chiave condivisa. Crea quindi un oggetto 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'app crea un oggetto BatchClient per creare e gestire pool, processi e attività nel servizio Batch. Il client Batch nell'esempio usa l'autenticazione con chiave condivisa. Batch supporta anche l'autenticazione con Azure Active Directory per autenticare singoli utenti o un'applicazione eseguita automaticamente.
BatchSharedKeyCredentials sharedKeyCredentials = new BatchSharedKeyCredentials(BatchAccountUrl, BatchAccountName, BatchAccountKey);
using (BatchClient batchClient = BatchClient.Open(sharedKeyCredentials))
...
Caricare i file di input
L'app passa l'oggetto blobClient
al metodo CreateContainerIfNotExistAsync
per creare un contenitore di archiviazione per i file di input (formato MP4) e un contenitore per l'output dell'attività.
CreateContainerIfNotExistAsync(blobClient, inputContainerName);
CreateContainerIfNotExistAsync(blobClient, outputContainerName);
I file vengono quindi caricati nel contenitore di input dalla cartella InputFiles
locale. I file nel contenitore di archiviazione sono definiti come oggetti ResourceFile di Batch che successivamente Batch può scaricare nei nodi di calcolo.
Per il caricamento dei file vengono usati due metodi in Program.cs
:
UploadFilesToContainerAsync
: restituisce una raccolta di oggetti ResourceFile e chiama internamenteUploadResourceFileToContainerAsync
per caricare ogni file passato nel parametroinputFilePaths
.UploadResourceFileToContainerAsync
: carica ogni file come BLOB nel contenitore di input. Dopo il caricamento del file, ottiene una firma di accesso condiviso per il BLOB e restituisce un oggetto ResourceFile che lo rappresenta.
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);
Per informazioni dettagliate sul caricamento di file come BLOB in un account di archiviazione con .NET, vedere Caricare, scaricare ed elencare BLOB con .NET.
Creare un pool di nodi di calcolo
L'esempio crea quindi un pool di nodi di calcolo nell'account Batch con una chiamata a CreatePoolIfNotExistAsync
. Questo metodo definito usa il metodo BatchClient.PoolOperations.CreatePool per impostare il numero di nodi, le dimensioni delle VM e una configurazione del pool. In questo caso, un oggetto VirtualMachineConfiguration specifica un oggetto ImageReference che fa riferimento a un'immagine di Windows Server pubblicata in Azure Marketplace. Batch supporta una vasta gamma di immagini di VM in Azure Marketplace, oltre che immagini di VM personalizzate.
Il numero di nodi e le dimensioni delle VM vengono impostati usando costanti definite. Batch supporta nodi dedicati e nodi Spot ed è possibile usare uno o entrambi i pool. I nodi dedicati sono riservati per il pool. I nodi spot sono offerti a un prezzo ridotto rispetto alla capacità di vm in eccesso in Azure. I nodi spot diventano non disponibili se Azure non dispone di capacità sufficiente. L'esempio crea per impostazione predefinita un pool contenente solo 5 nodi spot di dimensioni Standard_A1_v2.
Nota
Assicurarsi di controllare le quote del nodo. Per istruzioni su come creare una richiesta di aumento della quota, vedere Quote e i limiti del servizio Batch.
L'applicazione ffmpeg viene distribuita nei nodi di calcolo aggiungendo un oggetto ApplicationPackageReference alla configurazione del pool.
Il metodo CommitAsync invia il pool al servizio 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();
Creare un processo
Un processo Batch specifica un pool in cui eseguire le attività e impostazioni facoltative, ad esempio una priorità e una pianificazione per il lavoro. L'esempio crea un processo con una chiamata a CreateJobAsync
. Questo metodo definito usa il metodo BatchClient.JobOperations.CreateJob per creare un processo nel pool.
Il metodo CommitAsync invia il processo al servizio Batch. Inizialmente il processo è privo di attività.
CloudJob job = batchClient.JobOperations.CreateJob();
job.Id = JobId;
job.PoolInformation = new PoolInformation { PoolId = PoolId };
await job.CommitAsync();
Creare attività
L'esempio crea le attività del processo con una chiamata al metodo AddTasksAsync
, che crea un elenco di oggetti CloudTask. Ogni oggetto CloudTask
esegue ffmpeg per elaborare un oggetto ResourceFile
di input usando una proprietà CommandLine. Lo strumento ffmpeg è stato installato in precedenza in ogni nodo al momento della creazione del pool. In questo caso, la riga di comando esegue ffmpeg per convertire ogni file (video) MP4 di input in un file (audio) MP3.
L'esempio crea un oggetto OutputFile per il file MP3 dopo l'esecuzione della riga di comando. I file di output di ogni attività, in questo caso uno, vengono caricati in un contenitore nell'account di archiviazione collegato, usando la proprietà OutputFiles dell'attività. In precedenza nell'esempio di codice è stato ottenuto un URL di firma di accesso condiviso (outputContainerSasUrl
) per fornire accesso in scrittura al contenitore di output. Notare le condizioni impostate sull'oggetto outputFile
. Un file di output da un'attività viene caricato nel contenitore solo dopo il completamento corretto dell'attività (OutputFileUploadCondition.TaskSuccess
). Vedere l'esempio di codice completo su GitHub per altri dettagli sull'implementazione.
L'esempio aggiunge quindi le attività al processo con il metodo AddTaskAsync, che le accoda per l'esecuzione nei nodi di calcolo.
Sostituire il percorso del file eseguibile con il nome della versione scaricata. Questo codice di esempio usa l'esempio ffmpeg-4.3.1-2020-09-21-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
Monitorare le attività
Quando Batch aggiunge attività a un processo, il servizio le accoda automaticamente e ne pianifica l'esecuzione nei nodi di calcolo nel pool associato. In base alle impostazioni specificate, Batch gestisce tutte le operazioni di accodamento, pianificazione, ripetizione di tentativi e tutte le altre operazioni di amministrazione relative alle attività.
Sono disponibili molti approcci al monitoraggio dell'esecuzione delle attività. Questo esempio definisce un metodo MonitorTasks
che segnala solo gli stati di completamento ed esito positivo o negativo dell'attività. Il codice MonitorTasks
specifica un oggetto ODATADetailLevel per selezionare in modo efficiente solo informazioni minime sulle attività. Crea quindi un oggetto TaskStateMonitor, che fornisce utilità helper per il monitoraggio degli stati delle attività. In MonitorTasks
l'esempio attende che tutte le attività raggiungano uno stato TaskState.Completed
entro un limite di tempo. Termina quindi il processo e segnala le attività che sono state completate ma per cui potrebbe essersi verificato un errore, ad esempio un codice di uscita diverso da 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);
...
Pulire le risorse
Al termine dell'esecuzione delle attività, l'app elimina automaticamente il contenitore di archiviazione di input creato e consente di scegliere se eliminare il processo e il pool di Batch. Le classi JobOperations e PoolOperations di BatchClient hanno entrambe metodi di eliminazione corrispondenti, che vengono chiamati se l'utente conferma l'eliminazione. Anche se non vengono addebitati costi per i processi e per le attività, vengono invece addebiti costi per i nodi di calcolo. È quindi consigliabile allocare solo i pool necessari. Quando si elimina il pool, tutto l'output delle attività nei nodi viene eliminato. I file di output rimangono tuttavia nell'account di archiviazione.
Quando non sono più necessari, eliminare il gruppo di risorse, l'account Batch e l'account di archiviazione. A tale scopo, nel portale di Azure selezionare il gruppo di risorse per l'account Batch e fare clic su Elimina gruppo di risorse.
Passaggi successivi
In questa esercitazione sono state illustrate le procedure per:
- Aggiungere un pacchetto dell'applicazione all'account Batch
- Eseguire l'autenticazione con gli account di archiviazione e Batch
- Caricare i file di input nella risorsa di archiviazione
- Creare un pool di nodi di calcolo per eseguire un'applicazione
- Creare un processo e le attività per elaborare i file di input
- Monitorare l'esecuzione delle attività
- Recuperare i file di output
Per altri esempi di uso dell'API .NET per pianificare ed elaborare i carichi di lavoro di Batch, vedere gli esempi su GitHub.