LoginSignup
0
0

More than 1 year has passed since last update.

Azure 処理時間の長いAPIの応答が帰ってこない

Last updated at Posted at 2021-09-11

起こったこと

・クライアント(Pythonスクリプト)に、AzureVMに構築したAPIの応答が帰ってこない。
・サーバ側(VM)は正常に応答したログが記録されている。
・クライアントをcurlに変更すると何故か正常応答する。

構成

・Pythonクライアント→インターネット→Azure NSG→VM NIC→Nginx→Glassfish→SpringBoot
・SpringBootはファイル生成処理が挟まる関係上、リクエスト受領後約5分後に応答を返す。

結論

PublicIPのアイドルタイムアウト設定が初期値4分のままになっていたため。
これにより、4分間パケットのやり取りがないTCPコネクションがAzure側で掃除されていた。
アイドルタイムアウトを10分などに伸ばすと事象解消し正常にAPI応答が受領できるように。

下記がよくまとまっていたが、PublicIPのTCPアイドルタイムアウトが4分で固定と記載されている。
これは誤りで実際は4~30分で設定可能と思われる。
https://jpaztech.github.io/blog/network/snat-options-for-azure-vm/

VMのPublicIPに限らずApplicationGatewayのPublicIPや
LoadBalancer、NATGWなどSNATするもの全てでアイドルタイムアウト設定があるので、
応答に時間がかかるシステム構築では考慮が必要。

日本語の記事はあまり見当たらなかったが、英語だといくつかhitした。
https://docs.microsoft.com/en-us/answers/questions/152494/tcp-connections-dropped-after-approx-5-mins-of-ina.html

調べたこと①

・Pythonクライアント→localhost(自分のノートPC)→Tomcat→SpringBootでリクエスト→応答あり
・Pythonクライアント→インターネット→Azure NSG→VM NIC→Glassfish→SpringBoot→応答なし
・Pythonクライアント→localhost→VM NIC(lo)→Glassfish→SpringBoot→応答あり
・Pythonクライアント→localhost→VM NIC(lo)→→Nginx→Glassfish→SpringBoot→応答あり
→なんとなくAzureが怪しい、、

調べたこと②

クライアント側PCをwireshark、VM側をtcpdumpでパケットキャプチャを実施。
クライアント側は、httpsコネクションを受領後音沙汰なし。
netstatするとずっとコネクションはESTSABLISHEDのままとなっていた。

VM側は、コネクション確立後、約5分後正常にパケットを送信していたが、
ACKが帰ってこないため何度かリトライを実施(Azureではコネクションが消されているため)。
その後、FIN_WAIT1しRSTして切断していた。
→そりゃないコネクションにパケットを送っても届かないよね、、、

調べたこと③

curlすると何故か応答が帰ってくる、、、??
→wiresharkしたところ、何やらTCP Keep-Aliveしている。
→そのためAzureでアイドルタイムアウトで消される対象にされず延命されていた。
→でもlinuxのデフォルトTCP Keep-Aliveは7200秒(=2時間)で始まると聞いたぞ、、??

sysctl -a | grep keepalive

でVMの設定を確かめるも、

net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9

やはりデフォルトの2時間。

結果、curlの仕様を調べたらすぐに出てきました!
デフォルトで60秒おきにTCP Keep-Aliveしてくれるようです。

Use --keepalive-time to specify how often in full seconds you would like the probe to get sent to the peer. The default value is 60 seconds.

ちなみに、linuxのtcp_keepalive_timeの設定値を180秒など短くすることでも本事象は解消できそう。
この辺はシステム特性に応じて検討が必要ですね。

その他対処方法

Pythonのコード内でTCP Keep-Aliveを実装することもできそう。
通常のrequestsモジュールでは無理なのでsocketとかを使って書いていくみたい。
あまり深入りしなかったので、詳しくは分かりません。
https://www.programcreek.com/python/example/4925/socket.SO_KEEPALIVE

参考

TCP Keep-Alive/http Keep-Aliveの仕組みと違い
https通信をtcpdumpでキャプチャしてWiresharkする方法
Azure VM の外部接続 (SNAT) オプション まとめ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0