一覧CL-08-1 · ロードバランサーと配信

ロードバランサーの振り分けとヘルスチェック

どの単位で処理先が決まり、変更後にどの接続が残るかを確認して、切離し時の操作を説明します。

説明

ロードバランサーの振分けでは、接続を単位にするか、HTTP要求の内容を使うかで扱いが変わります。さらに、処理先が不健康になった場合や保守で切り離す場合は、新しい要求と既存接続を分けて考える必要があります。

L4では一度選んだ接続先を保持し、L7では/apiと/assets/の要求を別のグループへ送る固定モデルを使います。a・bの処理先を使って健康状態、draining、cookieによる固定を順に変えます。利用可能な対象がない場合は転送しない方針です。

どの単位で処理先が決まり、変更後にどの接続が残るかを確認して、切離し時の操作を説明します。

1L4では同じ接続を同じ処理先へ送る

L4はTCPなどの接続単位を扱うため、このモデルではpathの内容を振分けに使いません。c1で異なるpathを送ります。

from balance import Balancer l4 = Balancer("L4")接続単位の振分けを用意する l4.request("c1", "/api/orders")c1の最初の転送先を選ぶ l4.request("c1", "/assets/logo.svg")同じ接続の異なる要求を送る

両方ともaです。2回目はexisting connectionで、HTTPのpathが変わっても同じ接続先を使っています。

2L7では要求のpathからグループを選ぶ

L7の固定規則では/apiはa・b、/assets/はstaticへ送ります。同じフロント側の接続識別子で要求します。

l7 = Balancer("L7")要求内容による振分けを用意する l7.request("c1", "/api/orders")API用グループへ送る l7.request("c1", "/assets/logo.svg")静的ファイル用グループへ送る

/apiはa、/assets/はstaticへ送られます。HTTPを解釈する位置で、要求内容を使った振分けが可能になります。

3別のL4接続は別の処理先になる

新しい接続c2で要求します。選択は固定のラウンドロビンです。

l4.request("c2", "/api/orders")新しい接続の転送先を選ぶ print(l4.connections接続と処理先の対応を読む)

c2はbになり、接続表にはc1→a、c2→bが残ります。アプリが接続を長く再利用する場合、要求数がそのまま均等に分かれるとは限りません。

4異常なサーバーを新規接続の振り分け先から外す

bのhealthをFalseにして、新しいc3と既存のc2を使います。

l4.health["b"] = Falsebを新規選択の候補から外す l4.request("c3", "/api/orders")新規接続の選択を確認する l4.request("c2", "/api/orders")既存接続が自動移動しないことを確認する

新しいc3はaへ送られますが、c2はbとの接続なのでconnection_failedです。別の接続先へ、新しい接続としてやり直す処理が必要になります。

5drainingでは既存接続を残す

aをdrainingへ入れます。新しい接続を増やさず、処理中の接続を終えるための状態です。

l4.draining.add("a")aへの新規接続を止める l4.request("c4", "/api/orders")新しい接続先が残るか確認する l4.request("c1", "/api/orders")既存接続の継続を確認する

新しいc4には候補がありませんが、既存のc1はaへ届きます。drainingへ設定した時点で、すべての接続が終了したわけではありません。

6復旧した対象へ新しい接続を送る

bを健康状態へ戻してc4を要求します。

l4.health["b"] = Truebを利用可能な候補へ戻す l4.request("c4", "/api/orders")新しい接続を復旧先へ送る

c4はbへ送られます。aをdrainingにしたままでも、別の利用可能な対象があれば新しい接続を受け付けられます。

7古い接続を閉じてから再接続する

c1を閉じ、同じクライアントの新しい接続として再度要求します。

l4.close_connection("c1")aへ向いていた接続を閉じる l4.request("c1", "/api/orders")新規接続として選び直す

今度はbが選ばれます。既存接続の継続と新規選択が別なので、接続の終了・再接続まで含めて保守の完了を確認します。

8cookieによる固定と処理先の除外

L7でbを指すcookieを使い、その後bを不健康にして同じcookieを送ります。cookieはこの例では対象名を記録した固定値です。

l7.request("c5", "/api/orders", cookie="b")cookieで利用可能なbを選ぶ l7.health["b"] = False固定先のbを候補から外す l7.request("c6", "/api/orders", cookie="b")同じcookieの扱いを再確認する

最初はsticky cookieでb、除外後はaが選ばれます。固定先を使えなくなったときに、別の処理先でもセッション状態を扱える設計が必要です。

まとめ

接続単位とHTTP要求単位では、振分けを選び直すタイミングが異なります。

新規の振分け除外と、既存接続の終了を別々に確認します。

cookieによる固定でも処理先変更は起こり得るため、状態保持を別に設計します。

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

Python 3

1
from balance import Balancer l4 = Balancer("L4") l4.request("c1", "/api/orders") l4.request("c1", "/assets/logo.svg")
L4 connection=c1 path=/api/orders target=a reason=new selection result=delivered
L4 connection=c1 path=/assets/logo.svg target=a reason=existing connection result=delivered
2
l7 = Balancer("L7") l7.request("c1", "/api/orders") l7.request("c1", "/assets/logo.svg")
L7 connection=c1 path=/api/orders target=a reason=new selection result=delivered
L7 connection=c1 path=/assets/logo.svg target=static reason=new selection result=delivered
3
l4.request("c2", "/api/orders") print(l4.connections)
L4 connection=c2 path=/api/orders target=b reason=new selection result=delivered
{'c1': 'a', 'c2': 'b'}
4
l4.health["b"] = False l4.request("c3", "/api/orders") l4.request("c2", "/api/orders")
L4 connection=c3 path=/api/orders target=a reason=new selection result=delivered
L4 connection=c2 path=/api/orders target=b reason=existing connection result=connection_failed
5
l4.draining.add("a") l4.request("c4", "/api/orders") l4.request("c1", "/api/orders")
no eligible target
L4 connection=c1 path=/api/orders target=a reason=existing connection result=delivered
6
l4.health["b"] = True l4.request("c4", "/api/orders")
L4 connection=c4 path=/api/orders target=b reason=new selection result=delivered
7
l4.close_connection("c1") l4.request("c1", "/api/orders")
L4 connection=c1 path=/api/orders target=b reason=new selection result=delivered
8
l7.request("c5", "/api/orders", cookie="b") l7.health["b"] = False l7.request("c6", "/api/orders", cookie="b")
L7 connection=c5 path=/api/orders target=b reason=sticky cookie result=delivered
L7 connection=c6 path=/api/orders target=a reason=new selection result=delivered

演習完了