Eseguire attività contemporaneamente per ottimizzare l'uso dei nodi di calcolo Batch

È possibile ottimizzare l'utilizzo delle risorse in un numero inferiore di nodi di calcolo nel pool eseguendo più attività contemporaneamente in ogni nodo.

Anche se alcuni scenari funzionano meglio con tutte le risorse di un nodo dedicate a una singola attività, alcuni carichi di lavoro possono visualizzare tempi di processo più brevi e costi inferiori quando più attività condividono tali risorse. Esaminare gli scenari seguenti:

  • Ridurre al minimo il trasferimento dei dati per le attività in grado di condividere i dati. È possibile ridurre notevolmente i costi di trasferimento dei dati copiando i dati condivisi in un numero inferiore di nodi, quindi eseguendo attività in parallelo in ogni nodo. Questa strategia si applica in particolare se i dati da copiare in ogni nodo devono essere trasferiti tra aree geografiche.
  • Ottimizzare l'utilizzo della memoria per le attività che richiedono una grande quantità di memoria, ma solo durante brevi periodi di tempo e in momenti variabili durante l'esecuzione. È possibile usare un numero minore di istanze dei nodi, ma di dimensioni maggiori e con più memoria per gestire in modo efficiente i picchi. Questi nodi hanno più attività in esecuzione in parallelo in ogni nodo, ma ogni attività può sfruttare la memoria abbondante dei nodi in momenti diversi.
  • Attenuare i limiti dei numeri di nodo quando è necessaria la comunicazione tra nodi all'interno di un pool. Attualmente, per i pool configurati per la comunicazione tra nodi è previsto un limite di 50 nodi di calcolo, quindi, se ogni nodo nel pool può eseguire attività in parallelo, è possibile eseguire simultaneamente un maggior numero di attività.
  • Replicare un cluster di calcolo locale, ad esempio quando si sposta un ambiente di calcolo in Azure per la prima volta. Se la soluzione locale corrente esegue più attività per ogni nodo di calcolo, è possibile aumentare il numero massimo di attività dei nodi per rispecchiare maggiormente tale configurazione.

Scenario di esempio

Si supponga, ad esempio, che un'applicazione di attività con requisiti di CPU e memoria in modo che Standard_D1 nodi siano sufficienti. Tuttavia, per completare il processo nel tempo necessario, sono necessari 1.000 di questi nodi.

Invece di usare Standard_D1 nodi con un core CPU, è possibile usare Standard_D14 nodi con 16 core ciascuno e abilitare l'esecuzione di attività parallele. È possibile usare potenzialmente 16 volte meno nodi invece di 1.000 nodi, sarebbero necessari solo 63 nodi. Se per ogni nodo sono necessari file di applicazioni di grandi dimensioni o dati di riferimento, la durata e l'efficienza del processo vengono migliorate, poiché i dati vengono copiati in soli 63 nodi.

Abilitare l'esecuzione parallela di attività

I nodi di calcolo per l'esecuzione di attività parallele vengono configurati a livello di pool. Con la libreria Batch .NET, impostare la proprietà CloudPool.TaskSlotsPerNode quando si crea un pool. Se si usa l'API REST batch, impostare l'elemento taskSlotsPerNode nel corpo della richiesta durante la creazione del pool.

Nota

È possibile impostare l'elemento e la taskSlotsPerNode proprietà TaskSlotsPerNode solo in fase di creazione del pool. Non possono essere modificati dopo la creazione di un pool.

Azure Batch consente di impostare gli slot di attività per ogni nodo fino a (4x) il numero di core del nodo. Ad esempio, se il pool è configurato con nodi di grandi dimensioni (quattro core), è possibile impostare il valore di taskSlotsPerNode su 16. Tuttavia, indipendentemente dal numero di core del nodo, non è possibile avere più di 256 slot di attività per nodo. Per informazioni dettagliate sul numero di core per ogni dimensione del nodo, vedere Dimensioni per Servizi cloud (versione classica). Per altre informazioni sui limiti del servizio, vedere Quote e limiti del servizio Batch.

Suggerimento

Verificare di tener conto del valore taskSlotsPerNode durante la creazione di una formula di scalabilità automatica per il pool. Ad esempio, l'impatto di un aumento delle attività per nodo può influire in modo significativo su una formula che valuta $RunningTasks . Per altre informazioni, vedere Creare una formula automatica per ridimensionare i nodi di calcolo in un pool di Batch.

Specificare la distribuzione delle attività

Quando si abilitano le attività simultanee, è importante specificare la modalità di distribuzione delle attività tra i nodi del pool.

La proprietà CloudPool.TaskSchedulingPolicy consente di specificare che le attività vengano assegnate in modo uniforme in tutti i nodi del pool ("distribuzione"). In alternativa, è possibile specificare che più attività possibili vengano assegnate a ciascun nodo prima di essere assegnate a un altro nodo del pool ("imballaggio").

Si consideri ad esempio il pool di nodi Standard_D14 (nell'esempio precedente) configurato con un valore CloudPool.TaskSlotsPerNode pari a 16. Se CloudPool.TaskSchedulingPolicy è configurato con un ComputeNodeFillType di Pack, ottimizza l'utilizzo di tutti i 16 core di ogni nodo e consente a un pool di scalabilità automatica di rimuovere nodi inutilizzati (nodi senza attività assegnate) dal pool. La scalabilità automatica riduce al minimo l'utilizzo delle risorse e consente di risparmiare denaro.

Definire gli slot delle variabili per ogni attività

Un'attività può essere definita con la proprietà CloudTask.RequiredSlots , specificando il numero di slot necessari per l'esecuzione in un nodo di calcolo. Il valore predefinito è 1. È possibile impostare slot di attività variabili se le attività hanno pesi diversi associati all'utilizzo delle risorse nel nodo di calcolo. Gli slot di attività variabili consentono a ogni nodo di calcolo di avere un numero ragionevole di attività in esecuzione simultanee senza sovraccaricare risorse di sistema come CPU o memoria.

Ad esempio, per un pool con la proprietà taskSlotsPerNode = 8, è possibile inviare attività a elevato utilizzo di CPU necessarie a più core con requiredSlots = 8, mentre altre attività possono essere impostate su requiredSlots = 1. Quando questo carico di lavoro misto è pianificato, le attività a elevato utilizzo di CPU vengono eseguite esclusivamente sui nodi di calcolo, mentre altre attività possono essere eseguite simultaneamente (fino a otto attività contemporaneamente) in altri nodi. Il carico di lavoro misto consente di bilanciare il carico di lavoro tra nodi di calcolo e migliorare l'efficienza dell'utilizzo delle risorse.

Assicurarsi di non specificare che un'attività requiredSlots sia maggiore di quella del taskSlotsPerNodepool o che l'attività non venga mai eseguita. Il servizio Batch non convalida attualmente questo conflitto quando si inviano attività. Non convalida il conflitto, perché un processo potrebbe non avere un pool associato al momento dell'invio oppure può passare a un pool diverso disabilitando/riabilitando.

Suggerimento

Quando si usano slot di attività variabili, è possibile che le attività di grandi dimensioni con slot più necessari non vengano pianificate temporaneamente perché non sono disponibili slot sufficienti in qualsiasi nodo di calcolo, anche quando sono ancora presenti slot inattive in alcuni nodi. È possibile aumentare la priorità del processo per queste attività per aumentare la possibilità di competere per gli slot disponibili nei nodi.

Il servizio Batch genera TaskScheduleFailEvent quando non riesce a pianificare un'attività per l'esecuzione e continua a ripetere la pianificazione fino a quando non diventano disponibili gli slot necessari. È possibile restare in ascolto di tale evento per rilevare potenziali problemi di pianificazione delle attività e attenuare di conseguenza.

Esempio per Batch .NET

I frammenti di codice dell'API Batch .NET seguenti illustrano come creare un pool con più slot di attività per nodo e come inviare un'attività con gli slot necessari.

Creare un pool con più slot attività per nodo

Questo frammento di codice mostra una richiesta di creazione di un pool contenente quattro nodi, con quattro slot di attività consentiti per ogni nodo. Specifica un criterio di pianificazione delle attività che riempie ogni nodo con attività prima di assegnare attività a un altro nodo del pool.

Per altre informazioni sull'aggiunta di pool con l'API Batch .NET, vedere 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();

Creare un'attività con gli slot necessari

Questo frammento di codice crea un'attività con un valore non predefinito requiredSlots. Questa attività viene eseguita quando sono disponibili slot liberi sufficienti in un nodo di calcolo.

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

Elencare i nodi di calcolo con conteggi per l'esecuzione di attività e slot

Questo frammento di codice elenca tutti i nodi di calcolo nel pool e stampa i conteggi per l'esecuzione di attività e slot di attività per nodo.

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

Elencare i conteggi delle attività per il processo

Questo frammento di codice ottiene i conteggi delle attività per il processo, che include sia le attività che il numero di slot di attività per stato dell'attività.

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

Esempio per Batch REST

I frammenti di codice dell'API REST batch seguenti illustrano come creare un pool con più slot di attività per nodo e come inviare un'attività con gli slot necessari.

Creare un pool con più slot attività per nodo

Questo frammento di codice mostra una richiesta di creazione di un pool contenente due nodi di grandi dimensioni con un massimo di quattro attività per nodo.

Per altre informazioni sull'aggiunta di pool con l'API REST, vedere Aggiungere un pool a un account.

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

Creare un'attività con gli slot necessari

Questo frammento di codice mostra una richiesta di aggiunta di un'attività con un valore non predefinito requiredSlots. Questa attività viene eseguita solo quando nel nodo di calcolo sono disponibili slot gratuiti sufficienti.

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

Esempio di codice in GitHub

Il progetto ParallelTasks in GitHub illustra l'uso della proprietà CloudPool.TaskSlotsPerNode .

Questa applicazione console C# usa la libreria Batch .NET per creare un pool con uno o più nodi di calcolo. Esegue un numero configurabile di attività in tali nodi per simulare un carico variabile. L'output dell'applicazione mostra quali nodi hanno eseguito ogni attività. L'applicazione fornisce inoltre un riepilogo dei parametri e della durata del processo.

Nell'esempio seguente viene illustrata la parte di riepilogo dell'output di due esecuzioni diverse dell'applicazione di esempio ParallelTasks. Le durate dei processi mostrate qui non includono il tempo di creazione del pool, poiché ogni processo è stato inviato a un pool creato in precedenza i cui nodi di calcolo erano nello stato inattivo al momento dell'invio.

La prima esecuzione dell'applicazione di esempio mostra che con un singolo nodo nel pool e con l'impostazione predefinita di un'attività per nodo, la durata del processo è superiore a 30 minuti.

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

La seconda esecuzione dell'esempio illustra una diminuzione significativa nella durata del processo. Questa riduzione è dovuta al fatto che il pool è stato configurato con quattro attività per nodo, consentendo l'esecuzione di attività parallele per completare il processo in quasi un quarto del tempo.

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

Passaggi successivi