一覧CL-09-1 · 可用性と伸縮

オートスケーリングとアプリケーションの状態管理

要求台数と利用可能台数を分け、処理能力・縮小待機・アプリの状態保持を合わせて説明します。

説明

オートスケーリングでは、必要な台数を計算するだけでなく、新しい処理先が利用可能になるまでの時間と、削除する処理先が持つ状態を考える必要があります。台数の上限もあるため、負荷が増えれば必ず処理できるわけではありません。

1台が1区間に100件を処理し、目標をその60%とする固定モデルを使います。最小1台・最大4台、起動準備は2区間、縮小は最後の変更から2区間待つ条件です。負荷50→240→20を与え、準備中の台数と、縮小で消えるローカルの買物かごを確認します。

要求台数と利用可能台数を分け、処理能力・縮小待機・アプリの状態保持を合わせて説明します。

1最初の一台と共有状態

Scaleは利用可能なn1、準備中の一覧、ノードごとの買物かご、別に保持する共有状態を持ちます。

from scaling import Scale scale = Scale()固定条件の台数調整モデルを用意する print("ready", scale.ready利用可能なノードを読む, "pending", scale.pending準備中のノードを読む, "shared", scale.shared)

利用可能はn1だけで、準備中はありません。新しいノードを要求した件数と、現在使えるノードの件数は別に記録します。

2目標範囲内の負荷

最初の区間に50件の要求を与えます。必要台数はceil(要求数÷60)です。

scale.step(50)50件の負荷で必要台数と処理結果を計算する

requested=1、desired=1で、1台の能力100に対して50件を処理します。台数変更はありません。この例はCPU使用率の実測ではなく、固定の処理能力と件数による計算です。

3急増しても新しい台数はまだ使えない

次の区間に240件を与えます。

scale.step(240)240件への急増と起動準備を確認する

requested=4で3台を追加要求しますが、readyは1台です。能力100なので140件が処理できません。このモデルでは超過を待たせず拒否し、起動要求の時点で処理能力を増やしません。

4起動中のインスタンスを重複して追加しない

もう一度240件を与えます。

scale.step(240)準備中の台数を含めて追加要否を計算する

n2〜n4は引き続き準備中です。readyとpendingを合わせれば要求した4台があるため、さらに3台を重ねて要求しません。ただし、この区間も使える能力は100です。

5準備が完了した台数とローカル状態

次の区間で追加3台が利用可能になります。その後、n2にだけ買物かごを置き、同じ内容を共有状態にも保存します。

scale.step(240)追加ノードが利用可能になった区間を計算する scale.carts["n2"]["user7"] = ["book"]n2だけに利用者の状態を保存する scale.shared["user7"] = ["book"]ノード外の共有状態にも保存する print("local n2", scale.carts["n2"], "shared", scale.shared)

readyは4台、能力400で240件を処理できます。買物かごはn2のローカル状態と共有状態の二箇所にあり、ノード削除時の差を次に確認します。

6負荷が下がっても直ちに縮小しない

20件の区間を2回続けます。縮小は最後の変更から2区間経過してから行う条件です。

scale.step(20)負荷低下後の縮小条件を確認する scale.step(20)

最初はscale-in cooldownで4台を保ち、次にn1へ縮小します。短い負荷変動で台数を往復させにくくする待機ですが、余分な台数を維持する時間との兼ね合いがあります。

7削除したノードにしかない状態は消える

残ったn1から利用者の買物かごを探し、共有状態と比較します。

print("n1 local", scale.carts["n1"].get("user7")残ったノードのローカル状態を読む) print("shared", scale.shared.get("user7")ノード外で保持した状態を読む)

n1のローカルはNone、共有側はbookです。台数調整だけではノード内のセッションを移せません。処理先が変わっても必要な状態をどこで保持するかを設計します。

8最大台数でも処理しきれない負荷

600件の区間を3回与え、追加ノードが準備を終えるまで追います。

scale.step(600)上限を超える負荷と準備後の能力を追う scale.step(600) scale.step(600)

必要台数はceil(600÷60)=10ですが、上限でdesired=4です。準備後も能力400なので200件を拒否します。オートスケーリングに加えて、上限・他の依存先・受付制限も確認する必要があります。

まとめ

要求した台数と、今すぐ処理できる台数は異なります。

縮小待機とノード外の状態保持を合わせて設計します。

最大台数を超える負荷は台数調整だけでは処理できません。

操作履歴と解説を振り返れます。

Python 3

1
from scaling import Scale scale = Scale() print("ready", scale.ready, "pending", scale.pending, "shared", scale.shared)
ready ['n1'] pending {} shared {}
2
scale.step(50)
t=0 load=50 requested=1 desired=1 ready=['n1'] pending={} capacity=100 served=50 rejected=0 action=hold
3
scale.step(240)
t=1 load=240 requested=4 desired=4 ready=['n1'] pending={'n2': 3, 'n3': 3, 'n4': 3} capacity=100 served=100 rejected=140 action=launch
4
scale.step(240)
t=2 load=240 requested=4 desired=4 ready=['n1'] pending={'n2': 3, 'n3': 3, 'n4': 3} capacity=100 served=100 rejected=140 action=hold
5
scale.step(240) scale.carts["n2"]["user7"] = ["book"] scale.shared["user7"] = ["book"] print("local n2", scale.carts["n2"], "shared", scale.shared)
t=3 load=240 requested=4 desired=4 ready=['n1', 'n2', 'n3', 'n4'] pending={} capacity=400 served=240 rejected=0 action=hold
local n2 {'user7': ['book']} shared {'user7': ['book']}
6
scale.step(20) scale.step(20)
t=4 load=20 requested=1 desired=1 ready=['n1', 'n2', 'n3', 'n4'] pending={} capacity=400 served=20 rejected=0 action=scale-in cooldown
t=5 load=20 requested=1 desired=1 ready=['n1'] pending={} capacity=100 served=20 rejected=0 action=remove
7
print("n1 local", scale.carts["n1"].get("user7")) print("shared", scale.shared.get("user7"))
n1 local None
shared ['book']
8
scale.step(600) scale.step(600) scale.step(600)
t=6 load=600 requested=10 desired=4 ready=['n1'] pending={'n5': 8, 'n6': 8, 'n7': 8} capacity=100 served=100 rejected=500 action=launch
t=7 load=600 requested=10 desired=4 ready=['n1'] pending={'n5': 8, 'n6': 8, 'n7': 8} capacity=100 served=100 rejected=500 action=hold
t=8 load=600 requested=10 desired=4 ready=['n1', 'n5', 'n6', 'n7'] pending={} capacity=400 served=400 rejected=200 action=hold

演習完了