Batch プール内の計算ノードを自動的にスケーリングする数式を作成する

Azure Batch では定義したパラメーターに基づいてプールが自動的にスケールされるため、時間とコストを節約できます。 自動スケーリングにより、Batch ではタスクの需要が増えるとノードが動的にプールに追加され、タスクの需要が減ると計算ノードが削除されます。

計算ノードのプールで自動スケーリングを有効にするには、定義した自動スケーリングの数式をプールに関連付けます。 Batch サービスでは、自動スケーリングの数式を使用して、ワークロードを実行するために必要なノードの数が決定されます。 これらのノードは、専用ノードまたは Azure スポット ノードのいずれかです。 Batch は、サービス メトリック データを定期的に確認し、それを使用して、式に基づいて定義した間隔でプール内のノード数を調整します。

自動スケーリングは、プールの作成時に有効にするか、既存のプールに適用できます。 Batch を使用すると、数式をプールに割り当てる前に数式の評価を行うことができるほか、自動スケーリングの実行状態を監視することができます。 自動スケーリングによってプールを構成すると、後で数式に変更を加えることができます。

重要

Batch アカウントを作成する際に、プール割り当てモードを指定できます。これにより、プールが Batch Service サブスクリプションに割り当てられる (既定) か、ユーザー サブスクリプションに割り当てられるかを決定します。 Batch Service の既定の構成で Batch アカウントを作成した場合、アカウントは処理に使用できるコアの最大数に制限されます。 そのコア数が、Batch サービスでスケール可能な計算ノードの最大数になります。 このため、自動スケーリングの数式によって指定された計算ノードの目標数に Batch サービスが到達しない場合があります。 アカウント クォータを表示して増やす方法については、Azure Batch サービスのクォータと制限に関する記事を参照してください。

ユーザー サブスクリプション モードでアカウントを作成した場合、アカウントはそのサブスクリプションのコア クォータで共有します。 詳細については、「Azure サブスクリプションとサービスの制限、クォータ、制約」の「Virtual Machines の制限」をご覧ください。

自動スケーリングの数式

自動スケーリングの数式は、ユーザーが定義する文字列値であり、1 つまたは複数のステートメントが含まれています。 自動スケーリングの数式は、プールの autoScaleFormula 要素 (Batch REST) または CloudPool.AutoScaleFormula プロパティ (Batch .NET) に割り当てられます。 Batch サービスは、定義された数式を使用して、次の処理期間中のプール内の計算ノードの目標数を決定します。 この数式は 8 KB 以下の文字列で、最大 100 個のステートメントをセミコロンで区切って指定できます。また、改行やコメントを使用することもできます。

自動スケーリングの数式は、Batch 自動スケーリング "言語" と考えることができます。数式は自由形式のステートメントになっていて、Batch サービスによって定義されるサービス定義変数と、ユーザー定義変数の両方を含めることができます。 数式では、組み込みの型、演算子、関数を使用して、これらの値に対する各種の操作を実行できます。 たとえば、ステートメントは次の形式を使用する場合があります。

$myNewVariable = function($ServiceDefinedVariable, $myCustomVariable);

一般に、数式には複数のステートメントが存在し、先行するステートメントで取得された値に対してさまざまな操作が実行されます。 たとえば、まず variable1 の値を取得して、それを関数に渡して variable2 に代入します。

$variable1 = function1($ServiceDefinedVariable);
$variable2 = function2($OtherServiceDefinedVariable, $variable1);

計算ノードが目標の数に到達するように、自動スケールの数式にこれらのステートメントを含めます。 専用ノードとスポット ノードにはそれぞれ独自のターゲット設定があります。 自動スケールの数式には、専用ノード、スポット ノード、またはその両方に対して目標値を含めることができます。

ノードの目標数は、プール内のその種類のノードの現在の数より多くなることも、少なくなることも、同じになることもあります。 プールの自動スケーリングの数式は、Batch によって特定の自動スケーリング間隔で評価されます。 Batch はプール内の各種類のノードの目標数を、自動スケールの数式の評価時に割り出されたノード数と一致するように調整します。

自動スケールの数式の例

次の例で、ほとんどのシナリオで機能するように調整できる自動スケーリングの数式を 2 つ示します。 必要に応じて、例の式の startingNumberOfVMs 変数と maxNumberofVMs 変数を調整できます。

保留中のタスク

この自動スケールの数式では、プールは最初は 1 つの VM で作成されます。 $PendingTasks メトリックにより、実行中またはキューに置かれているタスクの数が定義されます。 この数式により、最後の 180 秒間の保留タスク平均数が判明し、$TargetDedicatedNodes 変数が適宜設定されます。 この数式により、専用ノードの目標数が 25 台の VM を超えることはありません。 新しいタスクが送信されると、プールは自動的に拡大します。 タスクが完了すると、VM が解放され、自動スケーリングの数式によってプールが縮小します。

この数式は専用ノードをスケーリングしますが、スポット ノードのスケールにも適用されるように変更できます。

startingNumberOfVMs = 1;
maxNumberofVMs = 25;
pendingTaskSamplePercent = $PendingTasks.GetSamplePercent(180 * TimeInterval_Second);
pendingTaskSamples = pendingTaskSamplePercent < 70 ? startingNumberOfVMs : avg($PendingTasks.GetSample(180 * TimeInterval_Second));
$TargetDedicatedNodes=min(maxNumberofVMs, pendingTaskSamples);
$NodeDeallocationOption = taskcompletion;

重要

現在、Batch サービスには、保留中のタスクの解決に関する制限があります。 タスクがジョブに追加されると、Batch サービスがスケジュールのために使用する内部キューにもタスクが追加されます。 タスクのスケジュール前にタスクが削除された場合、タスクはキュー内に保持され、$PendingTasks にカウントされる可能性があります。 Batch がキューからタスクをプルして Batch プール内のアイドル状態のノードでスケジュールすると、この削除されたタスクは最終的にキューからクリアされます。

Preempted Node (割り込まれたノード)

この例では、25 個のスポット ノードから始まるプールを作成します。 スポット ノードは、割り込まれるたびに専用のノードに置き換えられます。 最初の例と同様に、maxNumberofVMs 変数は、プールが 25 台の VM を超過することを防ぎます。 この例は、スポット VM を活用しながら、プールの有効期間中、プリエンプションを一定数に抑えるようにする場合に役立ちます。

maxNumberofVMs = 25;
$TargetDedicatedNodes = min(maxNumberofVMs, $PreemptedNodeCount.GetSample(180 * TimeInterval_Second));
$TargetLowPriorityNodes = min(maxNumberofVMs , maxNumberofVMs - $TargetDedicatedNodes);
$NodeDeallocationOption = taskcompletion;

この記事の後半で、自動スケーリングの数式を作成する方法の詳細について説明し、追加の自動スケーリングの数式の例を確認します。

変数

自動スケールの数式には、サービス定義の変数とユーザー定義の変数の両方を使用できます。

サービス定義の変数は Batch サービスに組み込まれています。 サービス定義の変数には、読み取り/書き込み可能な変数と読み取り専用の変数があります。

ユーザー定義の変数は、ユーザーが定義する変数です。 上の例では、$TargetDedicatedNodes$PendingTasks はサービス定義変数であり、startingNumberOfVMsmaxNumberofVMs はユーザー定義変数です。

Note

サービス定義の変数は、常にドル記号 ($) が前に付きます。 ユーザー定義の変数では、ドル記号は省略可能です。

次の表に、Batch サービスで定義されている読み取り/書き込み変数と読み取り専用変数を示します。

読み取り/書き込み可能なサービス定義変数

これらのサービス定義の変数の値を取得および設定することで、プール内の計算ノードの数を管理できます。

変数 説明
$TargetDedicatedNodes プールの専用計算ノードの目標数。 プールが目的の数のノードに常に到達するとは限らないため、目標として指定されます。 たとえば、自動スケーリング評価によって専用ノードの目標数がプールが最初に設定された目標に達する前に変更された場合、そのプールは目標に到達しない可能性があります。

Batch サービス モードで作成されたアカウント内のプールの目標が Batch アカウント ノードまたはコア クォータを超える場合、その目標に到達しない可能性があります。 ユーザー サブスクリプション モードで作成されたアカウント内のプールの目標がそのサブスクリプションの共有コア クォータを超える場合、その目標に到達しない可能性があります。
$TargetLowPriorityNodes プールのスポット計算ノードの目標数。 プールが目的の数のノードに常に到達するとは限らないため、目標として指定されます。 たとえば、プールが最初に設定された目標に達する前に、自動スケーリング評価によってスポット ノードの目標数が変更された場合、そのプールは目標に到達しない可能性があります。 また、目標が Batch アカウント ノードまたはコア クォータを超える場合、プールはその目標に到達しない可能性があります。

スポット計算ノードの詳細については、「Batch でスポット VM を使用する」を参照してください。
$NodeDeallocationOption コンピューティング ノードがプールから削除されるときに発生するアクション。 次のいずれかの値になります。
- requeue: 既定値。 すぐにタスクを終了し、再スケジュールされるようにジョブ キューに戻します。 このアクションにより、可能な限り早くノードの目標数に到達します。 ただし、実行中のタスクはすべて中断され、その後に再開される必要があるため、効率が低下する場合があります。
- terminate: タスクをすぐに終了し、ジョブ キューから削除します。
- taskcompletion: 現在実行中のタスクが完了するまで待機してから、ノードをプールから削除します。 タスクが中断されてキューに再登録されないようにして、タスクで行われた作業が無駄にならないようにするには、このオプションを使用します。
- retaineddata: ノードでローカル タスクによって保持されているすべてのデータがクリーンアップされるまで待機してから、ノードをプールから削除します。

Note

別名 $TargetDedicated を使用して、$TargetDedicatedNodes 変数を指定することもできます。 同様に、別名 $TargetLowPriority を使用して、$TargetLowPriorityNodes 変数を指定できます。 完全な名前の変数とその別名の両方が数式によって設定されている場合は、完全な名前の変数に割り当てられた値が優先されます。

読み取り専用のサービス定義変数

これらのサービス定義変数の値を取得して、Batch サービスのメトリックに基づいて調整できます。

重要

現在、ジョブ解放タスクは、$ActiveTasks$PendingTasks などの、タスク数を提供する変数には含まれていません。 自動スケーリングの数式によっては、このためにノードが削除され、ジョブ解放タスクを実行するためのノードが使用できなくなることがあります。

ヒント

これらの読み取り専用のサービス定義変数は、それぞれに関連付けられたデータにアクセスするさまざまなメソッドを指定するオブジェクトです。 詳しくは、後述の「サンプル データの取得」をご覧ください。

変数 説明
$CPUPercent 平均 CPU 使用率。
$WallClockSeconds 使用された秒数。 2024 年 3 月 31 日以降に廃止。
$MemoryBytes 使用された平均メガバイト数。 2024 年 3 月 31 日以降に廃止。
$DiskBytes ローカル ディスクで使用された平均ギガバイト数。 2024 年 3 月 31 日以降に廃止。
$DiskReadBytes 読み取るバイト数。 2024 年 3 月 31 日以降に廃止。
$DiskWriteBytes 書き込まれたバイト数。 2024 年 3 月 31 日以降に廃止。
$DiskReadOps 実行された読み取りディスク操作の数。 2024 年 3 月 31 日以降に廃止。
$DiskWriteOps 実行された書き込みディスク操作の数。 2024 年 3 月 31 日以降に廃止。
$NetworkInBytes 受信バイト数。 2024 年 3 月 31 日以降に廃止。
$NetworkOutBytes 送信バイト数。 2024 年 3 月 31 日以降に廃止。
$SampleNodeCount 計算ノードの数。 2024 年 3 月 31 日以降に廃止。
$ActiveTasks 実行する準備はできているがまだ実行されていないタスクの数。 これには、アクティブ状態にあり、依存関係が満たされているすべてのタスクが含まれます。 アクティブ状態にあるが、依存関係が満たされていないタスクはすべて $ActiveTasks の数から除外されます。 マルチインスタンス タスクの場合、$ActiveTasks にはタスクに設定されているインスタンスの数が含まれます。
$RunningTasks 実行状態のタスクの数。
$PendingTasks $ActiveTasks$RunningTasks の合計。
$SucceededTasks 正常に完了したタスクの数。
$FailedTasks 失敗したタスクの数。
$TaskSlotsPerNode プール内の単一の計算ノードで同時実行タスクを実行するために使用できるタスク スロットの数。
$CurrentDedicatedNodes 専用コンピューティング ノードの現在の数。
$CurrentLowPriorityNodes スポット計算ノードの現在の数。割り込まれたノードも含まれます。
$UsableNodeCount 使用可能なコンピューティング ノードの数。
$PreemptedNodeCount 割り込み状態にあるプール内のノードの数。

警告

サービス定義変数の選択は、上記の表に示すように、2024 年 3 月 31 日以降に廃止されます。 廃止日以降、これらのサービス定義変数にはサンプル データが設定されなくなります。 この日付より前に、これらの変数の使用を中止してください。

Note

特定の時点で実行されているタスクの数に基づいてスケーリングする場合は $RunningTasks を使用し、実行するためにキューに配置されているタスクの数に基づいてスケーリングする場合は $ActiveTasks を使用します。

自動スケーリングの数式では、次の種類がサポートされています。

  • double
  • doubleVec
  • doubleVecList
  • string
  • timestamp - 次のメンバーを含む複合構造です。
    • month (1 ~ 12)
    • day (1 ~ 31)
    • weekday (数値の形式で表記します。月曜は 1 など)
    • hour (24 時間の数字で表記します。午後 1 時は 13 など)
    • minute (00 ~ 59)
    • second (00 ~ 59)
  • timeinterval
    • TimeInterval_Zero
    • TimeInterval_100ns
    • TimeInterval_Microsecond
    • TimeInterval_Millisecond
    • TimeInterval_Second
    • TimeInterval_Minute
    • TimeInterval_Hour
    • TimeInterval_Day
    • TimeInterval_Week
    • TimeInterval_Year

操作

前のセクションに列挙されている型に対して、次の演算を実行できます。

操作 サポートされている演算子 結果の種類
double <演算子> double +, -, *, / double
double <演算子> timeinterval * timeinterval
doubleVec <演算子> double +、-、*、/ doubleVec
doubleVec <演算子> doubleVec +、-、*、/ doubleVec
timeinterval <演算子> double *、/ timeinterval
timeinterval <演算子> timeinterval +、- timeinterval
timeinterval <演算子> timestamp + timestamp
timestamp <演算子> timeinterval + timestamp
timestamp <演算子> timestamp - timeinterval
演算子 double -、! double
演算子 timeinterval - timeinterval
double <演算子> double <、<=、==、>=、>、!= double
string <演算子> string <、<=、==、>=、>、!= double
timestamp <演算子> timestamp <、<=、==、>=、>、!= double
timeinterval <演算子> timeinterval <、<=、==、>=、>、!= double
double <演算子> double &&, || 倍精度浮動小数点

三項演算子 (double ? statement1 : statement2) を使用して double 型をテストすると、0 以外は true、0 は false になります。

関数

自動スケーリングの数式を定義するときに、これらの定義済みの関数を使用できます。

機能 の戻り値の型 : 説明
avg(doubleVecList) double doubleVecList のすべての値の平均値を返します。
ceil(double) double double 以上で最小の整数値を返します。
ceil(doubleVecList) doubleVec doubleVecList の成分ごとの ceil を返します。
floor(double) double double 以下の最大の整数を返します。
floor(doubleVecList) doubleVec doubleVecList の成分ごとの floor を返します。
len(doubleVecList) double doubleVecList から作成されたベクター長を返します。
lg (double) double 2 を底とする double の対数を返します。
lg(doubleVecList) doubleVec doubleVecList の成分ごとの lg を返します。
ln(double) double double の自然対数を返します。
ln(doubleVecList) doubleVec doubleVecList の成分ごとの ln を返します。
log(double) double 10 を底とする double の対数を返します。
log(doubleVecList) doubleVec doubleVecList の成分ごとの log を返します。
max(doubleVecList) double doubleVecList の最大値を返します。
min(doubleVecList) double doubleVecList の最小値を返します。
norm(doubleVecList) double doubleVecList から作成されたベクトルの 2 ノルムを返します。
percentile(doubleVec v, double p) double ベクトル v の百分位要素を返します。
rand() double 0\.0 ~ 1.0 のランダムな値を返します。
range(doubleVecList) double doubleVecList の最小値と最大値の差を返します。
round(double) double 最も近い整数値を double (浮動小数点形式) で返し、小数点以下の端数を丸めます。
round(doubleVecList) doubleVec doubleVecList の成分ごとの round を返します。
std(doubleVecList) double doubleVecList の値のサンプルの標準偏差を返します。
stop() 自動スケール式の評価を停止します。
sum(doubleVecList) double doubleVecList のすべての成分の合計を返します。
time(string dateTime="") timestamp パラメーターが渡されない場合は現在の時刻のタイムスタンプ、渡された場合は dateTime 文字列のタイムスタンプを返します。 サポートされている dateTime 形式は、W3C-DTF と RFC 1123 です。
val(doubleVec v, double i) double 開始インデックス 0 のベクター v の位置 i にある要素の値を返します。

前の表に示した一部の関数は、リストを引数として受け入れることができます。 コンマ区切りのリストは、doubledoubleVec の任意の組み合わせです。 次に例を示します。

doubleVecList := ( (double | doubleVec)+(, (double | doubleVec) )* )?

doubleVecList 値は、評価の前に 1 つの doubleVec に変換されます。 たとえば、v = [1,2,3] の場合、avg(v) の呼び出しは、avg(1,2,3) の呼び出しに相当します。 avg(v, 7) の呼び出しは、avg(1,2,3,7) の呼び出しに相当します。

メトリック

数式を定義するときは、リソースとタスクの両方のメトリックを使用できます。 プール内の専用ノードの目標数は、収集して評価したメトリック データに基づいて調整します。 各メトリックの詳細については、「変数」セクションを参照してください。

メトリック 説明
リソース リソース メトリックは、計算ノードの CPU、帯域幅、およびメモリの使用状況とノード数に基づくメトリックです。

次のサービス定義の変数は、ノード数に基づいて調整を行う場合に有用です。
- $TargetDedicatedNodes
- $TargetLowPriorityNodes
- $CurrentDedicatedNodes
- $CurrentLowPriorityNodes
- $PreemptedNodeCount
- $UsableNodeCount

次のサービス定義の変数は、ノード リソースの使用状況に基づいて調整を行う場合に有用です。
- $CPUPercent
- $WallClockSeconds
- $MemoryBytes
- $DiskBytes
- $DiskReadBytes
- $DiskWriteBytes
- $DiskReadOps
- $DiskWriteOps
- $NetworkInBytes
- $NetworkOutBytes
タスク タスク メトリックは、タスクの状態 (アクティブ、保留中、完了) に基づくメトリックです。 次のサービス定義の変数は、タスク メトリックに基づいてプールのサイズを調整する場合に有用です。
- $ActiveTasks
- $RunningTasks
- $PendingTasks
- $SucceededTasks
- $FailedTasks

サンプル データの取得

タスクおよびリソースのメトリック データ (サンプル) を取得し、そのデータに基づいてプールのサイズを調整することが、自動スケーリングの数式の主要な動作となります。 そのため、自動スケーリングの数式とサンプルとがどのように関与するのかをしっかりと把握しておくことが重要です。

メソッド

自動スケーリングの数式は、Batch サービスから提供されるメトリック データのサンプルに基づいて作用します。 数式は、与えられる値に基づいてプール計算ノードを拡大または縮小します。 サービス定義変数は、オブジェクトに関連付けられたデータにアクセスするメソッドを提供するオブジェクトです。 たとえば、次の式は、最後の 5 分間の CPU 使用率を取得する要求を示しています。

$CPUPercent.GetSample(TimeInterval_Minute * 5)

次のメソッドは、サービス定義変数に関するサンプル データを取得するために使用できます。

メソッド 説明
GetSample() GetSample() メソッドは、データ サンプルのベクターを返します。

サンプルは、30 秒相当のメトリック データです。 つまり、30 秒ごとにサンプルが取得されます。 ただし、この後も説明しますが、サンプルが収集されるタイミングと、それが数式に使用できるタイミングとの間には遅延があります。 そのため、特定の期間に取得されたすべてのサンプルを数式の評価に使用できない可能性があります。

- doubleVec GetSample(double count): 最新の収集済みサンプルから取得するサンプル数を指定します。 GetSample(1) は、使用できる最新のサンプルを返します。 ただし、$CPUPercent などのメトリックの場合、サンプルが収集された時間がわからないので、GetSample(1) を使用できません。 最新の場合もありますが、システム上の問題が原因でかなり古い可能性があります。 このような場合は、次のように期間を使用することが適切です。

- doubleVec GetSample((timestamp or timeinterval) startTime [, double samplePercent]): サンプル データを収集する期間を指定します。 指定した期間内に必要となるサンプルの割合をオプションで指定できます。 たとえば、$CPUPercent.GetSample(TimeInterval_Minute * 10) は、過去 10 分間のサンプルがすべて CPUPercent 履歴に存在する場合、20 個のサンプルを返します。 過去 1 分間の履歴を使用できない場合は、18 個のサンプルのみが返されます。 この場合、$CPUPercent.GetSample(TimeInterval_Minute * 10, 95) は、サンプルの 90% しか使用できないため、失敗しますが、$CPUPercent.GetSample(TimeInterval_Minute * 10, 80) は成功します。

- doubleVec GetSample((timestamp or timeinterval) startTime, (timestamp or timeinterval) endTime [, double samplePercent]): 開始時刻と終了時刻の両方を使用して、データを収集する期間を指定します。 前述のように、サンプルが収集されるタイミングと、数式に使用できるようになるタイミングとの間には遅延があります。 GetSample メソッドを使用する際にはこの遅延を考慮します。 後述の GetSamplePercent をご覧ください。
GetSamplePeriod() 履歴のサンプル データ セットで受け取ったサンプルの期間を返します。
Count() メトリック履歴のサンプルの合計数を返します。
HistoryBeginTime() 使用可能な最も古いメトリックのデータ サンプルのタイムスタンプを返します。
GetSamplePercent() 特定の時間間隔で利用できるサンプルの割合を返します。 たとえば、「 doubleVec GetSamplePercent( (timestamp or timeinterval) startTime [, (timestamp or timeinterval) endTime] ) 」のように入力します。 返されたサンプルの割合が指定した samplePercent 未満の場合、GetSample メソッドは失敗するので、まず GetSamplePercent メソッドを使用して確認します。 その後、十分なサンプルが存在しない場合は、自動スケール評価を停止せずに代替の操作を実行します。

サンプル

Batch サービスでは、タスクおよびリソースのメトリックのサンプルを定期的に取得し、自動スケールの数式でこのサンプルを使用できるようにします。 これらのサンプルは 30 秒に 1 回、Batch サービスによって記録されます。 ただし通常、サンプルが記録されるタイミングと、それが自動スケールの数式で使用できる (読み取られる) タイミングとの間には、遅延があります。 さらに、ネットワークやその他のインフラストラクチャの問題などの要因により、特定の間隔でサンプルが記録されない場合があります。

サンプルの割合

samplePercentGetSample() メソッドに渡すか、GetSamplePercent() メソッドが呼び出されるときの "割合" とは、Batch サービスによって記録することが可能なサンプルの最大合計数と、自動スケールの数式で使用できるサンプルの数との比を示します。

例として、10 分間の時間枠で説明します。 サンプルは 30 秒ごとに記録されるため、10 分間の期間内に Batch によって記録されるサンプルの最大合計数は 20 サンプルとなります (1 分あたり 2 つ)。 しかし、レポートの機構上必然的に伴う時間差や Azure 内の問題により、自動スケーリングの数式で読み取り可能なサンプル数が 15 にしか到達しない可能性があります。 このため、たとえばこの 10 分間に数式で使用可能なサンプル数は、記録されたサンプルの合計数の 75% に限られるということです。

GetSample() とサンプルの範囲

自動スケーリングの数式は、ノードを追加または削除してプールを拡大および縮小します。 ノードには金銭的コストが伴うため、数式には、十分なデータに基づいたインテリジェントな分析方法を使用してください。 数式に傾向分析を使用することをお勧めします。 収集したサンプルの範囲に基づいて、プールの拡大と縮小を行うことをお勧めします。

そのためには、GetSample(interval look-back start, interval look-back end) を使用して、サンプルのベクターを返します。

$runningTasksSample = $RunningTasks.GetSample(1 * TimeInterval_Minute, 6 * TimeInterval_Minute);

Batch は、上記の行を評価すると、値のベクターとしてサンプルの範囲を返します。 次に例を示します。

$runningTasksSample=[1,1,1,1,1,1,1,1,1,1];

サンプルのベクターを収集したら、min()max()avg() などの関数を使用して、収集した範囲から有意な値を導き出すことができます。

特に慎重に対応するため、特定の期間に使用できるサンプルの割合が特定の値を下回る場合に、数式による評価を強制的に失敗させるように設定できます。 数式による評価を強制的に失敗させるときは、指定したサンプルの割合を使用できない場合に、数式のそれ以上の評価を中止するように Batch に指示します。 この場合、プール サイズの変更は行われません。 評価を成功させるために必要なサンプルの割合を指定するには、その割合を 3 番目のパラメーターとして GetSample() に指定します。 ここで、サンプルの 75% という要件は次のように指定します。

$runningTasksSample = $RunningTasks.GetSample(60 * TimeInterval_Second, 120 * TimeInterval_Second, 75);

サンプルの可用性には遅延が生じる場合があるため、時間範囲を指定する際には、常に、開始時間を 1 分より長くさかのぼって指定する必要があります。 サンプルがシステムを介して伝達されるまで約 1 分かかるため、(0 * TimeInterval_Second, 60 * TimeInterval_Second) の範囲内のサンプルは使用できない場合があります。 ここでも、 GetSample() の割合パラメーターを使用することで、サンプルの割合に関する特定の要件を適用できます。

重要

自動スケールの数式では GetSample(1)のみ依存することは避けることが強く推奨されます。 理由は、GetSample(1) は基本的には "どれほど前に取得したのかに関係なく、最後に取得したサンプルを渡す" よう Batch サービスに指示するためです。それは単一のサンプルであり、また以前のサンプルであるため、最近のタスクまたはリソースの状態を表す情報として十分でない可能性があります。 GetSample(1)を使用する場合は、より大きなステートメントの一部であり、数式が依存する唯一のデータ ポイントになっていないことを確認してください。

自動スケールの数式の記述

自動スケールの数式は、これまでに挙げたさまざまな要素を使ってステートメントを記述し、それらを 1 つの数式として組み合わせることで作成します。 このセクションでは、実際のスケーリングの決定を行い、調整を行うことができる自動スケーリングの数式のサンプルを作成します。

まず、新しい自動スケールの数式の要件を定義します。 数式の要件は次のようになります。

  • CPU 使用率が高い場合、プール内の専用計算ノードの目標数を増やす。
  • CPU 使用率が低い場合、プール内の専用計算ノードの目標数を減らす。
  • 常に専用ノードの最大数を 400 までに制限する。
  • ノードの数を減らすときは、タスクを実行しているノードを削除しないでください。必要な場合は、タスクが完了するまで待ってから、ノードを削除してください。

数式の最初のステートメントは、CPU 使用率が高いときにノード数を増加させます。 過去 10 分間の平均 CPU 使用率の最小値が 70% を超えた場合にのみ、ユーザー定義変数 ($totalDedicatedNodes) を専用ノードの現在の目標数の 110% の値に設定するステートメントを定義します。 それ以外の場合は、専用ノードの現在の数の値を使用します。

$totalDedicatedNodes =
    (min($CPUPercent.GetSample(TimeInterval_Minute * 10)) > 0.7) ?
    ($CurrentDedicatedNodes * 1.1) : $CurrentDedicatedNodes;

CPU 使用率が低いときに専用ノードの数を減らすには、数式の次のステートメントで、過去 60 分間の平均 CPU 使用率が 20% を下回る場合に、同じ $totalDedicatedNodes 変数を専用ノードの現在の目標数の 90% に設定します。 それ以外の場合は、上記のステートメントに入力した $totalDedicatedNodes の現在の値を使用します。

$totalDedicatedNodes =
    (avg($CPUPercent.GetSample(TimeInterval_Minute * 60)) < 0.2) ?
    ($CurrentDedicatedNodes * 0.9) : $totalDedicatedNodes;

ここでは、専用計算ノードの目標数を最大 400 に制限しています。

$TargetDedicatedNodes = min(400, $totalDedicatedNodes);

最後に、タスクが完了するまでノードが削除されないようにします。

$NodeDeallocationOption = taskcompletion;

完全な数式を次に示します。

$totalDedicatedNodes =
    (min($CPUPercent.GetSample(TimeInterval_Minute * 10)) > 0.7) ?
    ($CurrentDedicatedNodes * 1.1) : $CurrentDedicatedNodes;
$totalDedicatedNodes =
    (avg($CPUPercent.GetSample(TimeInterval_Minute * 60)) < 0.2) ?
    ($CurrentDedicatedNodes * 0.9) : $totalDedicatedNodes;
$TargetDedicatedNodes = min(400, $totalDedicatedNodes);
$NodeDeallocationOption = taskcompletion;

Note

これを選択する場合は、数式文字列にコメントと改行の両方を含めることができます。 また、セミコロンがないと、評価エラーが発生する可能性があることにもご注意ください。

自動スケールの間隔

既定では、Batch サービスは自動スケールの数式に従って 15 分ごとにプールのサイズを調整します。 この間隔は、次のプール プロパティを使用して構成できます。

間隔の最小値は 5 分、最大値は 168 時間です。 この範囲外の間隔が指定されると、Batch サービスは「正しくない要求 (400)」エラーを返します。

Note

現行の自動スケール機能は、1 分以内に起こった変化に対応するというよりは、ワークロードを実行する過程でプールのサイズを少しずつ調整することを意図しています。

Batch の SDK で自動スケーリング対応のプールを作成する

プールの自動スケーリングは、Batch の SDKBatch REST APIBatch PowerShell コマンドレット、および Batch CLI を使用して構成できます。 このセクションでは、.NET と Python の両方の例を紹介します。

.NET

.NET で自動スケール対応のプールを作成するには、次の手順を実行します。

  1. BatchClient.PoolOperations.CreatePool でプールを作成します。
  2. CloudPool.AutoScaleEnabled プロパティを true に設定します。
  3. CloudPool.AutoScaleFormula プロパティを自動スケールの数式で設定します。
  4. (省略可能) CloudPool.AutoScaleEvaluationInterval プロパティを設定します (既定では 15 分)。
  5. CloudPool.Commit または CommitAsync で、プールをコミットします。

次の例では、.NET で自動スケーリング対応のプールを作成します。 プールの自動スケーリングの数式によって、専用ノードの目標数を月曜日は 5 に、それ以外の曜日は 1 に設定しています。 自動スケールの間隔は、30 分に設定されます。 次に示す C# スニペットまたはこの記事で示すその他の C# スニペットでは、myBatchClient は適切に初期化された BatchClient クラスのインスタンスです。

CloudPool pool = myBatchClient.PoolOperations.CreatePool(
                    poolId: "mypool",
                    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.AutoScaleEnabled = true;
pool.AutoScaleFormula = "$TargetDedicatedNodes = (time().weekday == 1 ? 5:1);";
pool.AutoScaleEvaluationInterval = TimeSpan.FromMinutes(30);
await pool.CommitAsync();

重要

自動スケーリング対応のプールを作成する際には、CreatePool の呼び出しに targetDedicatedNodes パラメーターや targetLowPriorityNodes パラメーターを指定しないでください。 代わりに、プールの AutoScaleEnabled プロパティと AutoScaleFormula プロパティを指定します。 これらのプロパティの値は各種類のノードの目標数を決定します。

自動スケーリング対応のプールのサイズを手動で変更する場合 (BatchClient.PoolOperations.ResizePoolAsync などによって)、最初にプールで自動スケーリングを無効にしてから、プールのサイズを変更する必要があります。

ヒント

その他の .NET SDK の使用例については、GitHub の Batch .NET クイック スタート リポジトリを参照してください。

Python

自動スケーリング対応のプールを Python SDK で作成するには:

  1. プールを作成してその構成を指定します。
  2. サービス クライアントにプールを追加します。
  3. 作成した数式でプールの自動スケーリングを有効にします。

次の例に、これらの手順を示します。

# Create a pool; specify configuration
new_pool = batch.models.PoolAddParameter(
    id="autoscale-enabled-pool",
    virtual_machine_configuration=batchmodels.VirtualMachineConfiguration(
        image_reference=batchmodels.ImageReference(
          publisher="Canonical",
          offer="UbuntuServer",
          sku="20.04-LTS",
          version="latest"
            ),
        node_agent_sku_id="batch.node.ubuntu 20.04"),
    vm_size="STANDARD_D1_v2",
    target_dedicated_nodes=0,
    target_low_priority_nodes=0
)
batch_service_client.pool.add(new_pool) # Add the pool to the service client

formula = """$curTime = time();
             $workHours = $curTime.hour >= 8 && $curTime.hour < 18;
             $isWeekday = $curTime.weekday >= 1 && $curTime.weekday <= 5;
             $isWorkingWeekdayHour = $workHours && $isWeekday;
             $TargetDedicated = $isWorkingWeekdayHour ? 20:10;""";

# Enable autoscale; specify the formula
response = batch_service_client.pool.enable_auto_scale(pool_id, auto_scale_formula=formula,
                                            auto_scale_evaluation_interval=datetime.timedelta(minutes=10),
                                            pool_enable_auto_scale_options=None,
                                            custom_headers=None, raw=False)

ヒント

その他の Python SDK の使用例については、GitHub の Batch Python クイックスタート リポジトリを参照してください。

既存のプールでの自動スケールの有効化

各 Batch SDK には自動スケーリングを有効にする方法が用意されています。 次に例を示します。

既存のプールで自動スケーリングを有効にする際には、次の点に注意してください。

  • プールで自動スケーリングが現在無効になっている場合、要求の発行時に有効な自動スケーリングの数式を指定する必要があります。 必要に応じて、自動スケーリングの間隔を指定できます。 間隔を指定しない場合、既定値の 15 分が使用されます。
  • プールで自動スケーリングが現在有効になっている場合、新しい数式、新しい間隔、またはその両方を指定できます。 これらのプロパティの 1 つ以上を指定する必要があります。
    • 新しい自動スケーリングの間隔を指定すると、既存のスケジュールが停止し、新しいスケジュールが開始します。 新しいスケジュールの開始時刻は、自動スケールを有効にする要求を発行した時間です。
    • 自動スケールの数式と間隔のいずれかを省略すると、Batch サービスはその設定の現在の値を引き続き使用します。

Note

.NET でプールを作成したときに CreatePool メソッドの targetDedicatedNodes パラメーターと targetLowPriorityNodes パラメーターの値を指定した、または別の言語で同等のパラメーターを指定した場合、自動スケーリングの数式が評価されるときにそれらの値は無視されます。

この C# の例では、Batch .NET ライブラリを使用し、既存のプールで自動スケーリングを有効にします。

// Define the autoscaling formula. This formula sets the target number of nodes
// to 5 on Mondays, and 1 on every other day of the week
string myAutoScaleFormula = "$TargetDedicatedNodes = (time().weekday == 1 ? 5:1);";

// Set the autoscale formula on the existing pool
await myBatchClient.PoolOperations.EnableAutoScaleAsync(
    "myexistingpool",
    autoscaleFormula: myAutoScaleFormula);

自動スケールの数式の更新

既存の自動スケール対応のプールの数式を更新するには、新しい数式で自動スケールを再度有効にする操作を呼び出します。 たとえば、次の .NET コードの実行時に myexistingpool で自動スケールが既に有効になっている場合、自動スケールの数式は、myNewFormula の内容に置き換わります。

await myBatchClient.PoolOperations.EnableAutoScaleAsync(
    "myexistingpool",
    autoscaleFormula: myNewFormula);

自動スケールの間隔の更新

既存の自動スケール対応のプールの自動スケールの評価間隔を更新するには、新しい間隔で自動スケールを再度有効にする操作を呼び出します。 たとえば、既に自動スケールが有効なプールについて、自動スケール評価の間隔を 60 分に設定する場合、次のようになります。

await myBatchClient.PoolOperations.EnableAutoScaleAsync(
    "myexistingpool",
    autoscaleEvaluationInterval: TimeSpan.FromMinutes(60));

自動スケールの数式の評価

プールに適用する前に数式を評価できます。 これにより、数式の結果を運用環境に導入する前にテストできます。

自動スケーリングの数式を評価する前に、まず 1 行の数式 $TargetDedicatedNodes = 0 などの有効な数式を使用して、プールの自動スケーリングを有効にする必要があります。 その後、次のいずれかを使用してテスト対象の数式を評価します。

  • BatchClient.PoolOperations.EvaluateAutoScale または EvaluateAutoScaleAsync

    これらの Batch .NET メソッドでは、既存のプールの ID のほか、評価する自動スケールの数式が含まれた文字列が必要になります。

  • 自動スケールの数式の評価

    この REST API 要求では、URI にプール ID、要求本文の autoScaleFormula 要素に自動スケールの数式を指定します。 操作の応答には、数式に関連する可能性があるすべてのエラー情報が含まれています。

次の Batch .NET の例では、自動スケーリングの数式を評価します。 プールで自動スケーリングがまだ使用されていない場合は、まず自動スケーリングを有効にします。

// First obtain a reference to an existing pool
CloudPool pool = await batchClient.PoolOperations.GetPoolAsync("myExistingPool");

// If autoscaling isn't already enabled on the pool, enable it.
// You can't evaluate an autoscale formula on a non-autoscale-enabled pool.
if (pool.AutoScaleEnabled == false)
{
    // You need a valid autoscale formula to enable autoscaling on the
    // pool. This formula is valid, but won't resize the pool:
    await pool.EnableAutoScaleAsync(
        autoscaleFormula: "$TargetDedicatedNodes = $CurrentDedicatedNodes;",
        autoscaleEvaluationInterval: TimeSpan.FromMinutes(5));

    // Batch limits EnableAutoScaleAsync calls to once every 30 seconds.
    // Because you want to apply our new autoscale formula below if it
    // evaluates successfully, and you *just* enabled autoscaling on
    // this pool, pause here to ensure you pass that threshold.
    Thread.Sleep(TimeSpan.FromSeconds(31));

    // Refresh the properties of the pool so that we've got the
    // latest value for AutoScaleEnabled
    await pool.RefreshAsync();
}

// You must ensure that autoscaling is enabled on the pool prior to
// evaluating a formula
if (pool.AutoScaleEnabled == true)
{
    // The formula to evaluate - adjusts target number of nodes based on
    // day of week and time of day
    string myFormula = @"
        $curTime = time();
        $workHours = $curTime.hour >= 8 && $curTime.hour < 18;
        $isWeekday = $curTime.weekday >= 1 && $curTime.weekday <= 5;
        $isWorkingWeekdayHour = $workHours && $isWeekday;
        $TargetDedicatedNodes = $isWorkingWeekdayHour ? 20:10;
    ";

    // Perform the autoscale formula evaluation. Note that this code does not
    // actually apply the formula to the pool.
    AutoScaleRun eval =
        await batchClient.PoolOperations.EvaluateAutoScaleAsync(pool.Id, myFormula);

    if (eval.Error == null)
    {
        // Evaluation success - print the results of the AutoScaleRun.
        // This will display the values of each variable as evaluated by the
        // autoscale formula.
        Console.WriteLine("AutoScaleRun.Results: " +
            eval.Results.Replace("$", "\n    $"));

        // Apply the formula to the pool since it evaluated successfully
        await batchClient.PoolOperations.EnableAutoScaleAsync(pool.Id, myFormula);
    }
    else
    {
        // Evaluation failed, output the message associated with the error
        Console.WriteLine("AutoScaleRun.Error.Message: " +
            eval.Error.Message);
    }
}

数式が正しく評価されると、このコード スニペットには次のような結果が表示されます。

AutoScaleRun.Results:
    $TargetDedicatedNodes=10;
    $NodeDeallocationOption=requeue;
    $curTime=2016-10-13T19:18:47.805Z;
    $isWeekday=1;
    $isWorkingWeekdayHour=0;
    $workHours=0

自動スケールの実行に関する情報の取得

Batch サービスの自動スケールの数式の評価を定期的に確認することをお勧めします。 これを行うには、プールへの参照を取得 (または更新) してから、最後に行われた自動スケーリングの実行のプロパティを確認します。

Batch .NET の場合、プールで行われた最近の自動スケールの実行に関する情報は、CloudPool.AutoScaleRun プロパティ内のいくつかのプロパティに含まれています。

REST API の場合、プールに関する情報を取得する要求によって、プールに関する情報が返されます。この情報の autoScaleRun プロパティに、最新の自動スケーリングの実行に関する情報が含まれています。

次の C# の例では、Batch .NET ライブラリを使用して、プール myPool の最新の自動スケーリング実行に関する情報を出力します。

await Cloud pool = myBatchClient.PoolOperations.GetPoolAsync("myPool");
Console.WriteLine("Last execution: " + pool.AutoScaleRun.Timestamp);
Console.WriteLine("Result:" + pool.AutoScaleRun.Results.Replace("$", "\n  $"));
Console.WriteLine("Error: " + pool.AutoScaleRun.Error);

前の例からのサンプル出力:

Last execution: 10/14/2016 18:36:43
Result:
  $TargetDedicatedNodes=10;
  $NodeDeallocationOption=requeue;
  $curTime=2016-10-14T18:36:43.282Z;
  $isWeekday=1;
  $isWorkingWeekdayHour=0;
  $workHours=0
Error:

プールの自動スケーリング イベントを使用して自動スケールの実行履歴を取得する

PoolAutoScaleEvent に対してクエリを実行して、自動スケーリングの履歴を確認することもできます。 Batch は、このイベントを生成して、自動スケールの数式の評価と実行が発生するたびにそれを記録します。これは、潜在的な問題のトラブルシューティングに役立ちます。

PoolAutoScaleEvent のサンプル イベント:

{
    "id": "poolId",
    "timestamp": "2020-09-21T23:41:36.750Z",
    "formula": "...",
    "results": "$TargetDedicatedNodes=10;$NodeDeallocationOption=requeue;$curTime=2016-10-14T18:36:43.282Z;$isWeekday=1;$isWorkingWeekdayHour=0;$workHours=0",
    "error": {
        "code": "",
        "message": "",
        "values": []
    }
}

自動スケールの数式の例

さまざまな方法でプールのコンピューティング リソースの量を調整する、いくつかの数式を見ていきます。

例 1:時間ベースの調整

曜日や時間帯でプール サイズを調整する必要があるとします。 この例では、状況に応じてプールのノード数を増減させる方法を示します。

数式は、最初に現在の時刻を取得します。 平日 (1 ~ 5) および稼働時間 (午前 8 時~午後 6 時) 内の場合、目標のプール サイズは 20 のノードに設定されます。 その他の場合、プール サイズは 10 ノードに設定されます。

$curTime = time();
$workHours = $curTime.hour >= 8 && $curTime.hour < 18;
$isWeekday = $curTime.weekday >= 1 && $curTime.weekday <= 5;
$isWorkingWeekdayHour = $workHours && $isWeekday;
$TargetDedicatedNodes = $isWorkingWeekdayHour ? 20:10;
$NodeDeallocationOption = taskcompletion;

$curTime は、TimeZoneInterval_Hour と UTC オフセットの積に time() を追加することで、ローカル タイム ゾーンを反映するように調整できます。 たとえば、山地夏時間 (MDT) には $curTime = time() + (-6 * TimeInterval_Hour); を使用します。 オフセットは、夏時間の開始時と終了時に調整する必要があることにご注意ください (該当する場合)。

例 2:タスクベースの調整

この C# の例では、プールのサイズはキューのタスク数に基づいて調整されます。 コメントと改行の両方が数式の文字列に含まれています。

// Get pending tasks for the past 15 minutes.
$samples = $PendingTasks.GetSamplePercent(TimeInterval_Minute * 15);
// If you have fewer than 70 percent data points, use the last sample point,
// otherwise use the maximum of last sample point and the history average.
$tasks = $samples < 70 ? max(0,$PendingTasks.GetSample(1)) : max( $PendingTasks.GetSample(1), avg($PendingTasks.GetSample(TimeInterval_Minute * 15)));
// If number of pending tasks is not 0, set targetVM to pending tasks, otherwise
// half of current dedicated.
$targetVMs = $tasks > 0? $tasks:max(0, $TargetDedicatedNodes/2);
// The pool size is capped at 20, if target VM value is more than that, set it
// to 20. This value should be adjusted according to your use case.
$TargetDedicatedNodes = max(0, min($targetVMs, 20));
// Set node deallocation mode - let running tasks finish before removing a node
$NodeDeallocationOption = taskcompletion;

例 3: 並列タスクの説明

この C# の例では、タスクの数に基づいてプール サイズを調整します。 この数式では、プールに設定されている TaskSlotsPerNode 値も考慮されます。 このアプローチは、プールで並列タスクの実行が有効になっている場合に便利です。

// Determine whether 70 percent of the samples have been recorded in the past
// 15 minutes; if not, use last sample
$samples = $ActiveTasks.GetSamplePercent(TimeInterval_Minute * 15);
$tasks = $samples < 70 ? max(0,$ActiveTasks.GetSample(1)) : max( $ActiveTasks.GetSample(1),avg($ActiveTasks.GetSample(TimeInterval_Minute * 15)));
// Set the number of nodes to add to one-fourth the number of active tasks
// (the TaskSlotsPerNode property on this pool is set to 4, adjust
// this number for your use case)
$cores = $TargetDedicatedNodes * 4;
$extraVMs = (($tasks - $cores) + 3) / 4;
$targetVMs = ($TargetDedicatedNodes + $extraVMs);
// Attempt to grow the number of compute nodes to match the number of active
// tasks, with a maximum of 3
$TargetDedicatedNodes = max(0,min($targetVMs,3));
// Keep the nodes active until the tasks finish
$NodeDeallocationOption = taskcompletion;

例 4: 初期のプール サイズの設定

この例は、最初の期間におけるプール サイズを特定のノード数に設定する、自動スケーリングの数式を使用した C# の例を示しています。 その後、実行中のアクティブなタスク数に基づいてプール サイズが調整されます。

具体的に、この数式では次のことを行います。

  • 最初のプール サイズを 4 ノードに設定しています。
  • プールのライフサイクルの最初の 10 分間は、プール サイズを調整しません。
  • 10 分経過した後は、過去 60 分間の実行中でアクティブなタスク数の最大値を取得します。
    • 両方の値が 0 の場合、過去 60 分間に実行中のタスクやアクティブなタスクがなかったことを意味しており、プール サイズは 0 に設定されます。
    • いずれかの値が 0 よりも大きい場合は、変更されません。
string now = DateTime.UtcNow.ToString("r");
string formula = string.Format(@"
    $TargetDedicatedNodes = {1};
    lifespan         = time() - time(""{0}"");
    span             = TimeInterval_Minute * 60;
    startup          = TimeInterval_Minute * 10;
    ratio            = 50;

    $TargetDedicatedNodes = (lifespan > startup ? (max($RunningTasks.GetSample(span, ratio), $ActiveTasks.GetSample(span, ratio)) == 0 ? 0 : $TargetDedicatedNodes) : {1});
    ", now, 4);

次のステップ