[AWS] ALBの期間ベースのスティッキーセッション動作確認
ALBの期間ベースのスティッキーセッション動作確認
動作確認をしたので備忘録的にメモ。
何を確認したかったのか
上記のドキュメントに「トラフィックが最初にインスタンスにルーティングされた後、後続のトラフィックは指定された期間、その EC2 インスタンスに維持されます。」という記載があります。この文章だけ読むと、一度取得したCookieを利用し続けていると、指定された期間が過ぎたあと別のターゲットにリクエストが飛んでしまい期待通りの動作にならないことがあるのでは?と気になり、挙動を確認し安全に使うための方法が確認したかったです。
TL;DR;
取得したCookieをセットしてALBにアクセスすると、その度に新しいCookieの値が返ってくるので、同じターゲットにアクセスし続けたい場合、初回アクセス時のCookieをずっと使いまわすことはせず、常に直前のレスポンスのCookieを次のリクエストで利用すれば問題なさそうです。
確認
まず関連ドキュメントとその引用。初回ルーティング時のリクエストの話と、その有効期間の話が書いてあります。
ロードバランサーが生成した Cookie で Application Load Balancer を使用する場合:
Application Load Balancer は、ターゲットグループの重みを使用して、ターゲットグループ間で受信トラフィックのバランスをとる方法を決定します。
デフォルトでは、Application Load Balancer はラウンドロビンメソッドを使用して、送信先ターゲットグループの EC2 インスタンスにリクエストをルーティングします。
トラフィックが最初にインスタンスにルーティングされた後、後続のトラフィックは指定された期間、その EC2 インスタンスに維持されます。
期間ベースの維持
期間ベースの維持は、ロードバランサーが生成した Cookie (AWSALB) を使用して、ターゲットグループ内の同じターゲットにリクエストをルーティングします。 Cookie は、セッションをターゲットにマッピングするために使用します。アプリケーションに独自のセッション Cookie がない場合、独自の維持期間を指定し、ロードバランサーがユーザーのリクエストを同じターゲットに一貫してルーティングする期間を管理できます。
ロードバランサーは、クライアントから最初のリクエストを受信すると、選択したアルゴリズムに基づいてリクエストをターゲットにルーティングし、AWSALB という名前の Cookie を生成します。これは、選択したターゲットに関する情報をエンコードしてCookie を暗号化し、クライアントへの応答に Cookie を含めます。ロードバランサーが生成した cookie には 7 日間の有効期限がありますが、これは設定できません。
後続のリクエストでは、クライアントは AWSALB Cookie を含める必要があります。ロードバランサーは Cookie を含むクライアントからリクエストを受信すると、それを検出し、同じターゲットにリクエストをルーティングします。Cookie が存在するがデコードできない場合、または登録解除されたターゲットや異常なターゲットを参照している場合、ロードバランサーは新しいターゲットを選択し、新しいターゲットに関する情報で Cookie を更新します。
ただ、これだけでは、二回目以降にどのようにアクセスするべきか具体的な記述がありません。そのため、実際に実行してみます。
検証構成
今回の検証構成は下記の図の通りです。InternalなALBを作成して、Target Groupに2つのEC2インスタンスのPort 80番を登録、EC2インスタンス上ではnginxを動作させます。VPC内に配置した、cloudshellから実際にcurlコマンドでリクエストを送り、期間ベースの維持を実施する場合、どのように分散されるか見ていきます。

期間ベースの維持=ALBが発行したCookieをもとにしたルーティングの設定は下記のとおり、Target Group設定で行います。赤枠で囲んだエリアの設定です。

単純な実行
まずはCloudShellからcurlコマンドを何回か実行してみましょう。EC2 (1)はレスポンスとして1を、EC2 (2)は2というテキストだけを返すようにnginxのindex.htmlを書き換えておきます。とりあえず10回curlを実行してみます。

分散しましたね。
初回でCookieを取り出して利用する
初回リクエストでCookieを取り出して、そのCookieをセットして10回curlを実行したらどうなるかをみていきます。まずはCookieを取り出すために-vオプションをつけて実行してみます。

AWSALBというCookieが返ってきていますね。また、インスタンスは2番です。次に、このCookieをセットするために--cookieオプションをつけてこのCookieを設定してcurlを10回実行します。

ちゃんと2番のインスタンスに10回全てのリクエストが飛んでいることが確認できました。
Cookieの期限切れにどう対応するか
とはいえ、このままだと期限(Expires=Tue, 26 Aug 2025 11:43:18)が来てしまったときにどちらのインスタンスにリクエストが行くか分かりません。継続的に決まったインスタンスへリクエストを飛ばすためにはどうしたらいいのでしょうか。
実は、この期間ベースのCookieの場合は、上記のCookieをセットしてリクエストを投げると、また新しい別のCookieが返ってきます。こちらは、また新しい期限が切られることになるため、継続的に実行する場合、このCookieを逐一新しいものに乗り換えて行けば良さそうです。
実験のため、下記のようなスクリプトを書いてみます。最初にCookieを新規に取得し、以後はリクエストを送るたびに新しいCookieをレスポンスから取り出して、次のcurl実行ではそれをCookieとして設定する方式で、これを10回繰り返します。
#!/bin/bash
COOKIE=$(curl -s -D - "${ALB_URL}" | grep -i '^Set-Cookie: AWSALB=' | sed 's/Set-Cookie: //g' | sed 's/;.*//')
for i in $(seq 1 10); do
COOKIE=$(curl -s -o output -D - --cookie ${COOKIE} "${ALB_URL}" | grep -i '^Set-Cookie: AWSALB=' | sed 's/Set-Cookie: //g' | sed 's/;.*//')
echo "NEW COOKIE: ${COOKIE}"
cat output
done
このスクリプトを2回実行してみました。

ちゃんと初回で選択されたEC2インスタンスにリクエストが飛んでいるのが分かりますね。新しい値の異なるCookieが毎回返ってきていて、そのCookieに乗り換えていっても(当然ですが)同じにインスタンスにずっと割り当てられていることが確認できます。
まとめ
期間ベースの維持、すなわちALBが返すCookieを利用する場合には、取得したCookieをセットしてALBにアクセスすると、その度に新しいCookieの値が返ってくるので、同じターゲットにアクセスし続けたい場合、初回アクセス時のCookieをずっと使いまわすことはせず、常に直前のレスポンスのCookieを次のリクエストで利用すれば問題なさそうです。
ただし、(当然ですが)不必要にこのCookieの期限を長くして、毎回Cookieを設定し続けて同じインスタンスにリクエストが集中させてしまうのは、ロードバランスができず本末転倒なので、適切な期間に設定し、同じインスタンスに飛ばす必要がある時のみ、Cookieを取り出して利用しましょう。
Discussion