Utilizzare attività con istanze multiple per eseguire applicazioni MPI (Message Passing Interface) in Batch

Le attività a istanze multiple permettono di eseguire un'attività di Azure Batch in più nodi di calcolo contemporaneamente Queste attività permettono scenari di calcolo ad alte prestazioni come le applicazioni MPI (Message Passing Interface) su Batch. In questo articolo viene illustrato come eseguire attività multiistanza utilizzando la libreria Azure.Compute.Batch.

Nota

Mentre gli esempi in questo articolo si concentrano su Azure. Compute.Batch, MS-MPI e Windows nodi di calcolo, i concetti relativi alle attività a istanze multiple descritte di seguito sono applicabili ad altre piattaforme e tecnologie (ad esempio Python e Intel MPI nei nodi Linux).

Panoramica sulle attività a istanze multiple

In Batch ogni attività viene in genere eseguita in un singolo nodo di calcolo, si inviano più attività a un processo e il servizio Batch pianifica l'esecuzione di ogni attività in un nodo. Tuttavia, configurando le impostazioni per istanze multiple, si indica a Batch invece di creare un'attività primaria e svariate sottoattività per che quindi sono eseguite su più nodi.

Diagramma che mostra una panoramica delle impostazioni a istanze multiple.

Quando si invia a un processo un'attività con impostazioni per istanze multiple, Batch esegue diversi passaggi relativi esclusivamente alle attività a istanze multiple:

  1. Il servizio Batch crea un'attività primaria e diverse sottoattività in base alle impostazioni multi-istanza. Il numero totale di attività, ovvero quella primaria e tutte le sottoattività, corrisponde al numero di istanze (nodi di calcolo) specificato nelle impostazioni per istanze multiple.
  2. Il servizio Batch definisce uno dei nodi di calcolo come master e pianifica l'attività primaria da eseguire sul master. Pianifica le sottoattività da eseguire sugli altri nodi di calcolo allocati all'attività a istanze multiple, una sottoattività per ogni nodo.
  3. L'attività primaria e tutte le sottoattività scaricano gli eventuali file di risorse comuni specificati nelle impostazioni per istanze multiple.
  4. Dopo aver scaricato i file di risorse comuni, l'attività primaria e le sottoattività eseguono il comando di coordinamento specificato nelle impostazioni per istanze multiple. Il comando di coordinamento viene usato in genere per preparare i nodi per l'esecuzione dell'attività. Un esempio è l'avvio di servizi in background, come di Microsoft MPIsmpd.exe, e la verifica che i nodi siano pronti per elaborare messaggi tra i nodi.
  5. L'attività primaria esegue il comando applicazione sul nodo master dopo il completamento del comando di coordinamento da parte dell'attività primaria e di tutte le sottoattività. Il comando applicazione, vale a dire la riga di comando dell'attività a istanze multiple stessa, viene eseguito solo dall'attività primaria. In una soluzione basata su MS-MPI si esegue l'applicazione abilitata per MPI usando mpiexec.exe.

Nota

Anche se è funzionalmente distinto, l'attività a istanze multipli non è un tipo di attività univoco, ad esempio BatchStartTask o BatchJobPreparationTask. L'attività a istanze multipli è semplicemente un'attività Batch standard (BatchTask in Azure. Compute.Batch) le cui impostazioni multiistanza sono state configurate. In questo articolo viene definita attività a istanze multiple.

Requisiti delle attività a istanze multiple

Per le attività a istanze multiple è necessario un pool in cui sia abilitata la comunicazione tra i nodi e disabilitata l'esecuzione di attività simultanee. Per disabilitare l'esecuzione di attività simultanee, impostare la proprietà BatchAccountPoolData.TaskSlotsPerNode su 1.

Nota

Batch limita le dimensioni di un pool per cui è abilitata la comunicazione tra i nodi.

Questo frammento di codice illustra come creare un pool per attività multiistanza utilizzando la libreria Azure.ResourceManager.Batch.

ArmClient armClient = new ArmClient(new DefaultAzureCredential());

ResourceIdentifier batchAccountResourceId =
    BatchAccountResource.CreateResourceIdentifier("subscriptionId", "resourceGroupName", "accountName");
BatchAccountResource batchAccount = armClient.GetBatchAccountResource(batchAccountResourceId);

BatchAccountPoolCollection poolCollection = batchAccount.GetBatchAccountPools();

BatchAccountPoolData poolData = new BatchAccountPoolData()
{
    VmSize = "standard_d1_v2",
    DeploymentConfiguration = new BatchDeploymentConfiguration()
    {
        VmConfiguration = new BatchVmConfiguration(
            imageReference: new BatchImageReference()
            {
                Publisher = "MicrosoftWindowsServer",
                Offer = "WindowsServer",
                Sku = "2019-datacenter-core",
                Version = "latest"
            },
            nodeAgentSkuId: "batch.node.windows amd64")
    },
    ScaleSettings = new BatchAccountPoolScaleSettings()
    {
        FixedScale = new BatchAccountFixedScaleSettings() { TargetDedicatedNodes = 3 }
    },

    // Multi-instance tasks require inter-node communication, and those nodes
    // must run only one task at a time.
    InterNodeCommunication = InterNodeCommunicationState.Enabled,
    TaskSlotsPerNode = 1
};

Nota

Se si tenta di eseguire un'attività a più istanze in un pool con comunicazione internode disabilitata o con un valore taskSlotsPerNode maggiore di 1, l'attività non viene mai pianificata, ma rimane illimitata nello stato "attivo".

I pool con InterComputeNodeCommunication abilitato non consentono automaticamente il deprovisioning del nodo.

Utilizzare uno StartTask per installare MPI

Per eseguire applicazioni MPI con un'attività a più istanze, è necessario innanzitutto installare un'implementazione MPI (MS-MPI o Intel MPI, ad esempio) sui nodi di calcolo nel pool. Questo è un buon momento per usare batchAccountPoolStartTask, che viene eseguito ogni volta che un nodo viene aggiunto a un pool o viene riavviato. Questo frammento di codice aggiunge un'attività di avvio alla definizione del pool che specifica il pacchetto di installazione MS-MPI come file di risorse. La riga di comando dell'attività di avvio viene eseguita dopo avere scaricato il file di risorse sul nodo. In questo caso, la riga di comando esegue un'installazione automatica di MS-MPI.

// Add a start task to the pool which we use for installing MS-MPI on
// the nodes as they join the pool (or when they are restarted).
poolData.StartTask = new BatchAccountPoolStartTask()
{
    CommandLine = "cmd /c MSMpiSetup.exe -unattend -force",
    UserIdentity = new BatchUserIdentity()
    {
        AutoUser = new BatchAutoUserSpecification() { ElevationLevel = BatchUserAccountElevationLevel.Admin }
    },
    WaitForSuccess = true,
};
poolData.StartTask.ResourceFiles.Add(new BatchResourceFile()
{
    HttpUri = new Uri("https://mystorageaccount.blob.core.windows.net/mycontainer/MSMpiSetup.exe"),
    FilePath = "MSMpiSetup.exe"
});

// Create the fully configured pool.
ArmOperation<BatchAccountPoolResource> pool = await poolCollection.CreateOrUpdateAsync(
    WaitUntil.Completed, "MultiInstanceSamplePool", poolData);

Accesso diretto a memoria remota (RDMA)

Quando si sceglie una dimensione che supporta RDMA come ad esempio A9 per i nodi di calcolo nel pool Batch, l'applicazione MPI può sfruttare i vantaggi legati alle prestazioni elevate e alla latenza ridotta della rete con Accesso diretto a memoria remota (RDMA) di Azure.

Cercare le dimensioni specificate come "compatibile con RDMA" in Dimensioni per le macchine virtuali in Azure (per i pool VirtualMachineConfiguration) o Dimensioni per Servizi cloud (per i pool CloudServicesConfiguration).

Nota

Per sfruttare i RDMA in nodi di calcolo Linux, è necessario utilizzare Intel MPI sui nodi.

Creare un'attività a istanza multipla con Azure.Compute.Batch

Ora che sono stati illustrati i requisiti del pool e l'installazione del pacchetto MPI, è possibile passare alla creazione dell'attività a istanze multiple. In questo frammento, creiamo un oggetto BatchTaskCreateOptions standard, quindi configuriamo la proprietà MultiInstanceSettings. Come specificato in precedenza, l'attività a istanze multiple non è un tipo di attività distinto ma un'attività Batch Standard configurata con impostazioni per istanze multiple.

// Create the multi-instance task. Its command line is the "application command"
// and will be executed *only* by the primary, and only after the primary and
// subtasks execute the CoordinationCommandLine.
BatchTaskCreateOptions myMultiInstanceTask = new BatchTaskCreateOptions(
    id: "mymultiinstancetask",
    commandLine: "cmd /c mpiexec.exe -wdir %AZ_BATCH_TASK_SHARED_DIR% MyMPIApplication.exe")
{
    // Configure the task's MultiInstanceSettings. The CoordinationCommandLine will be executed by
    // the primary and all subtasks.
    MultiInstanceSettings = new MultiInstanceSettings(
        @"cmd /c start cmd /c ""%MSMPI_BIN%\smpd.exe"" -d")
    {
        NumberOfInstances = numberOfNodes
    }
};

myMultiInstanceTask.MultiInstanceSettings.CommonResourceFiles.Add(new ResourceFile()
{
    HttpUri = new Uri("https://mystorageaccount.blob.core.windows.net/mycontainer/MyMPIApplication.exe"),
    FilePath = "MyMPIApplication.exe"
});

// Submit the task to the job. Batch will take care of splitting it into subtasks and
// scheduling them for execution on the nodes.
await myBatchClient.CreateTaskAsync("mybatchjob", myMultiInstanceTask);

Attività primaria e sottoattività

Quando si creano le impostazioni per istanze multiple per un'attività, è necessario specificare il numero di nodi di calcolo che devono eseguire l'attività. Quando si invia l'attività a un processo, il servizio Batch crea un'attività primaria e un numero sufficiente di sottoattività che, insieme, corrispondono al numero di nodi specificato.

A queste attività viene assegnato un ID intero compreso tra 0 e numberOfInstances - 1. L'attività con ID 0 è l'attività primaria e tutti gli altri ID sono sottoattività. Ad esempio, se si creano le impostazioni a istanze multipli seguenti per un'attività, l'attività primaria avrà un ID pari a 0 e le sottoattività avranno ID da 1 a 9.

int numberOfNodes = 10;
myMultiInstanceTask.MultiInstanceSettings = new MultiInstanceSettings("coord-cmd")
{
    NumberOfInstances = numberOfNodes
};

Nodo master

Quando si invia un'attività a istanze multiple, il servizio Batch definisce uno dei nodi di calcolo come nodo "master" e pianifica l'attività primaria da eseguire sul nodo master. Le sottoattività sono pianificate per essere eseguite sul resto dei nodi allocati all'attività a istanze multiple.

comando di coordinamento

Il comando di coordinamento viene eseguito sia dall'attività primaria che dalle sottoattività.

L'invocazione del comando di coordinamento è bloccante: Batch non esegue il comando applicazione fino a quando il comando di coordinamento non è stato restituito con successo per tutte le sottoattività. Il comando di coordinamento deve quindi avviare eventuali servizi in background necessari, verificare che siano pronti per l'uso e chiudersi. Ad esempio, questo comando di coordinamento per una soluzione con MS-MPI versione 7 avvia il servizio SMPD nel nodo e quindi viene chiuso:

cmd /c start cmd /c ""%MSMPI_BIN%\smpd.exe"" -d

Si noti l'uso di start in questo comando di coordinamento. è necessario perché l'applicazione smpd.exe non viene restituita immediatamente dopo l'esecuzione. Senza l'uso del comando start, questo comando di coordinamento non verrebbe restituito e bloccherebbe l'esecuzione del comando applicazione.

Comando dell'applicazione

Al termine dell'esecuzione del comando di coordinamento da parte dell'attività primaria e di tutte le sottoattività, la riga di comando dell'attività a istanze multiple viene eseguita solodall'attività primaria. La riga di comando viene definita comando applicazione per distinguerla dal comando di coordinamento.

Per le applicazioni di MS-MPI, usare il comando applicazione per eseguire l'applicazione abilitata per MPI con mpiexec.exe. Di seguito è riportato, a titolo di esempio, il comando applicazione per una soluzione con MS-MPI versione 7:

cmd /c ""%MSMPI_BIN%\mpiexec.exe"" -c 1 -wdir %AZ_BATCH_TASK_SHARED_DIR% MyMPIApplication.exe

Nota

Poiché MS-MPI usa la mpiexec.exe variabile per impostazione predefinita (vedere CCP_NODES di ambiente), la riga di comando dell'applicazione di esempio precedente lo esclude.

Variabili di ambiente

Batch crea più variabili di ambiente specifiche delle attività a istanze multiple sui nodi di calcolo allocati a un'attività a istanze multiple. Le righe dei comandi applicazione e di coordinamento possono fare riferimento a queste variabili di ambiente, come agli script e ai programmi che eseguono.

Le variabili di ambiente seguenti vengono create dal servizio Batch per l'uso da parte di attività a istanze multiple:

  • CCP_NODES
  • AZ_BATCH_NODE_LIST
  • AZ_BATCH_HOST_LIST
  • AZ_BATCH_MASTER_NODE
  • AZ_BATCH_TASK_SHARED_DIR
  • AZ_BATCH_IS_CURRENT_NODE_MASTER

Per informazioni dettagliate su queste e altre variabili di ambiente dei nodi di calcolo, inclusi i contenuti e la visibilità, vedere l'argomento relativo alle variabili di ambiente dei nodi di calcolo.

Suggerimento

L'esempio di codice MPI di Batch Linux contiene un esempio di come è possibile usare diverse di queste variabili di ambiente.

File di risorse

Sono disponibili due set di file di risorse da prendere in considerazione per le attività a istanze multiple: file di risorse comuni, scaricati da tutte le attività, sia da quella primaria che dalle sottoattività, e file di risorse specifici per la stessa attività a istanze multiple, scaricati solo dall'attività primaria.

È possibile specificare uno o più file di risorse comuni nelle impostazioni per istanze multiple relative a un'attività. Questi file di risorse comuni vengono scaricati da Archiviazione di Azure dall'attività primaria e da tutte le sottoattività nella directory condivisa dell'attività di ogni nodo. È possibile accedere alla directory condivisa dell'attività dalle righe del comando applicazione e del comando di coordinamento usando la variabile di ambiente AZ_BATCH_TASK_SHARED_DIR. Il percorso AZ_BATCH_TASK_SHARED_DIR è identico in ogni nodo allocato all'attività a istanze multiple ed è quindi possibile condividere un singolo comando di coordinamento tra l'attività primaria e tutte le sottoattività. Il servizio Batch non "condivide" la directory nel senso di consentire un accesso remoto, ma è possibile usarla come punto di montaggio o condivisione, come indicato in precedenza nel suggerimento sulle variabili di ambiente.

I file di risorse specificati per l'attività a istanze multiple stessa vengono scaricati nella directory di lavoro dell'attività, AZ_BATCH_TASK_WORKING_DIR, per impostazione predefinita. Come accennato, a differenza dei file di risorse comuni, solo l'attività primaria scarica i file di risorse specificati per l'attività a istanze multiple stessa.

Importante

Usare sempre le variabili di ambiente AZ_BATCH_TASK_SHARED_DIR e AZ_BATCH_TASK_WORKING_DIR per fare riferimento a tali directory nelle righe di comando. Evitare di provare a costruire i percorsi manualmente.

Durata dell'attività

Dalla durata dell'attività principale dipende la durata dell'intera attività a istanze multiple. Quando viene chiusa l'attività primaria, vengono terminate tutte le sottoattività. Il codice di uscita dell'attività primaria è il codice di uscita dell'attività e viene quindi usato per determinare l'esito positivo o negativo dell'attività per la ripetizione dei tentativi.

Se una delle sottoattività ha esito negativo e viene chiusa con un codice restituito diverso da zero, ad esempio, l'intera attività a istanze multiple ha esito negativo. L'attività a istanze multiple viene quindi terminata e la sua esecuzione verrà ripetuta fino a raggiungere il limite di tentativi.

Quando si elimina un'attività a istanze multiple, il servizio Batch elimina anche l'attività primaria e tutte le sottoattività. Dai nodi di calcolo vengono eliminate tutte le directory delle sottoattività e i relativi file, come avviene per un'attività standard.

BatchTaskConstraints per un'attività a più istanze, ad esempio Le proprietà MaxTaskRetryCount, MaxWallClockTime e RetentionTime , vengono rispettate come sono per un'attività standard e si applicano alle sottoattività primarie e a tutte le sottoattività. Tuttavia, se si modifica la proprietàRetentionTime dopo l'aggiunta dell'attività a più istanze al processo, questa modifica viene applicata solo all'attività primaria e tutte le sottoattività continuano a usare retentionTime originale.

L'elenco di attività recenti di un nodo di calcolo riflette l'ID di una sottoattività se l'attività recente faceva parte di un'attività a più istanze.

Ottenere informazioni sulle sottoattività

Per ottenere informazioni sulle sottoattività utilizzando la libreria Azure.Compute.Batch, chiamare il metodo BatchClient.GetTaskSubTasks. Questo metodo restituisce informazioni su tutte le sottoattività e sul nodo di calcolo che ha eseguito le attività. Da queste informazioni è possibile determinare la directory radice di ogni sottoattività, l'ID del pool, il relativo stato corrente, il codice di uscita e altro ancora. È possibile usare queste informazioni in combinazione con il metodo BatchClient.GetNodeFile per ottenere i file della sottoattività. Si noti che questo metodo non restituisce informazioni per l'attività primaria (ID 0).

Nota

Se non diversamente specificato, i metodi di Azure.Compute.Batch che operano sul BatchTask multi-istanza stesso si applicano solo all'attività primaria. Ad esempio, quando si chiama il GetTaskFiles metodo in un'attività a istanze multipla, vengono restituiti solo i file dell'attività primaria.

Il frammento di codice seguente illustra come ottenere informazioni sulle sottoattività e come richiedere il contenuto dei file dai nodi in cui vengono eseguiti.

// Obtain the multi-instance task from the Batch service
BatchTask myMultiInstanceTask = await batchClient.GetTaskAsync("mybatchjob", "mymultiinstancetask");
_ = myMultiInstanceTask;

// Now iterate over the subtasks for the task and print their stdout and stderr
// output if the subtask has completed
await foreach (BatchSubtask subtask in batchClient.GetSubTasksAsync("mybatchjob", "mymultiinstancetask"))
{
    Console.WriteLine("subtask: {0}", subtask.Id);
    Console.WriteLine("exit code: {0}", subtask.ExitCode);

    if (subtask.State == BatchSubtaskState.Completed)
    {
        BatchNode node = await batchClient.GetNodeAsync(
            subtask.NodeInfo.PoolId,
            subtask.NodeInfo.NodeId);

        BinaryData stdOut = await batchClient.GetNodeFileAsync(
            subtask.NodeInfo.PoolId, node.Id, $"{subtask.NodeInfo.TaskRootDirectory}/stdout.txt");
        BinaryData stdErr = await batchClient.GetNodeFileAsync(
            subtask.NodeInfo.PoolId, node.Id, $"{subtask.NodeInfo.TaskRootDirectory}/stderr.txt");

        Console.WriteLine("node: {0}:", node.Id);
        Console.WriteLine("stdout.txt: {0}", stdOut);
        Console.WriteLine("stderr.txt: {0}", stdErr);
    }
    else
    {
        Console.WriteLine("\tSubtask {0} is in state {1}", subtask.Id, subtask.State);
    }
}

Esempio di codice

Il codice di esempio MultiInstanceTasks su GitHub illustra come usare un'attività a più istanze per eseguire un'applicazione MS-MPI nei nodi di calcolo di Batch. Per eseguire l'esempio, seguire questa procedura.

Operazioni preliminari

  1. Scaricare i programmi di installazione di MS-MPI SDK e Redist e installarli . Dopo l'installazione è possibile verificare che le variabili di ambiente MS-MPI siano state impostate.
  2. Compilare una versione Release del programma MPI di esempio MPIHelloWorld. Questo è il programma che sarà eseguito sui nodi di calcolo dal compito a più istanze.
  3. Creare un file ZIP contenente MPIHelloWorld.exe (compilato nel passaggio 2) e MSMpiSetup.exe (scaricato nel passaggio 1). Il file zip verrà caricato come un pacchetto dell'applicazione nel passaggio successivo.
  4. Usare il portale di Azure per creare un'applicazione Batch chiamata "MPIHelloWorld" e specificare il file zip creato nel passaggio precedente come versione "1.0" del pacchetto dell'applicazione. Vedere Caricare e gestire le applicazioni per maggiori informazioni.

Suggerimento

La compilazione di una versione release di MPIHelloWorld.exe garantisce che non sia necessario includere altre dipendenze (ad esempio, msvcp140d.dll o vcruntime140d.dll) nel pacchetto dell'applicazione.

Esecuzione

  1. Scaricare il file azure-batch-samples .zip da GitHub.

  2. Aprire la soluzione MultiInstanceTasks in Visual Studio 2019. Il MultiInstanceTasks.sln file della soluzione si trova:

    azure-batch-samples\CSharp\ArticleProjects\MultiInstanceTasks\

  3. Immettere le credenziali dell'account di archiviazione e Batch in AccountSettings.settings nel progetto Microsoft.Azure.Batch.Samples.Common.

  4. Compilare ed eseguire la soluzione MultiInstanceTasks per eseguire l'applicazione di esempio MPI sui nodi di calcolo in un pool di Batch.

  5. Facoltativo: usare il portale di Azure o Batch Explorer per esaminare il pool di esempio, il processo e l'attività ("MultiInstanceSamplePool", "MultiInstanceSampleJob", "MultiInstanceSampleTask") prima di eliminare le risorse.

Suggerimento

Se Visual Studio non è già disponibile, è possibile scaricare gratuitamente Visual Studio Community .

L'output di MultiInstanceTasks.exeè simile al seguente:

Creating pool [MultiInstanceSamplePool]...
Creating job [MultiInstanceSampleJob]...
Adding task [MultiInstanceSampleTask] to job [MultiInstanceSampleJob]...
Awaiting task completion, timeout in 00:30:00...

Main task [MultiInstanceSampleTask] is in state [Completed] and ran on compute node [tvm-1219235766_1-20161017t162002z]:
---- stdout.txt ----
Rank 2 received string "Hello world" from Rank 0
Rank 1 received string "Hello world" from Rank 0

---- stderr.txt ----

Main task completed, waiting 00:00:10 for subtasks to complete...

---- Subtask information ----
subtask: 1
        exit code: 0
        node: tvm-1219235766_3-20161017t162002z
        stdout.txt:
        stderr.txt:
subtask: 2
        exit code: 0
        node: tvm-1219235766_2-20161017t162002z
        stdout.txt:
        stderr.txt:

Delete job? [yes] no: yes
Delete pool? [yes] no: yes

Sample complete, hit ENTER to exit...

Passaggi successivi