[AWS] NLBに複数Listenerを登録した時のAvailability Zone DNS Affinityの挙動について
戒め
Availability Zone DNS Affinityを利用している時に、Targetが空のTarget Groupを無闇にNLBのListenerに追加してはならない。
背景
NLBに複数のListenerがある環境で、リクエストが高確率でタイムアウトするという現象にハマりました。この問題は、NLBのCross-zone load balancingとAvailablity Zone DNS Affinityの設定と、Target Groupの設定が悪く発生していました。そのため、その辺りの挙動を整理していきます。
問題
構成と現象
現象が起きた環境の構成は下記の通りです。
ただし、Target Groupは下記の2つが定義してありました。
- AZ-A, AZ-BのEC2インスタンスをTargetとして登録しいずれのEC2もHealthyと判断されているTarget Group(以下 Target Group 1)
- 一つもTargetが登録されていないTarget Group (以下Target Group2)。
この時、Lambdaを呼び出すとたまにLambdaの要求がタイムアウトするという現象に悩まされていました。
Cross-Zone load balancingによる一時的な解決
詳しい方は当たりがついているかもしれませんが、どうやらLambdaは全AZを利用するように設定されており、これがAZ-Cで起動された場合に、タイムアウトしているようだということがわかりました。そのため、まずはCross-Zone load balancingを導入することで、NLBからどのAZのEC2インスタンスにも要求を飛ばせるようにして、この問題を回避することが確認できました。
詳細な調査
上記で回避できたとはいえ、挙動については理解できていない部分があります。そのため、本件についてこの記事では詳細に掘り下げていきます。
AZ絡みのNLBの設定
まず、NLBでAZ跨りのバランシングに関わる設定として、下記の2つがあります。
- Availablity Zone DNS Affinity
- Cross-zone load balancing
Availablity Zone DNS Affinityは、NLBのドメインに対するRoute 53 resolverに対するDNSクエリの回答をどのAZのIPアドレスを回答するかを調整できる設定です。本設定で、Availability Zone affinityを設定すると、クエリ元と同じAZのNLBのIPアドレスを返却します。ただし、当該AZにHealthyなLoad balancerがいない場合、他のZoneを返却してくれます。これ以外のAvailablity Zone DNS Affinityの設定として、Partial Availability Zone affinity, Any Availability Zoneがありますが、今回使用したのはこのAvailability Zone affinityなので他の説明は割愛します。詳細はこちらの公式マニュアルをご覧ください。
Cross-zone load balancingは、NLBがリクエストを受け取った時にそのリクエストをどこに配送するかの設定です。これをONにすると、NLBは自AZ外のTargetにも要求を飛ばします。逆にOFFにすると、NLBは同じAZのTargetのみに要求を飛ばします。
上述の設定と実環境の挙動
今回、問題が起きた環境では、
- Availablity Zone DNS Affinity: Availability Zone affinity
- Cross-zone load balancing: OFF
となっていました。この設定では、通常、LambdaがAZ-A, AZ-Bで起動された場合、NLB、EC2はそれぞれ同一のAZでリクエストが処理されます。しかし、LambdaがAZ-Cで起動された場合には、NLBはAZ-Cが受け取り、Cross-Zone load balancingがOFFであるため、AZ-C内のTargetに送信しようとしますが、EC2はAZ-Cに存在しないため、タイムアウトとなります。。。
。。。あれ?Availability Zone DNS Affinityの「ただし、当該AZにHealthyなLoad balancerがいない場合、他のZoneを返却することがあります。(英語原文: Queries may resolve to other zones if there are no healthy load balancer IP addresses in their own zone.)」はどう解釈すれば?AZ-CにはまともなEC2がいないから、DNSクエリでAZ-A or BのNLBのIPを返してくれるはずでは。。。
そう、ここで影響しているのが、Target Group2の「一つもTargetが登録されていないTarget Group」です。実は、こいつを消すと想定通り、AZ-A, AZ-Bが帰ってきて正常にリクエストが処理されます。また、このTarget Group2のAZ-BにHealthyなTargetを追加すると、AZ-Bのみを返してくれます。
一つもTargetが登録されていないTaget Groupを持つNLBはHealthyなLoad balancerとはみなされないようです。Target Groupの状態としてはTargetがおらずHealthyでもUnhealthyでもない状態ですので、Healthyではないと判断されるのは不思議ではないですね。
また、DNSクエリの段階では、ポートやその他情報が明らかになっていないので、どのListenerに行くのか、つまりどのTarget Groupを利用するか判断がつきません。なので、この段階では全てのTarget Groupの状況を見てDNSクエリとして何を返すか決定するのは致し方ないですね。
AZ DNS Affinity設定時のDNSの結果について試した範囲を表にまとめます。
Lambda (DNS Client) | Target Group 1 | Target Group 2 | DNS Answer |
---|---|---|---|
AZ-C | AZ-A, AZ-B: Healthy | No Targets | AZ-C |
AZ-C | AZ-A, AZ-B: Healthy | AZ-B: Healthy | AZ-B |
AZ-C | AZ-A, AZ-B: Healthy | No Target Group | AZ-A, AZ-B |
まとめ
以上、Availability Zone DNS Affinityを利用している際のNLBの挙動について記載しました。こうしてみると、この機能を利用している時に、空のTarget Groupを当てるのはもちろん問題ですが、AZのHealthy状況が異なるような(Health Check方法が異なるような)場合は複数のTarget Groupを1つのNLBに追加するようなことは避けた方が無難そうですね。
Discussion