Поделиться через


Запуск задач параллельно для максимального использования вычислительных узлов Batch.

Максимальное использование ресурсов можно увеличить на меньшем количестве вычислительных узлов в пуле, одновременно выполняя несколько задач на каждом узле.

Хотя некоторые сценарии лучше всего работают, когда все ресурсы узла выделяются для одной задачи, в некоторых рабочих нагрузках можно наблюдать сокращение времени выполнения заданий и снижению затрат при совместном использовании этих ресурсов несколькими задачами. Рассмотрим следующие сценарии:

  • Свести к минимуму передачу данных для задач, совместно использующих данные. Вы можете значительно сократить расходы на передачу данных, скопировав общие данные в меньшее количество узлов, а затем параллельно выполняя задачи на каждом узле. Эта стратегия особенно применяется, если данные, скопированные на каждый узел, должны передаваться между географическими регионами.
  • Максимальное использование памяти для задач, требующих большого объема памяти, но только в течение коротких периодов времени и в различные моменты выполнения. Вы можете использовать меньше, но больше вычислительных узлов с большей памятью для эффективной обработки таких пиков. Эти узлы имеют несколько задач, выполняемых параллельно на каждом узле, но каждая задача может использовать много памяти узлов в разное время.
  • Устранение ограничений числа узлов при необходимости взаимодействия между узлами в пуле. В настоящее время пулы, настроенные для обмена данными между узлами, ограничены 50 вычислительными узлами. Если каждый узел в таком пуле может выполнять задачи параллельно, можно одновременно выполнять большее количество задач.
  • Репликация локального вычислительного кластера, например при первом перемещении вычислительной среды в Azure. Если текущее локальное решение выполняет несколько задач на вычислительный узел, можно увеличить максимальное количество задач узлов, чтобы более точно отражать эту конфигурацию.

Пример сценария

Например, представьте приложение с требованиями по центральному процессору и памяти так, что узлы Standard_D1 будут достаточными. Тем не менее, чтобы завершить задание в необходимое время, необходимо 1000 этих узлов.

Вместо использования Standard_D1 узлов с одним ядром ЦП можно использовать Standard_D14 узлы с 16 ядрами и включить параллельное выполнение задач. Возможно, вы можете использовать 16 раз меньше узлов вместо 1000 узлов, потребуется только 63. Если для каждого узла требуются большие файлы приложений или справочные данные, длительность задания и эффективность будут улучшены, так как данные копируются только на 63 узла.

Включение параллельного выполнения задач

Вы настраиваете вычислительные узлы для параллельного выполнения задач на уровне пула. В библиотеке Batch .NET задайте свойство CloudPool.TaskSlotsPerNode при создании пула. Если вы используете REST API пакетной службы, задайте элемент taskSlotsPerNode в тексте запроса во время создания пула.

Примечание.

Задать элемент taskSlotsPerNode и свойство TaskSlotsPerNode можно только во время создания пула. Эти параметры нельзя изменить после создания пула.

Служба Azure Batch позволяет задавать слоты задач на узел до четырех раз больше числа ядер узла. Например, если пул настроен с узлами размера "Большой" (четыре ядра), taskSlotsPerNode может быть задано значение 16. Однако независимо от того, сколько ядер имеет узел, нельзя иметь более 256 слотов задач на узел. Дополнительные сведения о количестве ядер для каждого размера узла см. в разделе "Размеры облачных служб" (классическая модель). Дополнительные сведения об ограничениях служб см. в разделе "Квоты и ограничения пакетной службы".

Подсказка

Обязательно учитывайте taskSlotsPerNode значение при создании формулы автомасштабирования для пула. Например, на формулу, которая оценивает $RunningTasks, может значительно повлиять увеличение количества задач на узел. Дополнительные сведения см. в статье "Создание автоматической формулы для масштабирования вычислительных узлов в пуле Batch."

Указание распределения задач

При включении параллельных задач важно указать способ распределения задач между узлами в пуле.

Используя свойство CloudPool.TaskSchedulingPolicy , можно указать, что задачи должны назначаться равномерно по всем узлам в пуле (распространение). Вы также можете указать, что максимально возможное количество задач должно назначаться каждому узлу, прежде чем задачи будут распределены на другой узел в пуле (упаковка).

В качестве примера рассмотрим пул узлов Standard_D14 (в предыдущем примере), настроенный с помощью значения CloudPool.TaskSlotsPerNode 16. Если CloudPool.TaskSchedulingPolicy настроен с параметром ComputeNodeFillTypePack, это позволит максимально использовать все 16 ядер каждого узла и позволит пулу автомасштабирования удалять неиспользуемые узлы из пула, то есть узлы, которым не назначены задачи. Автоматическое масштабирование сводит к минимуму использование ресурсов и может сэкономить деньги.

Определение слотов переменных для каждой задачи

Задачу можно определить с помощью свойства CloudTask.RequiredSlots , указывая, сколько слотов требуется для запуска на вычислительном узле. Значение по умолчанию — 1. Можно задать слоты задач переменной, если задачи имеют разные весовые значения, связанные с их использованием ресурсов на вычислительном узле. Слоты задач переменной позволяют каждому вычислительному узлу иметь разумное количество параллельных задач без подавляющего числа системных ресурсов, таких как ЦП или память.

Например, для пула со свойством taskSlotsPerNode = 8 можно отправлять задачи, требующие многоядерного процессора requiredSlots = 8, а другие задачи можно назначить на requiredSlots = 1. Если эта смешанная рабочая нагрузка запланирована, задачи с большим объемом ЦП выполняются исключительно на вычислительных узлах, а другие задачи могут выполняться одновременно (до восьми задач одновременно) на других узлах. Смешанная рабочая нагрузка помогает сбалансировать рабочую нагрузку на вычислительных узлах и повысить эффективность использования ресурсов.

Убедитесь, что вы не указываете requiredSlots задачи больше, чем taskSlotsPerNode пула, иначе задача никогда не выполнится. Пакетная служба в настоящее время не проверяет этот конфликт при отправке задач. Он не подтверждает конфликт, так как задание может не иметь привязки к пулу на момент отправки, или это привязка может измениться на другой пул при отключении и повторном включении.

Подсказка

При использовании переменных слотов задач возможно, что большие задачи, требующие больше слотов, может временно не удаваться запланировать, так как есть недостаток доступных слотов на любом вычислительном узле, даже если на некоторых узлах ещё есть незанятые слоты. Вы можете повысить приоритет задания для этих задач, чтобы увеличить их шансы конкурировать за доступные слоты на узлах.

Пакетная служба выдает taskScheduleFailEvent , если не удается запланировать выполнение задачи и сохраняет повторную попытку планирования до тех пор, пока необходимые слоты не станут доступными. Это событие можно прослушивать, чтобы обнаруживать потенциальные проблемы планирования задач и устранять соответствующие проблемы.

Пример пакетной обработки .NET

В следующих фрагментах кода API Batch .NET показано, как создать пул с несколькими слотами задач для каждого узла и как отправить задачу с требуемыми слотами.

Создайте пул с несколькими слотами задач для каждого узла

В этом фрагменте кода показан запрос на создание пула, содержащего четыре узла, с четырьмя слотами задач, разрешенными для каждого узла. Он задает политику планирования задач, которая заполняет каждый узел задачами перед назначением задач другому узлу в пуле.

Дополнительные сведения о добавлении пулов с помощью API Пакетной службы .NET см. в разделе 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();

Создайте задачу с необходимыми слотами

Этот фрагмент кода создает задачу с режимом "nondefault" requiredSlots. Эта задача выполняется, если на вычислительном узле достаточно свободных слотов.

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

Вывести список вычислительных узлов с количеством выполняемых задач и доступных слотов.

Этот фрагмент кода содержит список всех вычислительных узлов в пуле и выводит счетчики для выполнения задач и слотов задач на узел.

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

Список количества задач для работы

Этот фрагмент кода получает количество задач для задания, включая как количество задач, так и количество слотов на каждое состояние задачи.

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

Пример пакетного REST-запроса

В следующих фрагментах кода Batch REST API показано, как создать пул с несколькими слотами заданий на узле и как отправить задание с требуемыми слотами.

Создать пул с несколькими слотами задач для каждого узла

В этом фрагменте кода показан запрос на создание пула, содержащего два больших узла с не более чем четырьмя задачами на узел.

Дополнительные сведения о добавлении пулов с помощью REST API см. в статье "Добавление пула в учетную запись".

{
  "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,
}

Создайте задачу с необходимыми слотами

В этом фрагменте кода показан запрос на добавление задачи с нестандартными requiredSlots. Эта задача выполняется только в том случае, если на вычислительном узле достаточно свободных слотов.

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

Пример кода на GitHub

Проект ParallelTasks на GitHub иллюстрирует использование свойства CloudPool.TaskSlotsPerNode .

Это консольное приложение C# использует библиотеку Batch .NET для создания пула с одним или несколькими вычислительными узлами. Он выполняет настраиваемое количество задач на этих узлах для имитации переменной нагрузки. Выходные данные приложения показывают, какие узлы выполняли каждую задачу. Приложение также содержит сводку по параметрам задания и длительности.

В следующем примере показана сводная часть выходных данных из двух разных запусков примера приложения ParallelTasks. Длительность задания, показанная здесь, не включает время создания пула, так как каждое задание было отправлено в ранее созданный пул, вычислительные узлы которых находились в состоянии простоя во время отправки.

Первое выполнение примера приложения показывает, что с одним узлом в пуле и параметром по умолчанию одной задачи на узел длительность задания составляет более 30 минут.

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

Второй запуск образца показывает значительное снижение времени выполнения задания. Это сокращение связано с тем, что пул был настроен с четырьмя задачами на узел, что позволяет выполнять параллельное выполнение задачи почти за четверть времени.

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

Дальнейшие действия