Udostępnij za pośrednictwem


Uruchamianie aplikacji MPI (Message Passing Interface) w usłudze Batch za pomocą zadań obejmujących wiele wystąpień

Zadania z wieloma wystąpieniami umożliwiają jednoczesne uruchamianie zadania usługi Azure Batch na wielu węzłach obliczeniowych. Te zadania umożliwiają wykonywanie scenariuszy obliczeń o wysokiej wydajności, takich jak aplikacje interfejsu MPI (Message Passing Interface) w usłudze Batch. Z tego artykułu dowiesz się, jak wykonywać zadania obejmujące wiele wystąpień przy użyciu biblioteki .NET usługi Batch.

Uwaga

W przykładach w tym artykule skupiono się na węzłach obliczeniowych usługi Batch .NET, MS-MPI i Windows, ale omówione tutaj pojęcia dotyczące zadań obejmujących wiele wystąpień dotyczą innych platform i technologii (na przykład python i Intel MPI w węzłach systemu Linux).

Omówienie zadania obejmującego wiele wystąpień

W usłudze Batch każde zadanie jest zwykle wykonywane na jednym węźle obliczeniowym — przesyłasz wiele zadań do zadania, a usługa Batch planuje każde zadanie do wykonania w węźle. Jednak konfigurując ustawienia wielu wystąpień zadania, należy poinformować usługę Batch, aby zamiast tego utworzyć jedno zadanie podstawowe i kilka podzadań, które są następnie wykonywane w wielu węzłach.

Diagram przedstawiający przegląd ustawień wielu wystąpień.

Po przesłaniu zadania z ustawieniami wielu wystąpień do zadania usługa Batch wykonuje kilka kroków unikatowych dla zadań obejmujących wiele wystąpień:

  1. Usługa Batch tworzy jeden podstawowy i kilka podzadań na podstawie ustawień wielu wystąpień. Całkowita liczba zadań (podstawowe i wszystkie podzadania) jest zgodna z liczbą wystąpień (węzłów obliczeniowych) określonych w ustawieniach wielu wystąpień.
  2. Usługa Batch wyznacza jeden z węzłów obliczeniowych jako główny i planuje wykonanie zadania podstawowego na serwerze głównym. Planuje wykonywanie podzadań w pozostałej części węzłów obliczeniowych przydzielonych do zadania obejmującego wiele wystąpień— jedną podzadania na węzeł.
  3. Podstawowe i wszystkie podzadania pobierają wszystkie typowe pliki zasobów określone w ustawieniach wielu wystąpień.
  4. Po pobraniu typowych plików zasobów podzadania podstawowe i podrzędne wykonują polecenie koordynacji określone w ustawieniach wielu wystąpień. Polecenie koordynacji jest zwykle używane do przygotowywania węzłów do wykonywania zadania. Może to obejmować uruchamianie usług w tle (takich jak mpI firmy smpd.exeMicrosoft) i sprawdzanie, czy węzły są gotowe do przetwarzania komunikatów między węzłami.
  5. Zadanie podstawowe wykonuje polecenie aplikacji w węźle głównym po pomyślnym ukończeniu polecenia koordynacji przez podstawowe i wszystkie podzadania. Polecenie aplikacji jest wierszem polecenia samego zadania z wieloma wystąpieniami i jest wykonywane tylko przez zadanie podstawowe. W rozwiązaniu opartym na protokole MS-MPI jest to miejsce, w którym uruchamiasz aplikację z obsługą interfejsu MPI przy użyciu polecenia mpiexec.exe.

Uwaga

Chociaż jest ona funkcjonalnie odrębna, zadanie "multi-instance" nie jest unikatowym typem zadania, takiego jak StartTask lub JobPreparationTask. Zadanie obejmujące wiele wystąpień to po prostu standardowe zadanie usługi Batch (CloudTask na platformie .NET usługi Batch), którego ustawienia wielu wystąpień zostały skonfigurowane. W tym artykule nazywamy to zadaniem z wieloma wystąpieniami.

Wymagania dotyczące zadań obejmujących wiele wystąpień

Zadania z wieloma wystąpieniami wymagają puli z włączoną komunikacją między węzłami i z wyłączonym współbieżnym wykonywaniem zadań. Aby wyłączyć współbieżne wykonywanie zadań, ustaw właściwość CloudPool.TaskSlotsPerNode na 1.

Uwaga

Usługa Batch ogranicza rozmiar puli z włączoną komunikacją między węzłami.

Ten fragment kodu pokazuje, jak utworzyć pulę dla zadań obejmujących wiele wystąpień przy użyciu biblioteki platformy .NET usługi Batch.

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;

Uwaga

Jeśli spróbujesz uruchomić zadanie z wieloma wystąpieniami w puli z wyłączoną komunikacją międzywęzłową lub z wartością taskSlotsPerNode większą niż 1, zadanie nigdy nie jest zaplanowane — pozostaje na czas nieokreślony w stanie "aktywny".

Pule z włączonym interComputeNodeCommunication nie zezwalają na automatyczne anulowanie aprowizacji węzła.

Instalowanie interfejsu MPI przy użyciu elementu StartTask

Aby uruchamiać aplikacje MPI z zadaniem z wieloma wystąpieniami, najpierw należy zainstalować implementację MPI (MS-MPI lub Intel MPI, na przykład) w węzłach obliczeniowych w puli. Jest to dobry moment, aby użyć elementu StartTask, który jest wykonywany za każdym razem, gdy węzeł dołącza do puli lub jest uruchamiany ponownie. Ten fragment kodu tworzy element StartTask określający pakiet instalacyjny MS-MPI jako plik zasobu. Wiersz polecenia zadania uruchamiania jest wykonywany po pobraniu pliku zasobu do węzła. W takim przypadku wiersz polecenia wykonuje instalację nienadzorowaną 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();

Zdalny bezpośredni dostęp do pamięci (RDMA)

W przypadku wybrania rozmiaru z funkcją RDMA, takiego jak A9 dla węzłów obliczeniowych w puli usługi Batch, aplikacja MPI może korzystać z wysokiej wydajności sieci zdalnego bezpośredniego dostępu do pamięci (RDMA) platformy Azure o wysokiej wydajności.

Poszukaj rozmiarów określonych jako "z możliwością rdMA" w obszarze Rozmiary maszyn wirtualnych na platformie Azure (w przypadku pul VirtualMachineConfiguration) lub Rozmiary dla usług Cloud Services (w przypadku pul CloudServicesConfiguration).

Uwaga

Aby korzystać z funkcji RDMA w węzłach obliczeniowych systemu Linux, należy użyć funkcji Intel MPI w węzłach.

Tworzenie zadania obejmującego wiele wystąpień przy użyciu platformy .NET usługi Batch

Teraz, gdy już omówiliśmy wymagania dotyczące puli i instalację pakietu MPI, utwórzmy zadanie z wieloma wystąpieniami. W tym fragmencie kodu utworzymy standardową właściwość CloudTask, a następnie skonfigurujemy jej właściwość MultiInstanceSettings . Jak wspomniano wcześniej, zadanie z wieloma wystąpieniami nie jest odrębnym typem zadania, ale standardowym zadaniem usługi Batch skonfigurowanym z ustawieniami wielu wystąpień.

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

Zadania podstawowe i podzadania

Podczas tworzenia ustawień wielu wystąpień dla zadania należy określić liczbę węzłów obliczeniowych do wykonania zadania. Po przesłaniu zadania do zadania usługa Batch tworzy jedno zadanie podstawowe i wystarczającą liczbę podzadań , które razem są zgodne z określoną liczbą węzłów.

Te zadania są przypisywane identyfikatorowi całkowitemu w zakresie od 0 do numberOfInstances — 1. Zadanie o identyfikatorze 0 jest zadaniem podstawowym, a wszystkie inne identyfikatory to podzadania. Jeśli na przykład utworzysz następujące ustawienia obejmujące wiele wystąpień dla zadania, zadanie podstawowe będzie miało identyfikator 0, a podzadania będą miały identyfikatory od 1 do 9.

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

Węzeł główny

Po przesłaniu zadania obejmującego wiele wystąpień usługa Batch wyznacza jeden z węzłów obliczeniowych jako węzeł główny i planuje wykonanie zadania podstawowego w węźle głównym. Podzadania są zaplanowane do wykonania w pozostałej części węzłów przydzielonych do zadania z wieloma wystąpieniami.

Polecenie koordynacji

Polecenie koordynacji jest wykonywane zarówno przez podzadania podstawowe, jak i podrzędne.

Wywołanie polecenia koordynacji blokuje — usługa Batch nie wykonuje polecenia aplikacji, dopóki polecenie koordynacji nie zwróci pomyślnie wszystkich podzadań. W związku z tym polecenie koordynacji powinno uruchomić wszystkie wymagane usługi w tle, sprawdzić, czy są gotowe do użycia, a następnie zakończyć pracę. Na przykład to polecenie koordynacji dla rozwiązania korzystającego z ms-MPI w wersji 7 uruchamia usługę SMPD w węźle, a następnie kończy działanie:

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

Zwróć uwagę na użycie start w tym poleceniu koordynacji. Jest to wymagane, ponieważ smpd.exe aplikacja nie zwraca się natychmiast po wykonaniu. Bez użycia polecenia uruchamiania to polecenie koordynacji nie zwróci polecenia i w związku z tym zablokuje uruchomienie polecenia aplikacji.

Polecenie aplikacji

Gdy zadanie podstawowe i wszystkie podzadania zakończą wykonywanie polecenia koordynacji, wiersz polecenia zadania z wieloma wystąpieniami jest wykonywany tylko przez zadanie podstawowe. Nazywamy to poleceniem aplikacji, aby odróżnić je od polecenia koordynacji.

W przypadku aplikacji MS-MPI użyj polecenia aplikacji, aby wykonać aplikację z obsługą interfejsu MPI za pomocą polecenia mpiexec.exe. Na przykład poniżej przedstawiono polecenie aplikacji dla rozwiązania przy użyciu ms-MPI w wersji 7:

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

Uwaga

Ponieważ ms-MPI mpiexec.exe używa zmiennej CCP_NODES domyślnie (zobacz Zmienne środowiskowe), przykładowy wiersz polecenia aplikacji powyżej wyklucza ją.

Zmienne środowiskowe

Usługa Batch tworzy kilka zmiennych środowiskowych specyficznych dla zadań obejmujących wiele wystąpień w węzłach obliczeniowych przydzielonych do zadania obejmującego wiele wystąpień. Wiersze poleceń koordynacji i aplikacji mogą odwoływać się do tych zmiennych środowiskowych, tak jak skrypty i programy, które wykonują.

Następujące zmienne środowiskowe są tworzone przez usługę Batch do użycia przez zadania z wieloma wystąpieniami:

  • 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

Aby uzyskać szczegółowe informacje na temat tych i innych zmiennych środowiskowych węzła obliczeniowego usługi Batch, w tym ich zawartości i widoczności, zobacz Zmienne środowiskowe węzła obliczeniowego.

Napiwek

Przykładowy kod MPI systemu Linux usługi Batch zawiera przykład użycia kilku z tych zmiennych środowiskowych.

Pliki zasobów

Istnieją dwa zestawy plików zasobów, które należy wziąć pod uwagę w przypadku zadań obejmujących wiele wystąpień: typowe pliki zasobów pobierane przez wszystkie zadania podrzędne (zarówno podstawowe, jak i podrzędne) oraz pliki zasobów określone dla samego zadania z wieloma wystąpieniami, które pobiera tylko zadanie podstawowe .

W ustawieniach wielu wystąpień dla zadania można określić jeden lub więcej typowych plików zasobów. Te typowe pliki zasobów są pobierane z usługi Azure Storage do katalogu udostępnionego zadania każdego węzła przez podstawowe i wszystkie podzadania. Dostęp do udostępnionego katalogu zadań można uzyskać z poziomu wierszy poleceń aplikacji i koordynacji przy użyciu zmiennej środowiskowej AZ_BATCH_TASK_SHARED_DIR . Ścieżka jest identyczna AZ_BATCH_TASK_SHARED_DIR w każdym węźle przydzielonym do zadania z wieloma wystąpieniami, dzięki czemu można współużytkować jedno polecenie koordynacji między podzadaniami podstawowymi i wszystkimi podzadaniami. Usługa Batch nie udostępnia katalogu w sensie dostępu zdalnego, ale można użyć go jako punktu instalacji lub udziału, jak wspomniano wcześniej w poradzie dotyczącej zmiennych środowiskowych.

Pliki zasobów określone dla samego zadania z wieloma wystąpieniami są pobierane do katalogu roboczego zadania podrzędnego , AZ_BATCH_TASK_WORKING_DIRdomyślnie. Jak wspomniano, w przeciwieństwie do typowych plików zasobów tylko podstawowe zadanie pobiera pliki zasobów określone dla samego zadania z wieloma wystąpieniami.

Ważne

Zawsze używaj zmiennych AZ_BATCH_TASK_SHARED_DIR środowiskowych i AZ_BATCH_TASK_WORKING_DIR odwołaj się do tych katalogów w wierszach polecenia. Nie należy próbować ręcznie konstruować ścieżek.

Okres istnienia zadania

Okres istnienia zadania podstawowego kontroluje okres istnienia całego zadania z wieloma wystąpieniami. Po zakończeniu działania podstawowego wszystkie podzadania zostaną zakończone. Kod zakończenia zadania podstawowego jest kodem zakończenia zadania i dlatego służy do określania powodzenia lub niepowodzenia zadania na potrzeby ponawiania próby.

Jeśli którykolwiek z podzadań zakończy się niepowodzeniem, zakończ działanie z kodem niezerowym, na przykład całe zadanie z wieloma wystąpieniami zakończy się niepowodzeniem. Zadanie z wieloma wystąpieniami jest następnie przerywane i ponawiane, aż do limitu ponawiania prób.

Usunięcie zadania obejmującego wiele wystąpień powoduje również usunięcie podstawowych i wszystkich podzadań przez usługę Batch. Wszystkie katalogi podrzędne i ich pliki są usuwane z węzłów obliczeniowych, podobnie jak w przypadku zadania standardowego.

Ograniczenia zadań dla zadania z wieloma wystąpieniami, takie jak MaxTaskRetryCount, MaxWallClockTime i RetentionTime, są uznawane za standardowe zadanie i mają zastosowanie do podstawowych i wszystkich podzadań. Jeśli jednak zmienisz właściwośćRetentionTime po dodaniu zadania z wieloma wystąpieniami do zadania, ta zmiana zostanie zastosowana tylko do zadania podstawowego, a wszystkie podzadania będą nadal używać oryginalnego czasu przechowywania.

Ostatnia lista zadań węzła obliczeniowego odzwierciedla identyfikator podzadaku, jeśli ostatnie zadanie było częścią zadania obejmującego wiele wystąpień.

Uzyskiwanie informacji o podzadaniach

Aby uzyskać informacje o podzadaniach przy użyciu biblioteki platformy .NET usługi Batch, wywołaj metodę CloudTask.ListSubtasks . Ta metoda zwraca informacje o wszystkich podzadaniach oraz informacje o węźle obliczeniowym, który wykonał zadania. Z tych informacji można określić katalog główny każdego podzadaku, identyfikator puli, jego bieżący stan, kod zakończenia i nie tylko. Te informacje można używać w połączeniu z metodą PoolOperations.GetNodeFile w celu uzyskania plików podzadania. Należy pamiętać, że ta metoda nie zwraca informacji dla zadania podstawowego (identyfikator 0).

Uwaga

O ile nie określono inaczej, metody platformy .NET usługi Batch, które działają na samej usłudze CloudTask z wieloma wystąpieniami, mają zastosowanie tylko do zadania podstawowego. Na przykład po wywołaniu metody CloudTask.ListNodeFiles w zadaniu z wieloma wystąpieniami zwracane są tylko pliki zadania podstawowego.

Poniższy fragment kodu pokazuje, jak uzyskać informacje o podtakach, a także żądać zawartości pliku z węzłów, na których zostały wykonane.

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

Przykład kodu

Przykładowy kod MultiInstanceTasks w usłudze GitHub pokazuje, jak używać zadania z wieloma wystąpieniami do uruchamiania aplikacji MS-MPI w węzłach obliczeniowych usługi Batch. Wykonaj poniższe kroki, aby uruchomić przykład.

Przygotowywanie

  1. Pobierz zestaw SDK MS-MPI i instalatory redist i zainstaluj je. Po zainstalowaniu można sprawdzić, czy zmienne środowiskowe MS-MPI zostały ustawione.
  2. Utwórz wersję wydania przykładowego programu MPIHelloWorld. Jest to program, który będzie uruchamiany w węzłach obliczeniowych przez zadanie z wieloma wystąpieniami.
  3. Utwórz plik zip zawierający MPIHelloWorld.exe (utworzony w kroku 2) i MSMpiSetup.exe (pobrany w kroku 1). Ten plik zip zostanie przekazany jako pakiet aplikacji w następnym kroku.
  4. Użyj witryny Azure Portal, aby utworzyć aplikację usługi Batch o nazwie "MPIHelloWorld" i określić plik zip utworzony w poprzednim kroku jako wersję "1.0" pakietu aplikacji. Aby uzyskać więcej informacji, zobacz Przekazywanie aplikacji i zarządzanie nimi.

Napiwek

Utworzenie wersji wydania MPIHelloWorld.exe gwarantuje, że nie trzeba uwzględniać żadnych dodatkowych zależności (na przykład msvcp140d.dll lub vcruntime140d.dll) w pakiecie aplikacji.

Wykonanie

  1. Pobierz plik .zip azure-batch-samples z usługi GitHub.

  2. Otwórz rozwiązanie MultiInstanceTasks w programie Visual Studio 2019. Plik MultiInstanceTasks.sln rozwiązania znajduje się w:

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

  3. Wprowadź poświadczenia konta usługi Batch i magazynu w AccountSettings.settings projekcie Microsoft.Azure.Batch.Samples.Common .

  4. Skompiluj i uruchom rozwiązanie MultiInstanceTasks, aby wykonać przykładową aplikację MPI w węzłach obliczeniowych w puli usługi Batch.

  5. Opcjonalnie: użyj witryny Azure Portal lub narzędzia Batch Explorer , aby zbadać przykładową pulę, zadanie i zadanie ("MultiInstanceSamplePool", "MultiInstanceSampleJob", "MultiInstanceSampleTask") przed usunięciem zasobów.

Napiwek

Możesz bezpłatnie pobrać program Visual Studio Community , jeśli nie masz jeszcze programu Visual Studio.

Dane wyjściowe z MultiInstanceTasks.exe funkcji są podobne do następujących:

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

Następne kroki