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

Zadania obejmujące wiele wystąpień umożliwiają jednoczesne uruchamianie zadania 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. W tym artykule 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 z wieloma wystąpieniami

W usłudze Batch każde zadanie jest zwykle wykonywane w 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 następnie są wykonywane w wielu węzłach.

Diagram przedstawiający omówienie ustawień wielu wystąpień.

Podczas przesyłania zadania z ustawieniami wielu wystąpień do zadania usługa Batch wykonuje kilka kroków unikatowych dla zadań z wieloma wystąpieniami:

  1. Usługa Batch tworzy jeden podstawowy i kilka podzadań na podstawie ustawień wielu wystąpień. Całkowita liczba zadań (podstawowy 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 ona wykonanie podzadania w pozostałej części węzłów obliczeniowych przydzielonych do zadania z wieloma wystąpieniami— jednej 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 podstawowe i podzadania 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 firmysmpd.exe Microsoft) i sprawdzenie, 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 wykonujesz 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ń z wieloma wystąpieniami

Zadania obejmujące wiele wystąpień 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.

W tym fragmencie kodu pokazano, jak utworzyć pulę dla zadań z wieloma wystąpieniami przy użyciu biblioteki usługi Batch .NET.

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ędzy węzłami lub z wartością taskSlotsPerNode większą niż 1, zadanie nigdy nie jest zaplanowane — pozostaje bezterminowo w stanie "aktywny".

Pule z włączoną funkcją InterComputeNodeCommunication nie zezwalają automatycznie na anulowanie aprowizacji węzła.

Instalowanie interfejsu MPI przy użyciu narzędzia StartTask

Aby uruchamiać aplikacje MPI z zadaniem z wieloma wystąpieniami, należy najpierw zainstalować implementację MPI (MS-MPI lub Intel MPI, na przykład) na węzłach obliczeniowych w puli. Jest to dobry czas, 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 nienadzorowaną instalację 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 obsługą funkcji 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ą funkcji RDMA" w obszarze Rozmiary maszyn wirtualnych na platformie Azure (w przypadku pul VirtualMachineConfiguration) lub Rozmiary dla 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 z wieloma wystąpieniami przy użyciu platformy .NET usługi Batch

Teraz, gdy 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ę podzadania , które są razem zgodne z liczbą określonych węzłów.

Te zadania są przypisywane identyfikatora całkowitego w zakresie od 0 do liczbyOfInstances — 1. Zadanie o identyfikatorze 0 jest zadaniem podstawowym, a wszystkie inne identyfikatory to podzadania. Jeśli na przykład utworzysz następujące ustawienia wielu wystąpień dla zadania, zadanie podstawowe będzie mieć 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

Podczas przesyłania zadania z wieloma wystąpieniami 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 powoduje zablokowanie — 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

Zanotuj start użycie 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 zostanie zwrócone i w związku z tym uniemożliwi uruchomienie polecenia aplikacji.

Polecenie aplikacji

Gdy zadanie podstawowe i wszystkie podzadania zakończyły 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 oto polecenie aplikacji dla rozwiązania korzystającego z ms-MPI w wersji 7:

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

Uwaga

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

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 z wieloma wystąpieniami. Linie poleceń koordynacji i aplikacji mogą odwoływać się do tych zmiennych środowiskowych, ponieważ mogą być wykonywane skrypty i programy.

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.

Porada

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 , które pobierają wszystkie zadania podrzędne (zarówno podstawowe, jak i podrzędne), oraz pliki zasobów określone dla samego zadania obejmującego wiele wystąpień, 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 katalogu udostępnionego zadania 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ółdzielić 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 go użyć 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ływania 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, zamknięcie z kodem zwracanym bez zera, na przykład całe zadanie obejmujące wiele wystąpień kończy się niepowodzeniem. Zadanie z wieloma wystąpieniami jest następnie przerywane i ponawiane do limitu ponawiania prób.

Usunięcie zadania obejmującego wiele wystąpień powoduje również usunięcie podzadania podstawowego 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 obejmującego wiele wystąpień, takich jak MaxTaskRetryCount, MaxWallClockTime i RetentionTime , są uznawane za standardowe zadanie i mają zastosowanie do podzadania podstawowego 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 i 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żyć 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 o wielu wystąpieniach zwracane są tylko pliki zadania podstawowego.

Poniższy fragment kodu pokazuje, jak uzyskać informacje o podzadanie, 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 przedstawia sposób użycia 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.

Przygotowanie

  1. Pobierz zestaw SDK MS-MPI i instalatory redist i zainstaluj je. Po zakończeniu instalacji można sprawdzić, czy zmienne środowiskowe MS-MPI zostały ustawione.
  2. Skompiluj 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 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 .

Porada

Utworzenie wersji programuMPIHelloWorld.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 Azure Portal lub Batch Explorer, aby zbadać przykładową pulę, zadanie i zadanie ("MultiInstanceSamplePool", "MultiInstanceSampleJob", "MultiInstanceSampleTask") przed usunięciem zasobów.

Porada

Jeśli nie masz jeszcze programu Visual Studio, możesz pobrać Visual Studio Community bezpłatnie.

Dane wyjściowe z MultiInstanceTasks.exe polecenia 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