Azure Web Appsを利用するにはSNATに気をつけたい
Azureを利用する際に非常に重要なポイントとしてSNATポートの枯渇があります。
※Azureに限らずだとは思いますが・・・
特にWeb AppsについてはこのSNATポート枯渇の制限にハマりやすいかと思いますので、その制限についての詳細と回避するための方法について記載していきたいと思います。
そもそもSNATとは?
簡単に説明させていただくと、Private IPしか付与されていないサーバ等からPublicのサービスにアクセスする際にPublic IPに変換してNATすることをSNATと言います。
この通信の際に利用されるのephemeralなポートがSNATポートになります。
ではWeb AppsではどのようにこのSNATポートが枯渇されるのでしょうか。
Web Appsの内部構造とSNATの関係性について
Web Appsをすでにご利用されている方が多いと思いますので
本構成についてはご存知かと思いますが、Web Appsを作成する際にApp Serviceを作成します。これによりWeb Apps(ワーカーインスタンス)はこれはスタンプというユニット内にデプロイされます。
※App Service Environmentは少々異なる
ワーカーインスタンス自身にはPublic IPが付与されておらず、外部のリソースへアクセスするためにはスタンプのLoadbalancerを介してSNATを行い通信が実施されます。
SNATとApp Serviceの関係について詳細に知りたい方は、以下のサイトを参照ください。
App ServiceのSNATの制限値と超えた場合の挙動
上記のサイトにも記載がありますが、Web AppsのインスタンスごとにSNATポートの数は128までは保証されております。それを超える場合はスタンプ内で空いているポートからベストエフォートで割り当てが実施される場合があります。
では?この制限を超えた場合にどのような挙動になるのでしょうか・・・?
結論:外部との通信ができなくなる!
恐ろしいですね。いきなり通信が詰まってしまい正常に動作していたと思ったら
死に始めるような挙動になります。通信がうまく行くときもあれば、いかないときもあるなど・・・・
ではこのSNATポート枯渇にならないために必要なこととは何でしょうか?
- Modify the application to reuse connections
コネクションの再利用をする。アプリ側でHttpClientを使い回すことでしょうかね - Modify the application to use connectionpooling
DBなどでアクセスする際にConnection Poolingできますがこの設定をしておく
確かPHPのLarabelはDefaultでPoolingしないようになっていた気がするので注意が必要ですね! - Modify the application to use less aggressive retry logic
リトライ処理を実装と記載があります。ですがSNATポート枯渇している際にリトライしていたらどんどんつまりそうで根本的な解決にはならない気もしますが - Use keepalives to reset the outbound idle timeout
キープアライブの設定でアイドルタイムアウトのリセットを行う - Ensure the backend services can return response quickly.
バックエンドのサービスでレスポンスが早く返るか確認する。
通信が滞留する分SNATポートを保持し続ける時間も長くなるので大切ですね - Scale out the App Service plan to more instances
App Service Planのスケールアウトを行う。確かにインスタンスあたりで制限があるので増やせばその分SNATポートも増えます。ですがSNATポートが滞留するアプリ実装になっていれば増やしても根本的な解決にはならないし費用面が上がってしまします・・・ - Use App Service Environment, whose worker instance can have more SNAT ports, due to its smaller instances pool size.
App Service Environmentを利用するとありますが、確かにApp Service Environmentを利用すると、占有できるため利用できるSNATポートが増えますがその分構成が少々複雑になるのと価格が上がる懸念があります。 - A load test should simulate real world data in a steady feeding speed.
これは対策というよりも、リリース前の基本かと思いますが実際のデータでロードテストをすることも必要かと思います。
ここまでつらつらと対策と書いてきました。もちろんSNATポートを過度に利用しないためのアプリ側の実装等ももちろん大切ですが、そもそもSNATポートを利用しなければこんな問題には当たらないかと思います。
次の章でその方法について触れたいと思います。
SNATポートを利用しないためには?
SNATポートをそもそも利用しない方法として、3つのキーワードがあります。
- App Service Region VNet Integration
- Private Link
- Service Endpoint
この3つのキーワードでピンと来る方もいらっしゃるかもしれませんが・・・
そうです!そもそもPublic IPに変換してアクセスしなければいいんです!!!
※長々と書いてきましたがここがポイント
App Serviceの機能として、VNet Integrationがあります。
これはGatewayが必要なIntegrationと不要なRegion Integrationがあるのですが
今回はRegion Integrationを利用する必要があります。
※App Service PlanのPremiumV2のプランのみ
Region IntegrationはVNet内のリソースへのアクセスはもちろんサービスエンドポイントやPrivate Link経由にて各種Azureサービスへアクセスすることができます。
Azure SQL DatabaseやMySQL、Postgress、Storageなど様々なサービスでPrivate LinkまたはService Endpointの対応がされております。
これらのサービスへアクセスする際は、この機能を利用してVNet Integrationしたサブネットから内部的にアクセスすることでSNATポートを利用せずアクセスすることが可能になります!!!
またアプリでセッション管理等でCache for Redisを利用されるケースが多いと思われますが、このサービスについてはそもそもVNet内にPremium Plan以上でデプロイできるため内部的にアクセスすることが可能です。
まとめ
SNATポートを枯渇させないために、アプリ側の実装等気をつけるポイントはありますが、そもそもSNATポートを枯渇させないためにAzureの構成としてPrivate LinkやService Endpointをうまく利用することで解決することもできます。
これを機に構成を今一度見直す参考になれば良いと思っております。
最後になりますが、Web Apps自体でこのSNATポートの利用状況を確認できるページが追加されています。
仮にSNATポートの枯渇が疑われる場合は、本画面から現在利用されているSNATポートの数について確認していただければと思います。
今回はApp Serviceについてフォーカスしましたが、その他AzureサービスでもこのSNATポートについては気をつけて設計していただくのが予期しないエラーを回避する1つのポイントになるかと思います。
まあ偉そうに書いてますが、当の本人も1回このポイントを踏んでしまってるんですがね・・・
記載に不備があれば私自身も勉強になるためご指摘いただければと思います。