AWS re:Invent 2024 - Optimizing ELB traffic distribution for high availability (NET401) を聴講して

# はじめに
本ブログは[Japan AWS Top Engineers Advent Calendar 2024](https://qiita.com/advent-calendar/2024/aws-top-engineers) シリーズ2の24日目の記事です。
※業務都合、体調不良などあり、遅れての投稿失礼します:bow_tone1:

今年もAWS re:Invent2024が12/2～6にラスベガスで開催され、私も現地参加してきました。
現地で聴講した<b>「Optimizing ELB traffic distribution for high availability (NET401) 」</b>というBreakout SessionがELB好きの私にとっては大変興味深いセッションでしたので、本ブログでは概要と、セッションの中で興味深かった点について書いていきたいと思います。

# 本記事の前提

全体の流れを説明しながら、特に興味深かった点について詳細や関連情報に触れていきたいと思います。<b>単純な書き起こし記事ではないため、詳細が気になる方は動画やAWSの有志の方が作成されている書き起こし記事をご参照ください。</b>

■セッション動画

https://youtu.be/EhbFossuQhI?si=v2meA9BGEwcg1QEF

■AWSの有志の方による日本語全文書き起こし記事

https://zenn.dev/kiiwami/articles/e703cfa71bc3722e

また、今回出てきたELBのベストプラクティスの一部は以下に書かれているとのことですので、興味のある方はこちらもご参照ください！

https://aws.github.io/aws-elb-best-practices/

# Optimizing ELB traffic distribution for high availability (NET401) 概要

セッションCatalogに書かれていた概要は以下です。

> In modern cloud-based architectures, load balancing is key to high availability and scalability. AWS offers Elastic Load Balancing (ELB) to intelligently distribute incoming traffic across multiple targets, such as Amazon EC2 instances or containers. In this session, dive into ELB advanced traffic distribution algorithms and examine how requests are routed to target resources. From instance health checks and routing policies to client-side caching, explore the factors that shape your application’s performance. Gain insights into configuration best practices and learn how optimizing traffic distribution can enhance service availability and mitigate bottlenecks.

> 現代のクラウドベースのアーキテクチャにおいて、負荷分散は高い可用性とスケーラビリティを実現するための重要な要素です。AWSは、Elastic Load Balancing (ELB) を提供しており、Amazon EC2インスタンスやコンテナなどの複数のターゲットに対して、受信トラフィックをインテリジェントに分散させます。このセッションでは、ELBの高度なトラフィック分配アルゴリズムに深く入り込み、リクエストがターゲットリソースにどのようにルーティングされるかを詳しく調べます。インスタンスのヘルスチェックやルーティングポリシー、クライアントサイドキャッシングに至るまで、アプリケーションのパフォーマンスを形作る要因を探ります。設定のベストプラクティスについての洞察を得て、トラフィック分配を最適化することでサービスの可用性を向上させ、ボトルネックを軽減する方法を学びましょう。

登壇者はAWSのNetwork分野のSAであるEnrico Liguori氏とELB Customer SuccessのHeadであるJon Zobrist氏の2名でした。

大きく以下の内容に触れられており、
- Internet applications and architectures
- High availability application delivery
- Traffic routing clients to targets
- On-demand Loadbalancer Capacity Reservation

クライアントからアプリケーションに到達するための処理の詳細な流れや、関連するELB（特にALB（Application Load Balancer）/ NLB（Network Load Balancer））の内部動作、re:Invent 2024で発表された新機能も含むサービス仕様について触れた上で、どのように高可用性を保つのかのAWSサービス側としての取り組みや、ユーザ側で取るべきベストプラクティスについて話がありました。

また、このセッションを聞くことで以下の理解が深められる旨、説明がありました。

- AWSの高可用性がどのようなものか
- 正常で適切にスケーリングされたエンドポイントにルーティングされるようにロードバランサ―やその他システムを構成する方法
- DNSも含めた動作
- ALBの高度なルーティング機能

Level 400のセッションだけあり、表面的な動作だけでなくAWSの内部動作含めて説明されており、大変勉強になるセッションでした。

# セッション内容詳細

大きく以下3つのセクションに分かれておりますので、順に内容に触れていきます。

- ELBが高可用性を保つ仕組み
- Targetへのトラフィック分散について
- ELBのスケーリングについて

※以下「」がついている部分は単純なセッション内容の引用です。

## ELBが高可用性を保つ仕組み

### ClientからApplicationsへの到達性

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/74b9150f-5e2d-9ef0-4c17-139ab7fe482d.png)

最初はClientとApplicationsの到達性の話から。
関連するプロトコルとしてIPv4/v6、TCP/UDP、そしてTCP上のHTTPトラフィックについて説明していくという話がありましたが、この中で、AWSではIPとしてv4/v6が利用できるようになっており、<b>優れている点として、スタック全体でIPv6を学習して導入する必要がない点</b>に触れられていました。<b>実際AWSではフロントのELBをIPv4/v6のデュアルスタックで構築し、ターゲットとなるコンポーネントをIPv6で構成することなどが可能であるため</b>、部分的にIPv6を導入することが徐々に容易になってきていると感じます。



次にClientがApplicationsに接続するための仕組みの概要について話がありました。詳細は本記事では割愛しますが、この後の話で重要になる以下について触れられていました。

- ELBのDNS登録と名前解決の話
- 上記が適切なヘルスチェックやスケーリングと対応している話

### ELB障害の検出/障害部位を取り除く対応

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/a053a436-849b-9113-5b59-a9efab351a70.png)

「単一のリージョンにフォーカスすると、まず入り口のALBには最低利用AZごとに1つのIPアドレスが割り当てられます。ただ、規模に応じてIPアドレスの数が増加します。
正常でなくなった場合DNSから除外されます。」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/1ef3762a-cc49-eff1-03c3-46e2c8daac4d.png)

上記スライドでは"正常でなくなった"と判断される理由が挙げられています。

説明の中で、TargetGroupのFail openを発動させる閾値やRoute 53ヘルスチェックの話がありましたが、その点については昨年のセッション[Enhance your app’s security & availability with Elastic Load Balancing (NET318)](https://youtu.be/6iO6wtDOKGM?si=98QIzmvuCtG6Edai)で詳細が述べられているので、興味がある方はそちらを視聴されることをお勧めします（※）。
※私も正直今回の説明だけだと理解しきれなかったため、上記を見ました。

Amazon Route 53 ARC Zonal Shiftを利用すると特定AZからのFail offをコントロールできるという説明もありました。ベストプラクティスとして<b>"ロードバランサで利用されているすべてのAZを利用すること"、"利用していないAZがある場合はロードバランサからも取り除くこと"</b>が述べられていました。この点はクロスゾーンがオフ状態でTargetが空のTarget Groupが利用される影響の話の中でも挙げられており、理由としては、障害の状況によっては、障害AZの切り離し動作を行っても、実際に利用されていないAZの影響で障害の影響範囲が大きくなってしまうケースや、障害時動作が想定通りとならないケースが挙げられるかと思います。

### ALBの障害検出/復旧（AWS内部の動作）

ここからはAWS側で行っている障害検出/復旧機構に関する話です。まずはALB。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/7f9ef22b-a3bd-0b47-9e50-f1bf8487d43b.png)

「<b>DNSに登録された各IPアドレスがALB内の各マシンに関連付けられており、何かの理由で異常と判断された場合にDNSから取り除かれます</b>。」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/57675166-b82a-e2da-b35a-8b07ecb90602.png)

「また、<b>Route 53側からだけでなく、ELBのAvailability SystemからALB内の各ノードに対してもpingによる死活監視が行われています</b>。Route 53はヘルスチェックNGとなることでDNSから該当IPアドレスを取り除き、ELBのAvailability Systemはping NGになることで、該当ノードを正常なノードに置き換えます。（Route 53のトリガーに約30秒、DNSのTTLが60秒のため約90秒でクライアントからの接続から取り除かれる。）」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/014ccee8-28ed-547c-943b-071a11683bf1.png)

「別の仕組みとして、ピア間のノードのパフォーマンスもチェックしています。
<b>ノードのメトリクスを監視して、ELB 5xxが多いや、不健全なノード数が多い場合にもDNSからの削除やノードの置き換えが行われます</b>。その後、問題のない置き換えだったかをチェックします。この異常検知は、5分、15分、4時間の時間枠で継続的にすべてのLoad Balancerで実行され、ヘルスチェックをトリガーするほど深刻ではないグレー障害を検出します。」
単純な死活監視だけだと[グレー障害](https://docs.aws.amazon.com/ja_jp/whitepapers/latest/advanced-multi-az-resilience-patterns/gray-failures.html)（※）への対応が難しいため、別視点からの検出も行っているという話です。AWSによるグレー障害に関する言及はここ1～2年で増えており、昨年のre:Inventの[Detecting and mitigating gray failures (ARC310)](https://youtu.be/LzIZ-dEzgEw?si=3JlTxUqCucWgltVZ)というセッションで詳細に語られていました。
※生き/死にが明確に分かれる障害ではなく、観測点によって応答結果が異なるような障害。



### NLBの障害検出/復旧（AWS内部の動作）

続いてはNLBの障害検出/復旧機構に関する話です。
前提として、NLBはPrivateLinkやLambdaのVPC接続などで利用されているHyperplaneという仕組みが使われており、VPCには各AZに1つずつENIが作られる形になるため、ALBとは少し考え方が変わります。
Lambdaの例になりますが、Hyperplaneについては以下のAWS公式Blogが参考になります。

https://aws.amazon.com/jp/blogs/compute/announcing-improved-vpc-networking-for-aws-lambda-functions/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/1a0c775b-0412-05c3-fcdd-10de25793b85.png)

「NLBでもALBと同様の高可用性機構を持っており、ヘルスチェックパケットにタグをつけて送っています。ヘルスチェックパケットは他のパケット同様各VPCのENIを経由してターゲットまで到達します。」
「このパスでパケットドロップを検出すると、グレー障害としてそのLoad Balancerを予防的にそのゾーンからシフトできます。」
仕組みは異なるものの、考え方としては大きく相違はなさそうです。ただ、各AZにENIが一つずつとなるため、ALBのようなノードごとの切り離しではなくゾーン単位での切り離しにはなりそうです。

### ARC zonal shiftのアップデート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/1fba1f99-1a5f-8c73-4157-ad0360caebe3.png)

今回のre:Inventであった、ARC zonal shiftのクロスゾーン対応について紹介がありました。ゾーン全体をシフトアウトすると、除外対象AZにはトラフィックが流れなくなります。このため、DNSレベルの除外だけでは防げなかったクロスゾーン有効時の懸念も解消されます。

また、Autoshiftについても話がありました。この機能により、アラームが発生した際にZone Failoverをトリガーするように設定が可能になったことと共に、AZ分離の重要性、AZ分離できる機構の重要性についても述べられていました。

## Targetへのトラフィック分散について

### クライアントからALB/NLBへの接続

ここからはTargetへのトラフィック分散についての話で、まずクライアントからALB/NLBを経てターゲットに到達する仕組みについて説明がありました。一般的な流れについては本記事では割愛しますが、話の中にあった押さえておきたい点としては、

<b>「トラフィックの送信に使用するIPについてはクライアントの動作に委ねられる」</b>

という点です。

上述の通りALBについては<b>障害等の理由からALBの名前解決結果として返されるIPアドレスが変わる</b>こと起こり得ますし、<b>NLBについても特定AZのIPアドレスが名前解決結果から除外される可能性があります</b>。この場合にクライアントがTTLを守らずIPアドレスを保持してしまうと、通信が行えなくなります。自身も過去にクライアントとなるミドルウェアの仕様により利用できなくなったALBのIPアドレスをTTLを越えて保持してしまいエラーが発生するトラブルを経験したことがあるので、この点は皆さん十分に注意いただきたいと思います。

また、TTLを守ることに加えて、<b>「TCP接続が予期せず切断された場合にDNSを更新するようクライアントを設定し、再接続時に最新のリストを取得できるようにすること」</b>、<b>「多数のクライアントが同時に再接続する場合、特定のIPアドレスに過負荷をかけないよう、指数バックオフとジッターを使用すること」</b>、<b>「エラーが発生したものとは別のIPアドレスへの接続を試みてみること」</b>が挙げられており、クライアント側で対応できるのであれば、こういった考慮も必要になるかと思います。

### ALBにおけるTarget Groupの選択

続いてALBにおけるリスナールールを利用したTarget Groupの選択についての説明がありました。こちらも一般的なALBの振り分けの仕組みの説明部分については割愛しますが、リスナールールのベストプラクティスの話が興味深かったので触れていきます。

1点目は、<b>「ホストヘッダベースのルールやSNIを利用して複数ドメインを1つのALBに集約することで運用負荷を下げられる。ただし障害時の影響範囲は広くなるので影響への考慮は必要。」</b>で、これは一般的かと思います。

2点目は、<b>「リスナールールにおいてよく使われるルールの優先度を上げる」</b>でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/98602bb8-d8b5-287d-501d-786bc05cbc03.png)

理由としては、ALBはリクエストのルールに対する評価数を元にスケールアウト/アップされるものの評価数が増えることで計算コストは増えその分遅延も発生するため、評価数が最小限になるようによく使われるルールの優先度を上げることが必要というものです。
機能として動かすだけであればマッチするルールが準備されていればよいですが、より効率的に、高い性能を求める場合はこのあたりの考慮が必要になります。
（昔BIG-IPのiRuleで同じようなチューニングを行ったことを思い出しました。）

3点目は、<b>「インターネット公開するALBのデフォルトルールは、各ルールにマッチしなかったルールをリダイレクトおよび拒否する設定とする」</b>でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/857af487-406f-57b0-c2f9-0b586135312e.png)

こちらはリスナールールに合致しない正常ではない通信（ボットや不正通信）をALBレベルで拒否し、ターゲットにルーティングしない（ターゲットのリソースを利用しない）という考え方で、取り入れるべきと思いました。

### Targetの選択

ここからがNLB/ALB/GWLB（Gateway Load Balancer）に分かれたTargetの選択方法についての話です。

ケース別にポイントを絞ると以下となります。
- NLBでTCPを利用するケース
    - TCPとIP情報（6タプル）からハッシュが抽出され、ハッシュを元にTargetが決定する
    - 戻りのパケットについて、クライアントIPアドレスの保持が有効になっている場合は宛先がクライアントのものなっているが、AWS内部の特別な処理によりNLBに強制的に戻る形となる（その際NLBが戻りパケットの送信元を自身のものに書き換える）
    - NLBは分散データベースを持っており、接続を識別する6タプルと選択されたTargetの紐付情報を保持している。コネクションのタイムアウトを迎えるまでは、この情報を利用することで同じTargetに接続される。

- NLBでUDPを利用するケース
    - 基本的にはTCPと同じだが、シーケンス番号を持たないため、5タプルになる
    - そのため、同じ送信元ポート番号を利用する形で複数のUDPパケットを投げる場合同じTargetに振られてしまうため、必要に応じて送信元ポートを分ける対応がいる

- GWLB
    - 大まかな考え方としてはNLBと同じ
    - GWLBの背後には通常トラフィックに対してステートフルなルールを適用するように設定されたファイアウォールアプライアンスがあるため、TCPコネクションと各方向のトラフィックに選択されたターゲットとの間のStickinessをネイティブに提供している

- ALB
    - NLB/GWLBとは異なり、HTTPリクエストレベルでTargetの選択が行われる
    - ALBとTargetとの接続が確立されると一定期間コネクションが維持され再利用される
    - Sticky Sessionを有効にすると、リクエストが既存のセッションのものである場合、同一のTargetに振り分けられる
        - 少数のクライアントが既存のクライアントセッションを使用してLoad Balancerにリクエストの大部分を送信する場合、結果として分散が不均衡になるため要注意であり、使わなくてよいなら使わない方がよい
    - ルーティングアルゴリズムとしてRound Robin/Least Outstanding Request/Weighted Randomが利用できる
    - Weighted Randomを利用する場合、Anomaly Detection Systemに基づく異常緩和機能が利用できる

最後に出てきた<b>「Anomaly Detection Systemに基づく異常緩和機能」ですが、簡単に言うと「ヘルスチェックは通っているがメトリクスでエラーを返しているTargetへの振り分け荷重を自動的に下げる機能」</b>です。昨年のre:Inventで発表された機能になります。本セッション内では、<b>「本来的にはヘルスチェックで取り除かれることが望ましいですが、影響を迅速に排除するためには有効」</b>との説明がありました。

## ELBのスケーリングについて

最後はELBのスケーリングの仕組みについての話でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/1f2e26e9-3b3a-ecfc-3500-3bd6de5962a3.png)

基本的には処理量に応じて自動的にスケーリングが行われます。
Scale UpについてはCPU使用率35%、50 req/targetで行われるということで、かなり余裕をもって行われているようです。また、Scale downについては、Cooldown期間を12時間持つなど、かなり慎重に行われているようです（それはそうですが．．．。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/4448672a-cc42-db69-99fe-9528a28eafc5.png)

<b>上記のScale Upスピードにリクエスト増加が追い付かないケースにおいて、これまでは暖気申請が必要でしたが、re:Invent 2024のアップデートでCapacity Reservationが行えるようになりました</b>。将来的にGWLBでも対応予定とのことです。

この後Capacity Reservation機能やユースケースごとの動作、効果についての説明がありましたが、本記事では割愛します。

1点注意しておきたいと思った点としては、NLBについてはスケーリングの方法に少し特徴があるという点です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273915/e8b5e50f-a890-0a47-afa5-b733e3bc855e.png)

NLBは通常時のScaleをAZごとに行います。Capacity Reservationを利用する場合、指定したLCUをすべてのAZで分割する形になるので、AZごとの総数として均一にならない可能性がある点や、Targetが空になっているAZがありNLB上では有効になっていると、そこにもLCUが割り当てられてしまう点が注意点です。

## 終わりに

本記事では、re:Invetn 2024のBreakout Sessionで聴講した「Optimizing ELB traffic distribution for high availability (NET401) 」について興味深かった点を中心に整理しました。
進化も激しく中々追うのが大変ですが、内部的な仕組みも含めて本セッションで学ぶことができ、個人的にはとても楽しかったです。また、今回出てきた個別の技術についてはお正月中に深堀して学習したいと思います。