ALBの「賢いルーティング」を極める:重み付けとL7制御で実現する現場のゼロダウンタイム戦略
こんにちは。数え切れないほどの深夜の障害対応と、その後のポストモーテム(事後検証)で白髪が増えたシニアSREです。
皆さんはAWSのALB(Application Load Balancer)を単なる「リクエストを振り分ける箱」だと思っていませんか?もしそうなら、非常にもったいない。ALBは、実はインフラエンジニアにとって最も強力な「トラフィック・オーケストレーター」です。
今日は、教科書には載っていない「現場の泥臭い知見」を交えながら、ALBのL7ルーティングと重み付け制御を深掘りします。
—
1. なぜ「L7ルーティング」がビジネスを救うのか
一般的なLBはL4(TCP/UDP)で動きますが、ALBはHTTP/HTTPSのヘッダーを解釈します。ここが重要です。リクエストの Host ヘッダーや Path を見て、バックエンドのターゲットグループ(TG)へ振り分ける。この「賢さ」が、マイクロサービスアーキテクチャの心臓部となります。
パスベース・ホストベースの仕組み
ALBは、リスナーに対して「ルール」を優先度順に並べます。
- ホストベース:
api.example.comとweb.example.comを別々のサーバー群に飛ばす。 - パスベース:
/api/v1/userは認証基盤へ、/api/v1/productsはカタログ基盤へ飛ばす。
これらを組み合わせることで、モノリスなアプリを少しずつマイクロサービスへ切り出す「ストラングラー・フィグ・パターン(Strangler Fig Pattern)」が現実的なものになります。
—
2. 現場で重宝する「重み付け分散」の真実
ブルー/グリーンデプロイメントや、Canaryリリース(カナリアリリース)を行う際、最もお世話になるのが「ターゲットグループの重み付け」です。
例えば、新しいAPIサーバー(TG-New)を本番に投入する際、いきなり全トラフィックを向けるのは自殺行為です。まずは10%だけ流して、エラーレートとレイテンシを監視する。これがSREの鉄則です。
構成例:重み付け設定(Terraform記述)
Terraformで記述する場合、リスナーアクションの forward ブロック内で定義します。
resource "aws_lb_listener_rule" "canary_rule" {
listener_arn = aws_lb_listener.front_end.arn
priority = 100
action {
type = "forward"
forward {
# 旧バージョンに90%
target_group {
arn = aws_lb_target_group.old_version.arn
weight = 90
}
# 新バージョンに10%
target_group {
arn = aws_lb_target_group.new_version.arn
weight = 10
}
stickiness {
enabled = true
duration = 3600 # 1時間は同じTGに振り分ける
}
}
}
condition {
path_pattern {
values = ["/api/v1/*"]
}
}
}
SREの現場Tips:
stickiness(スティッキーセッション)の設定には注意してください。重み付けを行っている場合、クライアントのCookieベースでセッションを固定すると、比率が正確に反映されなくなります。カナリアリリースの初期段階では、あえてスティッキーセッションを無効にし、確率的な分散を優先するのがコツです。
—
3. 実践:デバッグと挙動確認
構築したルールが正しく動いているか、本番環境で試すのは勇気がいりますよね。まずはローカルから curl を叩いて、レスポンスヘッダーを確認するのが定石です。
# -v でHTTPヘッダーを表示し、リクエストがどのターゲットに到達したか検証する
# ALBが追加する 'X-Amzn-Trace-Id' を確認するのも有効です
curl -v -H "Host: api.example.com" https://your-alb-dns.com/api/v1/user
Pythonで簡易的な分散確認ツールを書くなら、以下のようなスクリプトを回して、数秒間の分布を見るのが一番手っ取り早いです。
import requests
from collections import Counter
# 100回リクエストを投げて、レスポンス内の特定の識別子(サーバーID等)を集計する
results = []
for _ in range(100):
res = requests.get("https://your-alb-dns.com/api/v1/user")
# レスポンスヘッダーからインスタンスID等を抽出(アプリ側で仕込んでおくこと)
server_id = res.headers.get("X-Server-ID")
results.append(server_id)
print(Counter(results))
—
4. トラブルシューティングの勘所
最後に、現場で必ずぶつかる壁を共有します。
1. 正規表現の罠:
path_pattern で正規表現を使う際、複雑すぎると評価順序のデバッグが困難になります。ルール数は最大100個まで。優先度(Priority)が若い順に評価されることを常に意識してください。
2. 503 Service Unavailable:
これが出たら、まずターゲットグループの「ヘルスチェック」を確認してください。ALBのルーティングが正しくても、ターゲットの HealthCheck が失敗していればリクエストは通りません。
3. HTTP 404:
ALBのルールで一致するものがない場合、デフォルトアクション(デフォルトターゲットグループ)に転送されます。もしデフォルトターゲットが存在しない、あるいは設定ミスがあると、ALBは迷わず 404 を返します。「意図しないリクエスト」を拾うための「キャッチオール用ターゲット」を常に用意しておくのが、ベテランのインフラ構成です。
—
まとめ
ALBのルーティング制御は、単なる設定作業ではありません。それは「トラフィックの交通整理」という名の、サービスを守るための防波堤構築です。
- 重み付けを使って安全にデプロイする。
- パスベースでサービスを疎結合にする。
- ヘッダーを駆使してリクエストを適切にハンドリングする。
これらを使いこなせば、皆さんのインフラはより堅牢に、そしてリリースが恐ろしくないものになるはずです。もし設定で詰まったら、まずは curl でヘッダーを追いかけるところから始めてみてください。パケットの行方を想像する力が、SREとしての最大の武器になります。
それでは、また次回の障害対応(ではなく、平和な運用)でお会いしましょう!
コメント