Równoczesne uruchamianie zadań w celu zmaksymalizowania użycia węzłów obliczeniowych usługi Batch

Możesz zmaksymalizować użycie zasobów na mniejszej liczbie węzłów obliczeniowych w puli, uruchamiając jednocześnie więcej niż jedno zadanie w każdym węźle.

Chociaż niektóre scenariusze działają najlepiej ze wszystkimi zasobami węzła przeznaczonymi dla jednego zadania, niektóre obciążenia mogą widzieć krótsze czasy zadań i obniżyć koszty, gdy wiele zadań współużytkuje te zasoby. Rozważ następujące scenariusze:

  • Minimalizuj transfer danych dla zadań, które mogą udostępniać dane. Opłaty za transfer danych można znacznie zmniejszyć, kopiując udostępnione dane do mniejszej liczby węzłów, a następnie wykonując zadania równolegle w każdym węźle. Ta strategia jest szczególnie stosowana, jeśli dane do skopiowania do każdego węzła muszą być przesyłane między regionami geograficznymi.
  • Maksymalizuj użycie pamięci dla zadań wymagających dużej ilości pamięci, ale tylko w krótkich okresach czasu i w zmiennych godzinach wykonywania. Możesz stosować mniej, ale większe węzły obliczeniowe z większą ilością pamięci, aby efektywnie obsługiwać takie skoki. Te węzły mają wiele zadań uruchomionych równolegle w każdym węźle, ale każde zadanie może korzystać z obfitej pamięci węzłów w różnych momentach.
  • Ogranicz limity liczby węzłów , gdy komunikacja między węzłami jest wymagana w puli. Obecnie pule skonfigurowane na potrzeby komunikacji między węzłami są ograniczone do 50 węzłów obliczeniowych. Jeśli każdy węzeł w takiej puli może równolegle wykonywać zadania, można wykonać większą liczbę zadań jednocześnie.
  • Replikowanie lokalnego klastra obliczeniowego, takiego jak podczas pierwszego przenoszenia środowiska obliczeniowego na platformę Azure. Jeśli bieżące rozwiązanie lokalne wykonuje wiele zadań na węzeł obliczeniowy, możesz zwiększyć maksymalną liczbę zadań węzłów w celu dokładniejszego dublowania tej konfiguracji.

Przykładowy scenariusz

Załóżmy na przykład, że aplikacja zadań z wymaganiami dotyczącymi procesora CPU i pamięci, takie jak Standard_D1 węzły są wystarczające. Jednak aby zakończyć zadanie w wymaganym czasie, potrzebne jest 1000 tych węzłów.

Zamiast używać węzłów Standard_D1 z jednym rdzeniem procesora CPU, można użyć Standard_D14 węzłów z 16 rdzeniami i włączyć równoległe wykonywanie zadań. Potencjalnie można użyć 16 razy mniejszej liczby węzłów zamiast 1000 węzłów, wymagane będzie tylko 63. Jeśli duże pliki aplikacji lub dane referencyjne są wymagane dla każdego węzła, czas trwania zadania i wydajność są lepsze, ponieważ dane są kopiowane do tylko 63 węzłów.

Włączanie równoległego wykonywania zadań

Węzły obliczeniowe są konfigurowane na potrzeby równoległego wykonywania zadań na poziomie puli. W bibliotece .NET usługi Batch ustaw właściwość CloudPool.TaskSlotsPerNode podczas tworzenia puli. Jeśli używasz interfejsu API REST usługi Batch, ustaw element taskSlotsPerNode w treści żądania podczas tworzenia puli.

Uwaga

Element i właściwość TaskSlotsPerNode można ustawić taskSlotsPerNode tylko w czasie tworzenia puli. Nie można ich modyfikować po utworzeniu puli.

Azure Batch umożliwia ustawienie miejsc zadań na węzeł do (4x) liczby rdzeni węzła. Jeśli na przykład pula jest skonfigurowana z węzłami o rozmiarze "Duży" (cztery rdzenie), może taskSlotsPerNode być ustawiona na 16. Jednak niezależnie od liczby rdzeni węzła nie można mieć więcej niż 256 miejsc zadań na węzeł. Aby uzyskać szczegółowe informacje na temat liczby rdzeni dla każdego rozmiaru węzła, zobacz Rozmiary dla Cloud Services (wersja klasyczna). Aby uzyskać więcej informacji na temat limitów usług, zobacz Batch service quotas and limits (Limity i limity usługi Batch).

Porada

Pamiętaj, aby uwzględnić taskSlotsPerNode wartość podczas tworzenia formuły autoskalowania dla puli. Na przykład formuła, która ocenia $RunningTasks , może być znacząco dotknięta wzrostem liczby zadań na węzeł. Aby uzyskać więcej informacji, zobacz Tworzenie formuły automatycznej na potrzeby skalowania węzłów obliczeniowych w puli usługi Batch.

Określanie dystrybucji zadań

Podczas włączania współbieżnych zadań ważne jest określenie sposobu dystrybucji zadań między węzłami w puli.

Za pomocą właściwości CloudPool.TaskSchedulingPolicy można określić, że zadania powinny być przypisywane równomiernie we wszystkich węzłach w puli ("rozprzestrzenianie"). Możesz też określić, że jak najwięcej zadań powinno być przypisanych do każdego węzła, zanim zadania zostaną przypisane do innego węzła w puli ("pakowanie").

Rozważmy na przykład pulę węzłów Standard_D14 (w poprzednim przykładzie), która jest skonfigurowana przy użyciu wartości CloudPool.TaskSlotsPerNode 16. Jeśli pula CloudPool.TaskSchedulingPolicy jest skonfigurowana za pomocą klasy ComputeNodeFillTypepakietu, maksymalizuj użycie wszystkich 16 rdzeni każdego węzła i umożliwia automatyczne skalowanie puli do usuwania nieużywanych węzłów (węzłów bez przydzielonych zadań) z puli. Skalowanie automatyczne minimalizuje użycie zasobów i może zaoszczędzić pieniądze.

Definiowanie miejsc zmiennych na zadanie

Zadanie można zdefiniować za pomocą właściwości CloudTask.RequiredSlots , określając liczbę miejsc wymaganych do uruchomienia w węźle obliczeniowym. Wartość domyślna to 1. Możesz ustawić zmienne miejsca zadań, jeśli zadania mają różne wagi skojarzone z ich użyciem zasobów w węźle obliczeniowym. Zmienne miejsca zadań umożliwiają każdemu węzłowi obliczeniowej rozsądną liczbę współbieżnych uruchomionych zadań bez przytłaczających zasobów systemowych, takich jak procesor CPU lub pamięć.

Na przykład w przypadku puli z właściwością taskSlotsPerNode = 8można przesłać wiele rdzeni wymaganych zadań intensywnie korzystających z procesora CPU za pomocą requiredSlots = 8polecenia , podczas gdy inne zadania można ustawić na requiredSlots = 1. Po zaplanowaniu tego mieszanego obciążenia zadania intensywnie korzystające z procesora CPU są uruchamiane wyłącznie na ich węzłach obliczeniowych, podczas gdy inne zadania mogą być uruchamiane współbieżnie (maksymalnie osiem zadań jednocześnie) w innych węzłach. Mieszane obciążenie pomaga równoważyć obciążenie między węzłami obliczeniowymi i zwiększyć wydajność użycia zasobów.

Upewnij się, że nie określisz zadania requiredSlots , które ma być większe niż pula taskSlotsPerNode, lub zadanie nigdy nie jest uruchamiane. Usługa Batch nie weryfikuje obecnie tego konfliktu podczas przesyłania zadań. Nie weryfikuje konfliktu, ponieważ zadanie może nie mieć puli powiązanej w czasie przesyłania lub może zmienić się na inną pulę, wyłączając/ponownie włączając.

Porada

W przypadku korzystania ze zmiennych miejsc zadań możliwe jest, że duże zadania z bardziej wymaganymi miejscami mogą tymczasowo zakończyć się niepowodzeniem, ponieważ nie ma wystarczającej liczby miejsc w dowolnym węźle obliczeniowym, nawet jeśli w niektórych węzłach nadal są bezczynne miejsca. Możesz podnieść priorytet zadania dla tych zadań, aby zwiększyć ich szansę konkurowania o dostępne miejsca w węzłach.

Usługa Batch emituje element TaskScheduleFailEvent , gdy nie można zaplanować zadania do uruchomienia i ponowi próbę planowania, dopóki wymagane miejsca nie staną się dostępne. Możesz nasłuchiwać tego zdarzenia, aby wykryć potencjalne problemy z planowaniem zadań i odpowiednio rozwiązać ten problem.

Przykład usługi Batch .NET

Poniższe fragmenty kodu interfejsu API platformy .NET usługi Batch pokazują, jak utworzyć pulę z wieloma miejscami zadań na węzeł i jak przesłać zadanie z wymaganymi miejscami.

Tworzenie puli z wieloma miejscami zadań na węzeł

Ten fragment kodu przedstawia żądanie utworzenia puli zawierającej cztery węzły z czterema miejscami zadań dozwolonymi na węzeł. Określa ona zasady planowania zadań, które wypełniają każdy węzeł zadaniami przed przypisaniem zadań do innego węzła w puli.

Aby uzyskać więcej informacji na temat dodawania pul przy użyciu interfejsu API platformy .NET usługi Batch, zobacz BatchClient.PoolOperations.CreatePool.

CloudPool pool =
    batchClient.PoolOperations.CreatePool(
        poolId: "mypool",
        targetDedicatedComputeNodes: 4
        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");

pool.TaskSlotsPerNode = 4;
pool.TaskSchedulingPolicy = new TaskSchedulingPolicy(ComputeNodeFillType.Pack);
pool.Commit();

Tworzenie zadania z wymaganymi miejscami

Ten fragment kodu tworzy zadanie z niedefault requiredSlots. To zadanie jest uruchamiane, gdy w węźle obliczeniowym jest wystarczająca ilość wolnych miejsc.

CloudTask task = new CloudTask(taskId, taskCommandLine)
{
    RequiredSlots = 2
};

Wyświetlanie listy węzłów obliczeniowych z liczbą uruchomionych zadań i miejsc

Ten fragment kodu zawiera listę wszystkich węzłów obliczeniowych w puli i drukuje liczby uruchamiania zadań i miejsc zadań na węzeł.

ODATADetailLevel nodeDetail = new ODATADetailLevel(selectClause: "id,runningTasksCount,runningTaskSlotsCount");
IPagedEnumerable<ComputeNode> nodes = batchClient.PoolOperations.ListComputeNodes(poolId, nodeDetail);

await nodes.ForEachAsync(node =>
{
    Console.WriteLine(node.Id + " :");
    Console.WriteLine($"RunningTasks = {node.RunningTasksCount}, RunningTaskSlots = {node.RunningTaskSlotsCount}");

}).ConfigureAwait(continueOnCapturedContext: false);

Wyświetlanie listy liczników zadań dla zadania

Ten fragment kodu pobiera liczniki zadań dla zadania, które obejmują zarówno zadania, jak i liczbę miejsc zadań na stan zadania.

TaskCountsResult result = await batchClient.JobOperations.GetJobTaskCountsAsync(jobId);

Console.WriteLine("\t\tActive\tRunning\tCompleted");
Console.WriteLine($"TaskCounts:\t{result.TaskCounts.Active}\t{result.TaskCounts.Running}\t{result.TaskCounts.Completed}");
Console.WriteLine($"TaskSlotCounts:\t{result.TaskSlotCounts.Active}\t{result.TaskSlotCounts.Running}\t{result.TaskSlotCounts.Completed}");

Przykład rest usługi Batch

Poniższe fragmenty kodu interfejsu API REST usługi Batch pokazują, jak utworzyć pulę z wieloma miejscami zadań na węzeł i jak przesłać zadanie z wymaganymi miejscami.

Tworzenie puli z wieloma miejscami zadań na węzeł

Ten fragment kodu przedstawia żądanie utworzenia puli zawierającej dwa duże węzły z maksymalnie czterema zadaniami na węzeł.

Aby uzyskać więcej informacji na temat dodawania pul przy użyciu interfejsu API REST, zobacz Dodawanie puli do konta.

{
  "odata.metadata":"https://myaccount.myregion.batch.azure.com/$metadata#pools/@Element",
  "id":"mypool",
  "vmSize":"large",
  "virtualMachineConfiguration": {
    "imageReference": {
      "publisher": "canonical",
      "offer": "ubuntuserver",
      "sku": "20.04-lts"
    },
    "nodeAgentSKUId": "batch.node.ubuntu 20.04"
  },
  "targetDedicatedComputeNodes":2,
  "taskSlotsPerNode":4,
  "enableInterNodeCommunication":true,
}

Tworzenie zadania z wymaganymi miejscami

Ten fragment kodu przedstawia żądanie dodania zadania z niedefault requiredSlots. To zadanie jest uruchamiane tylko wtedy, gdy w węźle obliczeniowym jest wystarczająca ilość wolnych miejsc.

{
  "id": "taskId",
  "commandLine": "bash -c 'echo hello'",
  "userIdentity": {
    "autoUser": {
      "scope": "task",
      "elevationLevel": "nonadmin"
    }
  },
  "requiredSLots": 2
}

Przykład kodu w witrynie GitHub

Projekt ParallelTasks w usłudze GitHub ilustruje użycie właściwości CloudPool.TaskSlotsPerNode .

Ta aplikacja konsolowa języka C# używa biblioteki .NET usługi Batch do utworzenia puli z co najmniej jednym węzłem obliczeniowym. Wykonuje on konfigurowalną liczbę zadań w tych węzłach w celu symulowania zmiennego obciążenia. Dane wyjściowe z aplikacji pokazują, które węzły wykonały każde zadanie. Aplikacja zawiera również podsumowanie parametrów i czasu trwania zadania.

W poniższym przykładzie przedstawiono część podsumowania danych wyjściowych z dwóch różnych przebiegów przykładowej aplikacji ParallelTasks. Czasy trwania zadania przedstawione w tym miejscu nie obejmują czasu tworzenia puli, ponieważ każde zadanie zostało przesłane do wcześniej utworzonej puli, której węzły obliczeniowe były w stanie bezczynności w czasie przesyłania.

Pierwsze wykonanie przykładowej aplikacji pokazuje, że z pojedynczym węzłem w puli i domyślnym ustawieniem jednego zadania na węzeł, czas trwania zadania wynosi ponad 30 minut.

Nodes: 1
Node size: large
Task slots per node: 1
Max slots per task: 1
Tasks: 32
Duration: 00:30:01.4638023

Drugi przebieg przykładu pokazuje znaczny spadek czasu trwania zadania. Jest to spowodowane tym, że pula została skonfigurowana z czterema zadaniami na węzeł, co umożliwia równoległe wykonywanie zadania w ciągu prawie jednej czwartej czasu.

Nodes: 1
Node size: large
Task slots per node: 4
Max slots per task: 1
Tasks: 32
Duration: 00:08:48.2423500

Następne kroki