Partilhar via


Executar tarefas em simultâneo para maximizar a utilização de nós de computação do Batch

Pode maximizar a utilização de recursos num número menor de nós de computação no conjunto ao executar mais do que uma tarefa em simultâneo em cada nó.

Embora alguns cenários funcionem melhor com todos os recursos de um nó dedicados a uma única tarefa, determinadas cargas de trabalho podem ver tempos de trabalho mais curtos e custos mais baixos quando várias tarefas partilham esses recursos. Pondere os seguintes cenários:

  • Minimizar a transferência de dados para tarefas que podem partilhar dados. Pode reduzir significativamente os custos de transferência de dados ao copiar dados partilhados para um número menor de nós e, em seguida, executar tarefas em paralelo em cada nó. Esta estratégia aplica-se especialmente se os dados a serem copiados para cada nó têm de ser transferidos entre regiões geográficas.
  • Maximize a utilização da memória para tarefas que requerem uma grande quantidade de memória, mas apenas durante curtos períodos de tempo e em horas variáveis durante a execução. Pode utilizar menos nós de computação, mas maiores, com mais memória para lidar com esses picos de forma eficiente. Estes nós têm várias tarefas em execução em paralelo em cada nó, mas cada tarefa pode tirar partido da memória abundante dos nós em momentos diferentes.
  • Mitigar limites de números de nós quando a comunicação entre nós é necessária num conjunto. Atualmente, os conjuntos configurados para comunicação entre nós estão limitados a 50 nós de computação. Se cada nó nesse conjunto conseguir executar tarefas em paralelo, um maior número de tarefas pode ser executado em simultâneo.
  • Replique um cluster de cálculo no local, como quando move pela primeira vez um ambiente de computação para o Azure. Se a sua solução no local atual executar várias tarefas por nó de computação, pode aumentar o número máximo de tarefas de nós para espelhar mais atentamente essa configuração.

Cenário de exemplo

Por exemplo, imagine uma aplicação de tarefas com requisitos de CPU e memória para que Standard_D1 nós sejam suficientes. No entanto, para concluir a tarefa no tempo necessário, são necessários 1000 destes nós.

Em vez de utilizar Standard_D1 nós com um núcleo de CPU, pode utilizar Standard_D14 nós com 16 núcleos cada e ativar a execução de tarefas paralelas. Poderia potencialmente utilizar 16 vezes menos nós em vez de 1000 nós, apenas 63 seriam necessários. Se forem necessários ficheiros de aplicação grandes ou dados de referência para cada nó, a duração e a eficiência da tarefa são melhoradas, uma vez que os dados são copiados para apenas 63 nós.

Ativar a execução de tarefas paralelas

Pode configurar nós de computação para execução de tarefas paralelas ao nível do conjunto. Com a biblioteca .NET do Batch, defina a propriedade CloudPool.TaskSlotsPerNode quando criar um conjunto. Se estiver a utilizar a API REST do Batch, defina o elemento taskSlotsPerNode no corpo do pedido durante a criação do conjunto.

Nota

Pode definir o elemento e a taskSlotsPerNode propriedade TaskSlotsPerNode apenas no momento da criação do conjunto. Não podem ser modificados depois de um conjunto já ter sido criado.

Azure Batch permite-lhe definir blocos de tarefas por nó até (4x) o número de núcleos de nó. Por exemplo, se o conjunto estiver configurado com nós de tamanho "Grande" (quatro núcleos), taskSlotsPerNode poderá ser definido como 16. No entanto, independentemente do número de núcleos que o nó tem, não pode ter mais de 256 blocos de tarefas por nó. Para obter detalhes sobre o número de núcleos para cada um dos tamanhos de nó, veja Tamanhos para Serviços Cloud (clássico). Para obter mais informações sobre os limites de serviço, veja Quotas e limites do serviço Batch.

Dica

Certifique-se de que tem em conta o taskSlotsPerNode valor ao construir uma fórmula de dimensionamento automático para o conjunto. Por exemplo, uma fórmula avaliada $RunningTasks pode ser afetada significativamente por um aumento de tarefas por nó. Para obter mais informações, veja Criar uma fórmula automática para dimensionar nós de computação num conjunto do Batch.

Especificar a distribuição de tarefas

Ao ativar tarefas simultâneas, é importante especificar como pretende que as tarefas sejam distribuídas pelos nós no conjunto.

Ao utilizar a propriedade CloudPool.TaskSchedulingPolicy , pode especificar que as tarefas devem ser atribuídas uniformemente a todos os nós no conjunto ("propagação"). Em alternativa, pode especificar que o maior número possível de tarefas deve ser atribuído a cada nó antes de as tarefas serem atribuídas a outro nó no conjunto ("empacotamento").

Por exemplo, considere o conjunto de Standard_D14 nós (no exemplo anterior) que está configurado com um valor CloudPool.TaskSlotsPerNode de 16. Se o CloudPool.TaskSchedulingPolicy estiver configurado com um ComputeNodeFillType de Pack, maximizará a utilização de todos os 16 núcleos de cada nó e permitirá que um conjunto de dimensionamento automático remova nós não utilizados (nós sem tarefas atribuídas) do conjunto. O dimensionamento automático minimiza a utilização de recursos e pode poupar dinheiro.

Definir blocos variáveis por tarefa

Uma tarefa pode ser definida com a propriedade CloudTask.RequiredSlots , especificando quantos blocos é necessário executar num nó de computação. O valor predefinido é 1. Pode definir blocos de tarefas variáveis se as suas tarefas tiverem pesos diferentes associados à respetiva utilização de recursos no nó de computação. Os blocos de tarefas variáveis permitem que cada nó de computação tenha um número razoável de tarefas em execução simultâneas sem sobrecarregar os recursos do sistema, como a CPU ou a memória.

Por exemplo, para um conjunto com a propriedade taskSlotsPerNode = 8, pode submeter tarefas com utilização intensiva da CPU de vários núcleos com requiredSlots = 8, enquanto outras tarefas podem ser definidas como requiredSlots = 1. Quando esta carga de trabalho mista é agendada, as tarefas com utilização intensiva da CPU são executadas exclusivamente nos nós de computação, enquanto outras tarefas podem ser executadas simultaneamente (até oito tarefas ao mesmo tempo) noutros nós. A carga de trabalho mista ajuda-o a equilibrar a carga de trabalho entre nós de computação e a melhorar a eficiência de utilização de recursos.

Certifique-se de que não especifica uma tarefa requiredSlots para ser maior do que a do taskSlotsPerNodeconjunto ou a tarefa nunca é executada. Atualmente, o Serviço Batch não valida este conflito ao submeter tarefas. Não valida o conflito, porque uma tarefa pode não ter um conjunto vinculado no momento da submissão ou pode ser alterado para um conjunto diferente ao desativar/reativar.

Dica

Ao utilizar blocos de tarefas variáveis, é possível que as tarefas grandes com blocos mais necessários possam falhar temporariamente para serem agendadas porque não existem blocos suficientes disponíveis em qualquer nó de computação, mesmo quando ainda existem blocos inativos em alguns nós. Pode aumentar a prioridade do trabalho para estas tarefas para aumentar a possibilidade de competir por blocos disponíveis nos nós.

O serviço Batch emite o TaskScheduleFailEvent quando não agenda uma tarefa para ser executada e continua a repetir o agendamento até que os blocos necessários fiquem disponíveis. Pode ouvir esse evento para detetar potenciais problemas de agendamento de tarefas e mitigar em conformidade.

Exemplo de .NET do Batch

Os seguintes fragmentos de código da API .NET do Batch mostram como criar um conjunto com vários blocos de tarefas por nó e como submeter uma tarefa com blocos necessários.

Criar um conjunto com vários blocos de tarefas por nó

Este fragmento de código mostra um pedido para criar um conjunto que contém quatro nós, com quatro blocos de tarefas permitidos por nó. Especifica uma política de agendamento de tarefas que preenche cada nó com tarefas antes de atribuir tarefas a outro nó no conjunto.

Para obter mais informações sobre como adicionar conjuntos com a API .NET do Batch, veja 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();

Criar uma tarefa com blocos necessários

Este fragmento de código cria uma tarefa sem predefinição requiredSlots. Esta tarefa é executada quando existem blocos gratuitos suficientes disponíveis num nó de computação.

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

Listar nós de computação com contagens para executar tarefas e blocos

Este fragmento de código lista todos os nós de computação no conjunto e imprime as contagens para executar tarefas e blocos de tarefas por nó.

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

Listar contagens de tarefas para a tarefa

Este fragmento de código obtém contagens de tarefas para a tarefa, que inclui a contagem de tarefas e de blocos de tarefas por estado da tarefa.

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

Exemplo rest do Batch

Os seguintes fragmentos de código da API REST do Batch mostram como criar um conjunto com vários blocos de tarefas por nó e como submeter uma tarefa com blocos necessários.

Criar um conjunto com vários blocos de tarefas por nó

Este fragmento mostra um pedido para criar um conjunto que contém dois nós grandes com um máximo de quatro tarefas por nó.

Para obter mais informações sobre como adicionar conjuntos com a API REST, veja Adicionar um conjunto a uma conta.

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

Criar uma tarefa com blocos necessários

Este fragmento mostra um pedido para adicionar uma tarefa sem predefinição requiredSlots. Esta tarefa só é executada quando existem blocos livres suficientes disponíveis no nó de computação.

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

Exemplo de código no GitHub

O projeto ParallelTasks no GitHub ilustra a utilização da propriedade CloudPool.TaskSlotsPerNode .

Esta aplicação de consola C# utiliza a biblioteca .NET do Batch para criar um conjunto com um ou mais nós de computação. Executa um número configurável de tarefas nesses nós para simular uma carga variável. O resultado da aplicação mostra os nós que executaram cada tarefa. A aplicação também fornece um resumo dos parâmetros e duração da tarefa.

O exemplo seguinte mostra a parte de resumo da saída de duas execuções diferentes da aplicação de exemplo ParallelTasks. As durações das tarefas aqui apresentadas não incluem o tempo de criação do conjunto, uma vez que cada tarefa foi submetida para um conjunto criado anteriormente cujos nós de computação estavam no estado Inativo no momento da submissão.

A primeira execução da aplicação de exemplo mostra que, com um único nó no conjunto e a predefinição de uma tarefa por nó, a duração da tarefa é superior a 30 minutos.

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

A segunda execução do exemplo mostra uma diminuição significativa na duração da tarefa. Esta redução deve-se ao facto de o conjunto ter sido configurado com quatro tarefas por nó, o que permite que a execução de tarefas paralelas conclua a tarefa em quase um quarto do tempo.

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

Passos seguintes