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


Использование задач с несколькими экземплярами для запуска приложений с интерфейсом передачи сообщений в пакетной службе

Многоэкземплярные задачи позволяют выполнять задачи пакетной службы Azure на нескольких вычислительных узлах одновременно. Эти задачи реализуют в пакетной службе такие сценарии высокопроизводительных вычислений, как приложения интерфейса передачи сообщений (MPI). Из этой статьи вы узнаете, как выполнять многоэкземплярные задачи с помощью библиотеки Batch .NET.

Примечание.

Примеры в этой статье посвящены вычислительным узлам Batch .NET, MS-MPI и Windows. Рассматриваемые здесь принципы выполнения многоэкземплярных задач применимы для других платформ и технологий (Python и Intel MPI на узлах Linux, например).

Общие сведения о задаче с несколькими экземплярами

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

Диаграмма, показывающая обзор настроек нескольких экземпляров.

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

  1. Служба Batch создает один основной и несколько подзадач на основе настроек многопоточности. Общее число задач (основной задачи и всех подзадач) соответствует количеству экземпляров (вычислительных узлов), указанному в настройках многопользовательского использования.
  2. Пакетная служба назначает один из вычислительных узлов главным и планирует выполнение основной задачи на нем. Выполнение подзадач она планирует на остальных вычислительных узлах, выделенных для многоэкземплярной задачи, размещая по одной подзадаче на каждом узле.
  3. Основная задача и все подзадачи загружают общие файлы ресурсов, которые вы указываете в настройках многозадачности.
  4. После загрузки общих файлов ресурсов основные и дополнительные задачи выполняют команду координации, указанную в настройках для множественных экземпляров. Команда координации обычно используется для подготовки узлов к выполнению задачи. Подготовка может включать запуск фоновых служб (таких как Microsoft MPIsmpd.exe) и проверку готовности узлов к обработке сообщений, передаваемых между узлами.
  5. После того, как основная задача и все подзадачи успешно выполнят команду координации, основная задача выполнит команду приложения на главном узле. Команда приложения — это командная строка самой многоэкземплярной задачи, и выполняется она только основной задачей. В решении на основе MS-MPI именно здесь вы выполняете свое приложение с поддержкой MPI, используя mpiexec.exe.

Примечание.

Хотя задача с несколькими экземплярами по функциональности отличается от остальных задач, она не относится к типу таких уникальных задач, как StartTask или JobPreparationTask. Задача с несколькими экземплярами — это всего лишь стандартная пакетная задача (CloudTask в Batch .NET) с настроенными параметрами нескольких экземпляров. В этой статье это называется многоэкземплярной задачей.

Требования к задачам с несколькими инстанциями

При выполнении многоэкземплярной задачи требуется, чтобы в пуле был включен обмен данными между узлами и отключено параллельное выполнение задач. Чтобы отключить параллельное выполнение задач, задайте для свойства CloudPool.TaskSlotsPerNode значение 1.

Примечание.

Батч ограничивает размер пула, для которого включен обмен данными между узлами.

В этом фрагменте кода показано, как создать пул для многоэкземплярных задач, используя библиотеку 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;

Примечание.

Если вы пытаетесь запустить многоэкземплярную задачу в пуле с отключённой связью между узлами или с параметром taskSlotsPerNode больше 1, задача никогда не будет запланирована и останется в состоянии "Активно" на неопределённый срок.

Пулы с включенной функцией InterComputeNodeCommunication не позволяют автоматически отменять подготовку узла.

Установка MPI с помощью StartTask

Для выполнения приложений MPI с многоэкземплярной задачей на вычислительных узлах в пуле сначала необходимо установить реализацию MPI (например, MS-MPI или Intel MPI). Это хорошая возможность воспользоваться задачей StartTask, которая выполняется каждый раз при присоединении узла к пулу или его перезапуске. В этом фрагменте кода создается задача StartTask, указывающая пакет установки MS-MPI в качестве файла ресурсов. Командная строка команды начальной задачи выполняется после загрузки файла ресурсов на вычислительный узел. В этом случае командная строка выполняет автоматическую установку 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();

Удаленный доступ к памяти (RDMA)

Если для вычислительных узлов пула пакетной обработки выбран размер с поддержкой RDMA, например А9, то ваше MPI-приложение может воспользоваться преимуществами высокопроизводительной сети RDMA Azure с удаленным доступом к памяти и низкими задержками.

Найдите размеры, помеченные как "С поддержкой доступа RDMA" в Размеры виртуальных машин в Azure (для пулов VirtualMachineConfiguration) или Размеры для облачных служб (для пулов CloudServicesConfiguration).

Примечание.

Чтобы воспользоваться преимуществами RDMA на вычислительных узлах Linux, на узлах необходимо использовать Intel MPI.

Создать задачу с несколькими экземплярами с помощью Batch .NET

Теперь после рассмотрения требований к пулу и установки пакета MPI самое время перейти к созданию задачи с несколькими экземплярами. В этом фрагменте кода мы создадим стандартную задачу CloudTask, а затем настроим ее свойство MultiInstanceSettings. Как упоминалось ранее, многоинстансовая задача не является отдельным типом задач, а представляет собой стандартную пакетную задачу, настроенную с параметрами для множества экземпляров.

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

Основная задача и подзадачи

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

Этим задачам назначается целочисленный идентификатор в диапазоне от 0 до numberOfInstances – 1. Задача с идентификатором 0 — это основная задача, а все остальные идентификаторы назначаются подзадачам. Например, при создании следующих параметров нескольких экземпляров для задачи основная задача будет иметь идентификатор 0, а подзадачи — в диапазоне от 1 до 9.

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

Главный узел

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

команду координации

Команду координации выполняют основная задача и подзадачи.

Вызов команды координации блокируется: пакетная служба не выполнит команду приложения, пока команда координации не будет успешно возвращена для всех подзадач. ** Команда координации должна запустить все необходимые фоновые службы, убедиться, что они готовы к использованию, а затем завершить работу. К примеру, эта команда координации для решения с использованием MS-MPI версии 7 запускает службу SMPD на узле, а затем завершает работу:

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

Обратите внимание, что в этой команде координации используется start . Это необходимо, так как приложение smpd.exe не возвращается сразу после выполнения. Если не использовать команду start, то команда координации не возвращается и выполнение команды приложения блокируется.

Команда приложения

Если основная задача и все подзадачи выполнили команду координации, командную строку многоэкземплярной задачи выполняет толькоосновная задача. Назовем эту командную строку командой приложения , чтобы отличать ее от команды координации.

Для приложений MS-MPI используйте команду приложения, чтобы выполнить приложение с поддержкой MPI с использованием mpiexec.exe. В качестве примера ниже приведена команда приложения для решения с использованием MS-MPI версии 7:

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

Примечание.

Так как команда mpiexec.exe приложений MS-MPI использует переменную CCP_NODES по умолчанию (см. раздел Переменные среды), в примере командной строки приложения выше она исключена.

Переменные среды

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

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

  • 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

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

Совет

Пример кода Batch Linux MPI содержит пример использования некоторых из этих переменных среды.

Файлы ресурсов

Для многоэкземплярных задач есть два набора файлов ресурсов: общие файлы ресурсов, которые скачивают все задачи (основная задача и подзадачи), и файлы ресурсов, указанные непосредственно для многоэкземплярной задачи, которые скачивает только основная задача.

В параметрах для задачи с множественными экземплярами можно указать один или несколько общих файлов ресурсов . Основная задача и все подзадачи скачивают эти общие файлы ресурсов из службы хранилища Azure в общий каталог задач каждого узла. Доступ к общему каталогу задач можно получить из командных строк приложения и координации с помощью переменной среды AZ_BATCH_TASK_SHARED_DIR. Пути AZ_BATCH_TASK_SHARED_DIR идентичны для каждого узла, выделенного многоэкземплярной задаче, поэтому можно использовать общую команду координации для основной задачи и всех подзадач. Пакетная служба не предоставляет общий доступ к каталогу в смысле удаленного доступа, но его можно использовать как точку монтирования или общий ресурс, как уже упоминалось ранее в совете по переменным среды.

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

Внимание

Для создания ссылок на эти каталоги в командной строке всегда используйте переменные среды AZ_BATCH_TASK_SHARED_DIR и AZ_BATCH_TASK_WORKING_DIR. Не пытайтесь создать пути вручную.

Срок действия задачи

Жизненный цикл основной задачи определяет продолжительность всей многоэкземплярной задачи. При завершении главной задачи все подзадачи завершаются. Код завершения основного процесса является кодом завершения задачи и используется для определения успешности или неуспешности задачи в целях повторной попытки.

Если любая из подзадач завершается неудачно, например, из-за выхода с ненулевым кодом возврата, то происходит сбой всей задачи, состоящей из нескольких экземпляров. Затем задача с несколькими экземплярами завершается и выполняется повторно, пока не будет достигнут лимит повторных попыток.

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

Свойства TaskConstraints для задачи с несколькими экземплярами, такие как MaxTaskRetryCount, MaxWallClockTime, и RetentionTime, соблюдаются так же, как и для стандартной задачи, и применяются к основной и всем подзадачам. Однако при изменении свойства RetentionTime после добавления задачи с несколькими экземплярами в задание это изменение будет применено только к основной задаче, а все подзадачи продолжат использовать исходное значение RetentionTime.

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

Получение сведений о подзадачах

Чтобы получить сведения о подзадачах, воспользуйтесь методом CloudTask.ListSubtasks библиотеки пакетной службы .NET. Этот метод возвращает сведения о всех подзадачах и вычислительном узле, на котором выполняются задачи. Руководствуясь полученной информацией, можно определить корневой каталог каждой подзадачи, идентификатор пула, его текущее состояние, код выхода и многое другое. Эти сведения можно использовать в сочетании с методом PoolOperations.GetNodeFile, чтобы получить файлы подзадачи. Обратите внимание, что этот метод не возвращает сведения для основной задачи (идентификатор — 0).

Примечание.

Если не указано иное, методы Batch .NET, используемые в многозадачной системе CloudTask, применяются только к основной задаче. Например, при вызове метода CloudTask.ListNodeFiles для задачи с несколькими экземплярами возвращаются только файлы основной задачи.

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

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

Пример кода

В примере кода MultiInstanceTasks на GitHub демонстрируется использование задачи с несколькими экземплярами для запуска приложения MS-MPI на вычислительных узлах службы Batch. Чтобы запустить пример кода, выполните указанные ниже действия.

Подготовка

  1. Скачайте установщики пакета SDK для MS-MPI и Redist и установите их. После установки можно проверить, настроены ли переменные среды MS-MPI.
  2. Создайте релизную сборку программы-примера MPI MPIHelloWorld. Это программа, которую будет выполнять на вычислительных узлах задача с несколькими экземплярами.
  3. Создайте ZIP-файл, содержащий файл MPIHelloWorld.exe (созданный на шаге 2) и MSMpiSetup.exe (скачанный на шаге 1). Вы отправите этот ZIP-файл как пакет приложения на следующем шаге.
  4. Используйте портал Azure для создания приложения пакетной службы с именем "MPIHelloWorld" и укажите ZIP-файл, созданный на предыдущем шаге, в качестве версии 1.0 пакета приложения. Дополнительные сведения см. в разделе Передача приложений и управление ими.

Совет

Создание версии Release для MPIHelloWorld.exe обеспечивает отсутствие необходимости включать любые дополнительные зависимости (например, msvcp140d.dll или vcruntime140d.dll) в пакет вашего приложения.

Выполнение

  1. Скачайте файл ZIP-файл azure-batch-samples с GitHub.

  2. Откройте решение MultiInstanceTasks в Visual Studio 2019. Файл решения MultiInstanceTasks.sln находится в следующем расположении:

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

  3. Введите данные своей учетной записи пакетной службы и учетной записи хранения в AccountSettings.settings для проекта Microsoft.Azure.Batch.Samples.Common.

  4. Создайте и запустите решение MultiInstanceTasks, чтобы выполнить пример приложения MPI на вычислительных узлах в пуле пакетной службы.

  5. Необязательно. Используйте портал Azure или Batch Explorer, чтобы проверить пример пула, задания и задачи ("MultiInstanceSamplePool", "MultiInstanceSampleJob", "MultiInstanceSampleTask"), а затем удалить ресурсы.

Совет

Вы можете скачать Visual Studio Community бесплатно, если у вас нет Visual Studio.

Результат MultiInstanceTasks.exe аналогичен приведенному ниже:

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

Следующие шаги