Använd multi-instanceuppgifter för att köra Message Passing Interface (MPI)-applikationer i Batch

Med aktiviteter med flera instanser kan du köra en Azure Batch uppgift på flera beräkningsnoder samtidigt. Dessa uppgifter möjliggör högpresterande datorscenarier såsom Message Passing Interface (MPI) applikationer i Batch. I den här artikeln får du lära dig hur du kör uppgifter med flera instanser med hjälp av Azure. Compute.Batch bibliotek.

Note

Även om exemplen i den här artikeln fokuserar på Azure.Compute.Batch, MS-MPI och Windows-beräkningsnoder, är de begrepp för uppgifter med flera instanser som beskrivs här tillämpliga på andra plattformar och tekniker (till exempel Python och Intel MPI på Linux-noder).

Översikt av uppgifter med flera instanser

I Batch utförs normalt varje uppgift på en enda beräkningsnoden -- du skickar flera uppgifter till ett jobb, och Batch-tjänsten schemalägger varje uppgift för körning på en nod. Genom att konfigurera en uppgifts inställningar för flera instanser, instruerar du Batch att istället skapa en primär uppgift och flera deluppgifter som sedan körs på flera noder.

Diagram som visar en översikt över inställningar för flera instanser.

När du skickar en uppgift med inställningar för flera instanser till ett jobb, utför Batch flera steg som är unika för uppgifter med flera instanser.

  1. Batchtjänsten skapar en primär och flera undertasker baserat på inställningarna för flera instanser. Det totala antalet aktiviteter (primärt plus alla underaktiviteter) matchar antalet instanser (beräkningsnoder) som du anger i inställningarna för flera instanser.
  2. Batch anger en av beräkningsnoderna som huvudnod och schemalägger den primära uppgiften som ska köras på huvudservern. Den schemalägger deluppgifter att utföras på återstoden av de datornoder som tilldelats den flerinstansuppgiften, en deluppgift per nod.
  3. Primären och alla underuppgifter hämtar alla gemensamma resursfiler som du anger i multi-instance-inställningarna.
  4. Efter att de gemensamma resursfilerna har hämtats, utför primära och underuppgifter det samordningskommando du anger i inställningarna för flera instanser. Koordinationskommandot används vanligtvis för att förbereda noderna för att utföra uppgiften. Detta kan inkludera att starta bakgrundstjänster (så som Microsoft MPIssmpd.exe) och verifiera att noderna är redo att bearbeta meddelanden mellan noder.
  5. Den primära uppgiften kör applikationskommandot på huvudnoden efter att samordningskommandot har slutförts framgångsrikt av den primära uppgiften och alla deluppgifter. Programkommandot är kommandoraden för själva aktiviteten med flera instanser och körs endast av den primära aktiviteten. I en MS-MPI-baserad lösning är det här platsen där du kör din MPI-aktiverade applikation med hjälp av mpiexec.exe.

Note

Även om den är funktionellt distinkt är "multiinstansaktiviteten" inte en unik aktivitetstyp som BatchStartTask eller BatchJobPreparationTask. Uppgiften för flera instanser är helt enkelt en Standard Batch-uppgift (BatchTask i Azure. Compute.Batch) vars inställningar för flera instanser har konfigurerats. I den här artikeln hänvisar vi till detta som multi-instance-uppgift.

Krav för uppgifter med flera instanser

Multi-instansuppgifter kräver en pool med kommunikation mellan noder aktiverad och med samtidig uppgiftsutförande avaktiverad. Om du vill inaktivera samtidig körning av aktiviteter anger du egenskapen BatchAccountPoolData.TaskSlotsPerNode till 1.

Note

Batch begränsar storleken på en pool som har aktiverad inter-node-kommunikation.

Det här kodfragmentet visar hur du skapar en pool för uppgifter med flera instanser med hjälp av Azure. ResourceManager.Batch-bibliotek.

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
};

Note

Om du försöker köra en multi-instanstask i en pool där kommunikation mellan noder är inaktiverad, eller med ett taskSlotsPerNode-värde större än 1, blir tasken aldrig schemalagd--den förblir oändligt i det "aktiva" tillståndet.

Pooler med aktiverad InterComputeNodeCommunication kommer inte automatiskt tillåta att noder deprovisioneras.

Använd en Startuppgift för att installera MPI

För att köra MPI-program med en multi-instansuppgift behöver du först installera en MPI-implementation (till exempel MS-MPI eller Intel MPI) på beräkningsnoderna i poolen. Det här är ett bra tillfälle att använda en BatchAccountPoolStartTask, som körs när en nod ansluter till en pool eller startas om. Det här kodfragmentet lägger till en startaktivitet i pooldefinitionen som anger MS-MPI installationspaketet som en resursfil. Startuppgiftens kommandorad körs efter att resursfilen har laddats ner till noden. I det här fallet utför kommandoraden en obevakad installation av 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);

Fjärrdirekt minnesåtkomst (RDMA)

När du väljer en RDMA-kapabel storlek som A9 för beräkningsnoderna i din Batch-pool, kan din MPI-applikation dra nytta av Azures högpresterande, låglatens närdirektminnesåtkomst (RDMA) nätverk.

Sök efter storlekarna som specificeras som "RDMA-kapabla" i Storlekar för virtuella maskiner i Azure (för VirtualMachineConfiguration-pooler) eller Storlekar för molntjänster (för CloudServicesConfiguration-pooler).

Note

För att dra nytta av RDMA på Linux compute nodes, måste du använda Intel MPI på noderna.

Skapa en uppgift med flera instanser med Azure. Compute.Batch

Nu när vi har gått igenom poolkraven och installationen av MPI-paketet, låt oss skapa uppgiften för flera instanser. I det här kodfragmentet skapar vi en Standard BatchTaskCreateOptions och konfigurerar sedan egenskapen MultiInstanceSettings . Som nämnts tidigare, är multi-instans-uppgiften inte en särskild uppgiftstyp, utan en standard Batch-uppgift konfigurerad med multi-instans-inställningar.

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

Huvuduppgift och deluppgifter

När du skapar flerinställningsinställningarna för en uppgift, anger du antalet beräkningsnoder som ska utföra uppgiften. När du skickar in uppgiften till ett jobb skapar Batch-tjänsten en primär uppgift och tillräckligt med deluppgifter så att de tillsammans motsvarar antalet noder du specificerade.

Dessa uppgifter tilldelas ett heltals-ID i intervallet från 0 till numberOfInstances - 1. Uppgiften med ID 0 är huvuduppgiften, och alla andra ID:n är deluppgifter. Till exempel, om du skapar följande inställningar för flera instanser för en uppgift, skulle huvuduppgiften ha ett ID på 0, och deluppgifterna skulle ha ID:n från 1 till 9.

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

Masternod

När du skickar en uppgift med flera instanser anger Batch-tjänsten en av beräkningsnoderna som "huvudnoden" och schemalägger den primära uppgiften som ska köras på huvudnoden. Underaktiviteterna är schemalagda att köras på de resterande noder som har allokerats till flerinstansaktiviteten.

Koordineringskommando

Koordineringskommandot utförs av både huvud- och deluppgifter.

Anropet av samordningskommandot är blockerande; Batch utför inte applikationskommandot förrän samordningskommandot har returnerat framgångsrikt för alla deluppgifter. Samordningskommandot bör därför starta alla nödvändiga bakgrundstjänster, kontrollera att de är redo att användas och sedan avsluta. Till exempel startar denna samordningskommando för en lösning med MS-MPI version 7 SMPD-tjänsten på noden och avslutas sedan.

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

Observera användningen av start i det här koordinationskommandot. Detta är nödvändigt eftersom smpd.exe-applikationen inte återgår omedelbart efter exekvering. Utan att använda startkommandot skulle detta samordningskommando inte återvända, och det skulle därför blockera applikationskommandot från att köras.

Applikationskommando

När huvuduppgiften och alla deluppgifter har avslutat genomförandet av samordningskommandot, körs kommandoraden för flerinstansuppgiften endast av huvuduppgiften endast. Vi anropar det här programkommandot för att skilja det från samordningskommandot.

För MS-MPI-applikationer, använd applikationskommandot för att köra din MPI-aktiverade applikation med mpiexec.exe. Till exempel är här ett programkommando för en lösning som använder MS-MPI version 7:

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

Note

Eftersom MS-MPI's mpiexec.exe som standard använder variabeln CCP_NODES (se Miljövariabler), utesluter kommandoraden för exempelapplikationen ovan denna.

Miljövariabler

Batch skapar flera miljövariabler som är specifika för flerstegsuppgifter på de beräkningsnoder som är tilldelade en flerstegsuppgift. Dina koordinations- och applikationskommandorader kan referera till dessa miljövariabler, liksom de skript och program som de kör.

Följande miljövariabler skapas av Batch-tjänsten för användning av flera instanser:

  • 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

För fullständig information om dessa och de andra Batch beräkningsnodens miljövariabler, inklusive deras innehåll och synlighet, se Beräkningsnodens miljövariabler.

Tips

Exemplet på Batch Linux MPI-kod innehåller ett exempel på hur flera av dessa miljövariabler kan användas.

Resursfiler

Det finns två uppsättningar resursfiler att tänka på för aktiviteter med flera instanser: vanliga resursfiler som alla aktiviteter laddar ned (både primära och underaktiviteter) och de resursfiler som angetts för själva aktiviteten med flera instanser, som endast den primära aktiviteten laddar ned.

Du kan ange en eller flera gemensamma resursfiler i inställningarna för flera instanser för en uppgift. Dessa vanliga resursfiler laddas ner från Azure Storage till varje nods delade aktivitetskatalog av huvuduppgiften och alla deluppgifter. Du kan komma åt den delade uppgiftskatalogen från applikations- och samordningskommandorader genom att använda miljövariabeln AZ_BATCH_TASK_SHARED_DIR. Vägen AZ_BATCH_TASK_SHARED_DIR är identisk på varje nod som tilldelas till multiinstancesuppgiften, därför kan du dela ett enda samordningskommando mellan huvuduppgiften och alla underuppgifter. Batch "delar" inte katalogen i en fjärråtkomstbetydelse, men du kan använda den som en monterings- eller delningspunkt som nämnts tidigare i tipset om miljövariabler.

Resursfiler som du anger för själva aktiviteten med flera instanser laddas ned till aktivitetens arbetskatalog, AZ_BATCH_TASK_WORKING_DIR, som standard. Som nämnts, i kontrast till vanliga resursfiler, laddar endast huvuduppgiften ner resursfiler som är specifikt angivna för själva multiinstansuppgiften.

Viktigt

Använd alltid miljövariablerna AZ_BATCH_TASK_SHARED_DIR och AZ_BATCH_TASK_WORKING_DIR referera till dessa kataloger på kommandoraderna. Försök inte att konstruera vägarna manuellt.

Uppgiftens livslängd

Livslängden för den primära uppgiften styr livslängden för hela multi-instansuppgiften. När huvudsakliga processen avslutas, avbryts alla deluppgifter. Avslutningskoden för primärprocessen är avslutningskoden för uppgiften, och används därför för att bestämma om uppgiften har lyckats eller misslyckats i syfte att göra ett nytt försök.

Om någon av deluppgifterna misslyckas genom att till exempel avslutas med en returkod som inte är noll, misslyckas hela uppgiften med flera instanser. Multi-instansuppgiften avslutas sedan och försöks på nytt, upp till dess gräns för försök.

När du tar bort en multi-instansuppgift raderas även huvud- och alla deluppgifter av Batch-tjänsten. Alla deluppgiftskataloger och deras filer raderas från beräkningsnoderna, precis som för en standarduppgift.

BatchTaskConstraints för en aktivitet med flera instanser, till exempel egenskaperna MaxTaskRetryCount, MaxWallClockTime och RetentionTime , respekteras som de är för en standardaktivitet och gäller för de primära och alla underaktiviteter. Om du emellertid ändrar egenskapen RetentionTime efter att ha lagt till flerinstansuppgiften till jobbet, gäller denna ändring endast för huvuduppgiften, och alla underuppgifter fortsätter att använda den ursprungliga RetentionTime.

En beräkningsnods senaste arbetslista återspeglar ID:t för en deluppgift ifall den senaste uppgiften var en del av en multiansistuppgift.

Skaffa information om deluppgifter

Så här hämtar du information om underaktiviteter med hjälp av Azure. Compute.Batch-biblioteket anropar metoden BatchClient.GetTaskSubTasks. Denna metod returnerar information om alla deluppgifter och information om beräkningsnoden som utförde uppgifterna. Från denna information kan du fastställa varje deluppgifts rotkatalog, pool-ID, dess aktuella status, avslutningskod och mer. Du kan använda den här informationen i kombination med metoden BatchClient.GetNodeFile för att hämta underuppgiftens filer. Observera att den här metoden inte returnerar information för den primära aktiviteten (ID 0).

Note

Om inget annat anges gäller Azure.Compute.Batch-metoder som arbetar på själva BatchTask med flera instanser endast den primära aktiviteten. När du till exempel anropar GetTaskFiles metoden för en aktivitet med flera instanser returneras endast den primära aktivitetens filer.

Följande kodexempel visar hur man hämtar information om deluppgifter och begär innehåll från filer på de noder där de kördes.

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

Kodexempel

Exemplet på koden för MultiInstanceTasks på GitHub visar hur man använder en multi-instansuppgift för att köra en MS-MPI-applikation på Batch-beräkningsnoder. Följ stegen nedan för att köra exemplet.

Förberedelse

  1. Ladda ned installationsprogrammet förMS-MPI SDK och Redist och installera dem. Efter installationen kan du kontrollera att MS-MPI-miljövariablerna har ställts in.
  2. Skapa en Release version av MPI-exempelprogrammet MPIHelloWorld. Detta är programmet som kommer att köras på beräkningsnoder av multi-instans uppgiften.
  3. Skapa en zip-fil som innehåller MPIHelloWorld.exe (som du byggde i steg 2) och MSMpiSetup.exe (som du laddade ner i steg 1). Du laddar upp zip-filen som ett programpaket i nästa steg.
  4. Använd Azure-portalen för att skapa en Batch-applikation kallad "MPIHelloWorld", och ange zip-filen du skapade i det föregående steget som version "1.0" av applikationspaketet. Se Ladda upp och hantera applikationer för mer information.

Tips

Att bygga en releaseversion av MPIHelloWorld.exe innebär att du inte behöver inkludera några ytterligare beroenden (till exempel msvcp140d.dll eller vcruntime140d.dll) i ditt programpaket.

Utförande

  1. Ladda ner azure-batch-samples .zip filen från GitHub.

  2. Öppna MultiInstanceTasks lösning i Visual Studio 2019. Lösningsfilen MultiInstanceTasks.sln finns i:

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

  3. Ange autentiseringsuppgifterna för batch- och lagringskontot i AccountSettings.settings i Microsoft.Azure. Batch.Samples.Common projekt.

  4. Bygg och kör MultiInstanceTasks-lösningen för att köra MPI-exempelprogrammet på beräkningsnoder i en Batch-pool.

  5. Valfritt: Använd Azure-portalen eller Batch Explorer för att undersöka exempelpoolen, jobbet och aktiviteten ("MultiInstanceSamplePool", "MultiInstanceSampleJob", "MultiInstanceSampleTask") innan du tar bort resurserna.

Tips

Du kan ladda ner Visual Studio Community gratis om du inte redan har Visual Studio.

Utdata från MultiInstanceTasks.exe är liknande följande:

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

Nästa steg