Tutorial: Ejecución de una carga de trabajo paralela con Azure Batch mediante la API de .NET
Use Azure Batch para ejecutar aplicaciones de informática de alto rendimiento (HPC) en paralelo y a gran escala, de manera eficaz en Azure. Este tutorial le guía a través de un ejemplo de C# de ejecución de carga de trabajo paralela con Batch. Aprenderá lo que es un flujo de trabajo de aplicación de Batch común y a interactuar con los recursos de Batch y Storage mediante programación.
- Agregar un paquete de aplicación a la cuenta de Batch.
- Autenticarse en las cuentas de Batch y Storage.
- Cargar archivos de entrada en Storage.
- Crear un grupo de nodos de proceso para ejecutar una aplicación.
- Crear un trabajo y tareas para procesar archivos de entrada.
- Supervise la ejecución de las tareas.
- Recuperación de archivos de salida.
En este tutorial, convertiremos archivos multimedia MP4 a formato MP3 en paralelo con la herramienta de código de abierto ffmpeg.
Si no tiene una suscripción a Azure, cree una cuenta gratuita de Azure antes de empezar.
Requisitos previos
Visual Studio 2017 o superior o el SDK de .NET Core para Linux, macOS o Windows.
Una cuenta de Batch y una cuenta de Azure Storage vinculada. Para crear estas cuentas, consulte las guías de inicio rápido de Batch para Azure Portal o la CLI de Azure.
Descargue en el equipo local la versión de ffmpeg que mejor se adecúe a su caso de uso. En este tutorial, así como en la aplicación de ejemplo relacionada con este, se usa la versión completa de ffmpeg 4.3.1 para sistemas con Windows de 64 bits. Para este tutorial solo se necesita el archivo zip. No es necesario descomprimir el archivo ni instalarlo localmente.
Inicio de sesión en Azure
Inicie sesión en Azure Portal.
Incorporación de un paquete de aplicación
Use Azure Portal para agregar ffmpeg a la cuenta de Batch como paquete de aplicación. Los paquetes de aplicación ayudan a administrar aplicaciones de tareas y a implementarlas en los nodos de proceso del grupo.
En Azure Portal, seleccione Más servicios>Cuentas de Batch y en el nombre de la cuenta de Batch.
Haga clic en Aplicaciones>Agregar.
Escriba ffmpeg en el campo Id. de aplicación y una versión del paquete 4.3.1 en el campo Versión. Seleccione el archivo zip ffmpeg que ha descargado y, a continuación, seleccione Enviar. El paquete de aplicación de ffmpeg se agrega a la cuenta de Batch.
Obtención de credenciales de la cuenta
En este ejemplo, debe especificar las credenciales de las cuentas de Batch y Storage. Azure Portal es una manera sencilla de obtener las credenciales necesarias. (también se pueden obtener mediante las API de Azure o las herramientas de línea de comandos).
Seleccione Todos los servicios>Cuentas de Batch y, después, seleccione el nombre de la cuenta de Batch.
Para ver las credenciales de Batch, haga clic en Claves. Copie los valores de cuenta de Batch, URL y Clave de acceso principal en un editor de texto.
Para ver el nombre y las claves de la cuenta de almacenamiento, seleccione Cuenta de almacenamiento. Copie los valores de Nombre de la cuenta de almacenamiento y Key1 en un editor de texto.
Descarga y ejecución de la aplicación de ejemplo
Descarga de la aplicación de ejemplo
Descargue o clone la aplicación de ejemplo desde GitHub. Para clonar el repositorio de la aplicación de ejemplo con un cliente de Git, use el siguiente comando:
git clone https://github.com/Azure-Samples/batch-dotnet-ffmpeg-tutorial.git
Vaya al directorio que contiene el archivo BatchDotNetFfmpegTutorial.sln de la solución de Visual Studio.
Además, asegúrese de que la referencia del paquete de aplicación de ffmpeg de la solución coincida con el identificador y la versión del paquete de ffmpeg que cargó en la cuenta de Batch. Por ejemplo, ffmpeg
y 4.3.1
.
const string appPackageId = "ffmpeg";
const string appPackageVersion = "4.3.1";
Compilación y ejecución del proyecto de ejemplo
Compile y ejecute la aplicación en Visual Studio o en la línea de comandos con los comandos dotnet build
y dotnet run
. Después de ejecutar la aplicación, examine el código para ver qué es lo que hace cada parte de la aplicación. Por ejemplo, en Visual Studio:
Haga clic con el botón derecho en el Explorador de soluciones y seleccione Compilar solución.
Si se le solicita, confirme la restauración de los paquetes NuGet. Si necesita descargar los paquetes que faltan, asegúrese de que el Administrador de paquetes NuGet está instalado.
Ejecute la solución. Al ejecutar la aplicación de ejemplo, la salida de la consola es similar a la siguiente. Durante la ejecución, se experimenta una pausa en
Monitoring all tasks for 'Completed' state, timeout in 00:30:00...
mientras se inician los nodos de proceso del grupo.
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
Vaya a la cuenta de Batch de Azure Portal para supervisar el grupo, los nodos de proceso, el trabajo y las tareas. Por ejemplo, para ver un mapa térmico de los nodos de proceso del grupo, haga clic en Grupos>WinFFmpegPool.
Con las tareas en ejecución, el mapa térmico es similar al siguiente:
El tiempo de ejecución típico es de aproximadamente 10 minutos al ejecutar la aplicación con la configuración predeterminada. La creación del grupo es lo que más tarda.
Recuperación de archivos de salida
Puede usar Azure Portal para descargar los archivos MP3 de salida generados por las tareas de ffmpeg.
- Haga clic en Todos los servicios>Cuentas de almacenamiento y haga clic en el nombre de la cuenta de almacenamiento.
- Haga clic en Blobs>salida.
- Haga clic con el botón derecho en uno de los archivos MP3 de salida y, después, haga clic en Descargar. Para abrir o guardar el archivo, siga las indicaciones del explorador.
Aunque no se muestra en este ejemplo, los archivos también se pueden descargar mediante programación desde los nodos de proceso o desde el contenedor de almacenamiento.
Revisión del código
En las secciones siguientes se desglosan los pasos que lleva a cabo la aplicación de ejemplo para procesar una carga de trabajo en el servicio Batch. Consulte el archivo Program.cs en la solución mientras lee el resto de este artículo, ya que no se explican todas las líneas de código del ejemplo.
Autenticación de los clientes de Blob y Batch
Para interactuar con la cuenta de almacenamiento vinculada, la aplicación usa la biblioteca Azure.Storage.Blobs para .NET. Usar la claseBlobServiceClient que toma una referencia al URI de la cuenta y autentica el 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());
La aplicación crea una referencia al BatchAccountResource a través de la ArmClient del administrador de recursos para crear el grupo en el servicio Batch. El cliente Arm del ejemplo usa la autenticación DefaultAzureCredential.
ArmClient _armClient = new ArmClient(new DefaultAzureCredential());
var batchAccountIdentifier = ResourceIdentifier.Parse(BatchAccountResourceID);
BatchAccountResource batchAccount = await _armClient.GetBatchAccountResource(batchAccountIdentifier).GetAsync();
La aplicación crea un objeto BatchClient para crear trabajos y tareas en el servicio Batch. El cliente de Batch del ejemplo usa la autenticación 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());
Carga de archivos de entrada
La aplicación pasa el objeto blobServerClient
al método CreateContainerIfNotExistc
para crear un contenedor de almacenamiento para los archivos de entrada (formato MP4) y uno para la salida de la tarea.
CreateContainerIfNotExist(blobClient, inputContainerName);
CreateContainerIfNotExist(blobClient, outputContainerName);
A continuación, los archivos se cargan al contenedor de entrada desde la carpeta InputFiles local. Los archivos de almacenamiento se definen como objetos ResourceFile de Batch para que el servicio los descargue después en nodos de proceso.
En la carga de los archivos participan dos métodos de Program.cs:
UploadFilesToContainerAsync
: devuelve una colección de objetosResourceFile
y llama internamente aUploadResourceFileToContainerAsync
para cargar todos los archivos que se pasan en el parámetroinputFilePaths
.UploadResourceFileToContainerAsync
: carga los archivos como blobs en el contenedor de entrada. Después de cargar el archivo, obtiene una firma de acceso compartido (SAS) para el blob y devuelve un objetoResourceFile
que lo representa.
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 más información sobre cómo cargar archivos como blobs en una cuenta de almacenamiento con. NET, consulte Carga, descarga y enumeración de blobs mediante .NET.
Creación de un grupo de nodos de proceso
Después, en el ejemplo se crea un grupo de nodos de proceso en la cuenta de Batch con una llamada a CreatePoolIfNotExistAsync
. Este método definido usa el método BatchAccountResource.GetBatchAccountPools(). CreateOrUpdateAsync para establecer el número de nodos, el tamaño de la máquina virtual y una configuración de grupo. Aquí, un objeto BatchVmConfiguration especifica un BatchImageReference a una imagen de Windows Server publicada en Azure Marketplace. Batch es compatible con una amplia gama de imágenes de máquina virtual de Azure Marketplace, así como con las imágenes de máquina virtual personalizadas.
El número de nodos y el tamaño de la máquina virtual se establecen mediante constantes definidas. Batch admite nodos especializados y nodos de acceso puntual, y en los grupos puede utilizar ambos. Los nodos dedicados están reservados para el grupo. Los nodos de acceso puntual se ofrecen a precio reducido por la capacidad sobrante de las máquinas virtuales de Azure. Los nodos de acceso puntual dejan de estar disponibles si Azure no tiene capacidad suficiente. En el ejemplo, de forma predeterminada se crea un grupo que contiene solo 5 nodos de acceso puntual con el tamaño Standard_A1_v2.
Nota
Asegúrese de comprobar las cuotas de nodo. Consulte Límites y cuotas del servicio Batch para obtener instrucciones sobre cómo crear una solicitud de cuota.
La aplicación ffmpeg se implementa en los nodos de proceso mediante la incorporación de un valor ApplicationPackageReference a la configuración del grupo.
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;
Creación de un trabajo
Un trabajo de Batch especifica un grupo en el que ejecutar tareas y valores de configuración opcionales, como la prioridad y la programación del trabajo. En el ejemplo se crea un trabajo con una llamada a CreateJobAsync
. Este método definido usa el método BatchClient.CreateJobAsync para crear un trabajo en el grupo.
BatchJobCreateContent batchJobCreateContent = new BatchJobCreateContent(jobId, new BatchPoolInfo { PoolId = poolId });
await batchClient.CreateJobAsync(batchJobCreateContent);
Crear tareas
El ejemplo crea tareas en el trabajo con una llamada al método AddTasksAsync
, que crea una lista de objetos BatchTask . Los objetos BatchTask
ejecutan ffmpeg para procesar un objeto ResourceFile
de entrada con una propiedad CommandLine. Al crear el grupo, ffmpeg se instaló previamente en todos los nodos. En este caso, la línea de comandos ejecuta ffmpeg para convertir los archivos MP4 de entrada (vídeo) en archivos MP3 (audio).
En el ejemplo se crea un objeto OutputFile para el archivo MP3 después de ejecutar la línea de comandos. Los archivos de salida de la tarea (en este caso, uno) se cargan en un contenedor en la cuenta de Storage vinculada mediante la propiedad OutputFiles de la tarea. Tenga en cuenta las condiciones establecidas en el objeto outputFile
. Solo se carga un archivo de salida de una tarea en el contenedor después de que la tarea se haya completado correctamente (OutputFileUploadCondition.TaskSuccess
). Vea el código de ejemplo en GitHub para obtener más detalles sobre la implementación.
A continuación, el ejemplo agrega tareas al trabajo con el método CreateTaskAsync , que los pone en cola para ejecutarse en los nodos de proceso.
Reemplace la ruta de acceso del archivo ejecutable por el nombre de la versión que descargó. En este código de ejemplo se usa el ejemplo 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));
Limpieza de recursos
Después de ejecutar las tareas, la aplicación elimina automáticamente el contenedor de almacenamiento de entrada que creó y ofrece la opción de eliminar el grupo y el trabajo de Batch. BatchClient tiene un método para eliminar un trabajo DeleteJobAsync y eliminar un grupo DeletePoolAsync, al que se llama si confirma la eliminación. Aunque no se cobran los trabajos y las tareas, sí se cobran los nodos de proceso. Por consiguiente, se recomienda asignar solo los grupos necesarios. Al eliminar el grupo, las salidas de tarea de los nodos también se eliminan. Sin embargo, los archivos de salida permanecen en la cuenta de almacenamiento.
Cuando ya no los necesite, elimine el grupo de recursos, la cuenta de Batch y la de Storage. Para hacerlo desde Azure Portal, seleccione el grupo de recursos de la cuenta de Batch y haga clic en Eliminar grupo de recursos.
Pasos siguientes
En este tutorial, ha aprendido a:
- Agregar un paquete de aplicación a la cuenta de Batch.
- Autenticarse en las cuentas de Batch y Storage.
- Cargar archivos de entrada en Storage.
- Crear un grupo de nodos de proceso para ejecutar una aplicación.
- Crear un trabajo y tareas para procesar archivos de entrada.
- Supervise la ejecución de las tareas.
- Recuperación de archivos de salida.
Para más muestras de uso de la API de .NET para programar y procesar cargas de trabajo de Batch, consulte las muestras de Batch C# en GitHub.