Använda uppgifter med flera instanser för att köra MPI-program (Message Passing Interface) 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 scenarier med databehandling med höga prestanda, till exempel MPI-program (Message Passing Interface) 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 Batch .NET-biblioteket .

Anteckning

Exemplen i den här artikeln fokuserar på Batch .NET-, MS-MPI- och Windows-beräkningsnoder, men de uppgiftsbegrepp med flera instanser som beskrivs här gäller för andra plattformar och tekniker (till exempel Python och Intel MPI på Linux-noder).

Översikt över uppgift för flera instanser

I Batch körs varje aktivitet normalt på en enda beräkningsnod – du skickar flera aktiviteter till ett jobb och Batch-tjänsten schemalägger varje aktivitet för körning på en nod. Men genom att konfigurera en aktivitets inställningar för flera instanser ber du Batch att i stället skapa en primär aktivitet och flera underaktiviteter 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 aktiviteter med flera instanser:

  1. Batch-tjänsten skapar en primär och flera underaktiviteter 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 aktiviteten som ska köras på huvudnoden. Den schemalägger underaktiviteterna så att de körs på resten av beräkningsnoderna som allokeras till aktiviteten med flera instanser, en underaktivitet per nod.
  3. De primära och alla underaktiviteter laddar ned alla vanliga resursfiler som du anger i inställningarna för flera instanser.
  4. När de gemensamma resursfilerna har laddats ned kör de primära och underaktiviteterna det samordningskommando som du anger i inställningarna för flera instanser. Samordningskommandot används vanligtvis för att förbereda noder för att köra uppgiften. Detta kan omfatta start av bakgrundstjänster (till exempel Microsoft MPI:ersmpd.exe) och verifiering av att noderna är redo att bearbeta meddelanden mellan noder.
  5. Den primära aktiviteten kör programkommandot på huvudnoden när samordningskommandot har slutförts av den primära och alla underaktiviteter. 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 kör du ditt MPI-aktiverade program med hjälp av mpiexec.exe.

Anteckning

Även om det är funktionellt distinkt är "multi-instance task" inte en unik aktivitetstyp som StartTask eller JobPreparationTask. Uppgiften med flera instanser är helt enkelt en Standard Batch-uppgift (CloudTask i Batch .NET) vars inställningar för flera instanser har konfigurerats. I den här artikeln refererar vi till detta som uppgiften för flera instanser.

Krav för uppgifter med flera instanser

Aktiviteter med flera instanser kräver en pool med kommunikation mellan noder aktiverad och samtidig aktivitetskörning inaktiverad. Om du vill inaktivera samtidig aktivitetskörning anger du egenskapen CloudPool.TaskSlotsPerNode till 1.

Anteckning

Batch begränsar storleken på en pool som har kommunikation mellan noder aktiverad.

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

CloudPool myCloudPool =
    myBatchClient.PoolOperations.CreatePool(
        poolId: "MultiInstanceSamplePool",
        targetDedicatedComputeNodes: 3
        virtualMachineSize: "standard_d1_v2",
        VirtualMachineConfiguration: new VirtualMachineConfiguration(
        imageReference: new ImageReference(
                        publisher: "MicrosoftWindowsServer",
                        offer: "WindowsServer",
                        sku: "2019-datacenter-core",
                        version: "latest"),
        nodeAgentSkuId: "batch.node.windows amd64");

// Multi-instance tasks require inter-node communication, and those nodes
// must run only one task at a time.
myCloudPool.InterComputeNodeCommunicationEnabled = true;
myCloudPool.TaskSlotsPerNode = 1;

Anteckning

Om du försöker köra en aktivitet med flera instanser i en pool med internode-kommunikation inaktiverad eller med ett taskSlotsPerNode-värde som är större än 1, schemaläggs aktiviteten aldrig – den förblir på obestämd tid i tillståndet "aktiv".

Pooler med InterComputeNodeCommunication aktiverat tillåter inte automatiskt avetablering av noden.

Använda en StartTask för att installera MPI

Om du vill köra MPI-program med en uppgift med flera instanser måste du först installera en MPI-implementering (till exempel MS-MPI eller Intel MPI) på beräkningsnoderna i poolen. Det här är ett bra tillfälle att använda en StartTask som körs när en nod ansluter till en pool eller startas om. Det här kodfragmentet skapar en StartTask som anger MS-MPI-installationspaketet som en resursfil. Startaktivitetens kommandorad körs när resursfilen har laddats ned till noden. I det här fallet utför kommandoraden en obevakad installation av MS-MPI.

// Create a StartTask for the pool which we use for installing MS-MPI on
// the nodes as they join the pool (or when they are restarted).
StartTask startTask = new StartTask
{
    CommandLine = "cmd /c MSMpiSetup.exe -unattend -force",
    ResourceFiles = new List<ResourceFile> { new ResourceFile("https://mystorageaccount.blob.core.windows.net/mycontainer/MSMpiSetup.exe", "MSMpiSetup.exe") },
    UserIdentity = new UserIdentity(new AutoUserSpecification(elevationLevel: ElevationLevel.Admin)),
    WaitForSuccess = true
};
myCloudPool.StartTask = startTask;

// Commit the fully configured pool to the Batch service to actually create
// the pool and its compute nodes.
await myCloudPool.CommitAsync();

Direktåtkomst till fjärrminne (RDMA)

När du väljer en RDMA-kompatibel storlek , till exempel A9 för beräkningsnoderna i Batch-poolen, kan ditt MPI-program dra nytta av Azures RDMA-nätverk (high-performance, low-latency remote direct memory access).

Leta efter de storlekar som anges som "RDMA-kompatibla" i Storlekar för virtuella datorer i Azure (för VirtualMachineConfiguration-pooler) eller Storlekar för Cloud Services (för CloudServicesConfiguration-pooler).

Anteckning

Om du vill dra nytta av RDMA på Linux-beräkningsnoder måste du använda Intel MPI på noderna.

Skapa en uppgift med flera instanser med Batch .NET

Nu när vi har gått igenom poolkraven och installationen av MPI-paket ska vi skapa uppgiften för flera instanser. I det här kodfragmentet skapar vi en Standard CloudTask och konfigurerar sedan dess MultiInstanceSettings-egenskap . Som tidigare nämnts är aktiviteten med flera instanser inte en distinkt aktivitetstyp, utan en standard-Batch-uppgift som konfigurerats med inställningar för flera instanser.

// 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.
CloudTask myMultiInstanceTask = new CloudTask(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.
myMultiInstanceTask.MultiInstanceSettings =
    new MultiInstanceSettings(numberOfNodes) {
    CoordinationCommandLine = @"cmd /c start cmd /c ""%MSMPI_BIN%\smpd.exe"" -d",
    CommonResourceFiles = new List<ResourceFile> {
    new ResourceFile("https://mystorageaccount.blob.core.windows.net/mycontainer/MyMPIApplication.exe",
                     "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.JobOperations.AddTaskAsync("mybatchjob", myMultiInstanceTask);

Primär aktivitet och underaktiviteter

När du skapar inställningarna för flera instanser för en aktivitet anger du antalet beräkningsnoder som ska köra aktiviteten. När du skickar aktiviteten till ett jobb skapar Batch-tjänsten en primär aktivitet och tillräckligt med underaktiviteter som tillsammans matchar antalet noder som du har angett.

De här uppgifterna tilldelas ett heltals-ID i intervallet 0 till numberOfInstances – 1. Uppgiften med ID 0 är den primära aktiviteten och alla andra ID:er är underaktiviteter. Om du till exempel skapar följande inställningar för flera instanser för en aktivitet skulle den primära aktiviteten ha ID:t 0 och underaktiviteterna har ID:t 1 till och med 9.

int numberOfNodes = 10;
myMultiInstanceTask.MultiInstanceSettings = new MultiInstanceSettings(numberOfNodes);

Huvudnod

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 aktiviteten som ska köras på huvudnoden. Underaktiviteterna är schemalagda att köras på resten av noderna som allokeras till aktiviteten med flera instanser.

Samordningskommando

Samordningskommandot körs av både de primära och underaktiviteterna.

Anropet av samordningskommandot blockerar – Batch kör inte programkommandot förrän samordningskommandot har returnerats för alla underaktiviteter. Samordningskommandot bör därför starta alla nödvändiga bakgrundstjänster, kontrollera att de är redo att användas och sedan avsluta. Det här samordningskommandot för en lösning som använder MS-MPI version 7 startar till exempel SMPD-tjänsten på noden och avslutar sedan:

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

Observera användningen av start i det här samordningskommandot. Detta krävs eftersom programmet smpd.exe inte returneras omedelbart efter körningen. Utan startkommandot skulle det här samordningskommandot inte returneras och därför blockera programkommandot från att köras.

Programkommando

När den primära aktiviteten och alla underaktiviteter har slutfört körningen av samordningskommandot körs kommandoraden för flera instanser endast av den primära aktiviteten. Vi kallar detta programkommando för att skilja det från samordningskommandot.

För MS-MPI-program använder du programkommandot för att köra ditt MPI-aktiverade program med mpiexec.exe. Här är till exempel 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

Anteckning

Eftersom MS-MPI använder mpiexec.exe variabeln CCP_NODES som standard (se Miljövariabler) exkluderar exempelprogrammets kommandorad ovan den.

Miljövariabler

Batch skapar flera miljövariabler som är specifika för aktiviteter med flera instanser på beräkningsnoderna som allokeras till en aktivitet med flera instanser. Kommandoraderna för samordning och program 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 uppgifter med 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

Fullständig information om dessa och andra miljövariabler för Batch-beräkningsnoder, inklusive deras innehåll och synlighet, finns i Miljövariabler för beräkningsnoder.

Tips

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

Resursfiler

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

Du kan ange en eller flera vanliga resursfiler i inställningarna för flera instanser för en aktivitet. De här vanliga resursfilerna laddas ned från Azure Storage till varje nods delade aktivitetskatalog av den primära och alla underaktiviteter. Du kan komma åt den delade katalogen för aktiviteter från kommandoraderna för program och samordning med hjälp AZ_BATCH_TASK_SHARED_DIR av miljövariabeln. Sökvägen AZ_BATCH_TASK_SHARED_DIR är identisk på varje nod som allokeras till aktiviteten med flera instanser, så du kan dela ett enda samordningskommando mellan den primära och alla underaktiviteter. Batch "delar" inte katalogen i fjärråtkomst, men du kan använda den som en monterings- eller resurspunkt 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, till skillnad från vanliga resursfiler, hämtar endast den primära aktiviteten resursfiler som har angetts för själva aktiviteten med flera instanser.

Viktigt

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

Aktivitetens livslängd

Livslängden för den primära aktiviteten styr livslängden för hela aktiviteten med flera instanser. När den primära avslutas avslutas alla underaktiviteter. Slutkoden för den primära aktiviteten är slutkoden för aktiviteten och används därför för att fastställa om aktiviteten lyckades eller misslyckades i återförsökssyfte.

Om någon av underaktiviteterna misslyckas och avslutas med en returkod som inte är noll, misslyckas till exempel hela multiinstansaktiviteten. Aktiviteten med flera instanser avslutas sedan och görs ett nytt försök, upp till gränsen för återförsök.

När du tar bort en aktivitet med flera instanser tas även den primära och alla underaktiviteter bort av Batch-tjänsten. Alla underaktivitetskataloger och deras filer tas bort från beräkningsnoderna, precis som för en standardaktivitet.

TaskConstraints 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. Men om du ändrar egenskapenRetentionTime när du har lagt till aktiviteten med flera instanser i jobbet tillämpas den här ändringen endast på den primära aktiviteten och alla underaktiviteter fortsätter att använda den ursprungliga RetentionTime.

En beräkningsnods senaste uppgiftslista visar ID:t för en underaktivitet om den senaste aktiviteten ingick i en aktivitet med flera instanser.

Hämta information om underaktiviteter

Om du vill hämta information om underaktiviteter med hjälp av Batch .NET-biblioteket anropar du metoden CloudTask.ListSubtasks . Den här metoden returnerar information om alla underaktiviteter och information om beräkningsnoden som körde aktiviteterna. Med den här informationen kan du fastställa varje underavdelnings rotkatalog, pool-ID, dess aktuella tillstånd, slutkod med mera. Du kan använda den här informationen i kombination med metoden PoolOperations.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).

Anteckning

Om inget annat anges gäller Batch .NET-metoder som körs på själva CloudTask med flera instanser endast för den primära aktiviteten. När du till exempel anropar metoden CloudTask.ListNodeFiles för en uppgift med flera instanser returneras endast den primära aktivitetens filer.

Följande kodfragment visar hur du hämtar information om underaktiviteter samt begär filinnehåll från de noder som de kördes på.

// Obtain the job and the multi-instance task from the Batch service
CloudJob boundJob = batchClient.JobOperations.GetJob("mybatchjob");
CloudTask myMultiInstanceTask = boundJob.GetTask("mymultiinstancetask");

// Now obtain the list of subtasks for the task
IPagedEnumerable<SubtaskInformation> subtasks = myMultiInstanceTask.ListSubtasks();

// Asynchronously iterate over the subtasks and print their stdout and stderr
// output if the subtask has completed
await subtasks.ForEachAsync(async (subtask) =>
{
    Console.WriteLine("subtask: {0}", subtask.Id);
    Console.WriteLine("exit code: {0}", subtask.ExitCode);

    if (subtask.State == SubtaskState.Completed)
    {
        ComputeNode node =
            await batchClient.PoolOperations.GetComputeNodeAsync(subtask.ComputeNodeInformation.PoolId,
                                                                 subtask.ComputeNodeInformation.ComputeNodeId);

        NodeFile stdOutFile = await node.GetNodeFileAsync(subtask.ComputeNodeInformation.TaskRootDirectory + "\\" + Constants.StandardOutFileName);
        NodeFile stdErrFile = await node.GetNodeFileAsync(subtask.ComputeNodeInformation.TaskRootDirectory + "\\" + Constants.StandardErrorFileName);
        stdOut = await stdOutFile.ReadAsStringAsync();
        stdErr = await stdErrFile.ReadAsStringAsync();

        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

Kodexemplet MultiInstanceTasks på GitHub visar hur du använder en uppgift med flera instanser för att köra ett MS-MPI-program på Batch-beräkningsnoder. Följ stegen nedan för att köra exemplet.

Förberedelse

  1. Ladda ned installationsprogrammet för MS-MPI SDK och Redist och installera dem. Efter installationen kan du kontrollera att miljövariablerna för MS-MPI har angetts.
  2. Skapa en versionsversion av MPIHelloWorld-exempelprogrammet MPI. Det här är programmet som ska köras på beräkningsnoder av aktiviteten för flera instanser.
  3. Skapa en zip-fil som innehåller MPIHelloWorld.exe (som du skapade i steg 2) och MSMpiSetup.exe (som du laddade ned i steg 1). Du laddar upp zip-filen som ett programpaket i nästa steg.
  4. Använd Azure Portal för att skapa ett Batch-program med namnet "MPIHelloWorld" och ange zip-filen som du skapade i föregående steg som version "1.0" av programpaketet. Mer information finns i Ladda upp och hantera program .

Tips

Att skapa en versionsversion av MPIHelloWorld.exe säkerställer att du inte behöver inkludera några ytterligare beroenden (till exempel msvcp140d.dll eller vcruntime140d.dll) i programpaketet.

Körnings-

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

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

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

  3. Ange dina autentiseringsuppgifter för Batch- och Storage-kontot i AccountSettings.settings projektet Microsoft.Azure.Batch.Samples.Common .

  4. Skapa 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 Portal eller Batch Explorer för att undersöka exempelpoolen, jobbet och aktiviteten ("MultiInstanceSamplePool", "MultiInstanceSampleJob", "MultiInstanceSampleTask") innan du tar bort resurserna.

Tips

Du kan ladda ned Visual Studio Community kostnadsfritt om du inte redan har Visual Studio.

Utdata från MultiInstanceTasks.exe liknar 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