こんにちは、サイオステクノロジー 水倉です。
先日、Azure のネットワークタイムアウトでちょっとハマったことがあったため、注意すべき点をまとめておきたいと思います。具体的には、Azure VM のパブリック IP アドレスのアイドルタイムアウトが与える影響について、いくつかのケースを例に考えていきます。
- ローカル開発環境 AP サーバから Azure VM 上の DB へ接続しているケース
- Azure VM 上に Web アプリケーション(以後アプリと記す)をデプロイしているケース
- Azure VM の DB サーバへローカル DB クライアントツールを接続するケース
※本記事は、Azure Resource Manager デプロイメントモデルを前提としています。
Azure パブリック IP アドレスのタイムアウト仕様について
まず、Azure VM のパブリック IP アドレスはデフォルトでは 4 分間でタイムアウトする仕様となっています。適用されているタイムアウト値はパブリック IP アドレスの「構成」から確認することができます。
続いて、このタイムアウト値が与える影響について、いくつかのケースを確認していきます。
ローカルTomcat が Azure VM 上の DB を参照しているケース
例えば、こんな開発環境。
開発環境でTomcatはローカル、 DB は Azure 上で共有しているようなケースですね。(実際は仮想ネットワークがありますが簡略化しています。えっ、VPN じゃないの!?とか、そもそもの構成の妥当性はここでは置いておきます)
この時、アプリから DB への接続でコネクションプーリングを使用する場合に問題となることがあります。
コネクションプーリングは都度 DB へ接続するのではなく、接続をあらかじめプールしておいて使い回すことでアプリケーションの性能を高めるためのものです。一定時間使用されなければ接続を破棄する(ここでは「コネクションプーリングのアイドルタイムアウト」と表現します)仕組みとなっていますが、
コネクションプーリングのアイドルタイムアウト > Azure アイドルタイムアウト
の場合に問題が発生します。
例えば、コネクションプーリングのアイドルタイムアウトが 10 分、Azure アイドルタイムアウトが 4 分の場合、4 分以上使用されなかったコネクションは Azure 側で切断されるため、プールされているけれど実は死んでいる接続となります。このコネクションをアプリが使用するとソケットエラーとなります。
単に Azure アイドルタイムアウトを延ばせばエラーは起きなくなりますが、TCPセッションが残っていくためリソース面が懸念されます。コネクションプーリングには、プールされているコネクションが生存しているか(DB側で切断されているケースなど)をチェックする仕組みが実装されているので、これを使用します。
(参考) Tomcat JDBC Pool のパラメータ例
validationQuery="SELECT 1 FROM DUAL" validationInterval="60000"ここでは、コネクションプーリングの実装には言及しません。Tomcat JDBC Pool、Apache Commons DBCP、各種アプリケーションフレームワークでおおむね上記のようなパラメータが実装されていますので、具体的な設定は各ドキュメントをご確認ください。
Azure VM に Web アプリをデプロイしているケース
Azure VM で Web/AP/DB サーバをホストして、Web アプリをデプロイしているケースです。
Apache – Tomcat 間の通信タイムアウト > Azure アイドルタイムアウト
となる場合、Web ブラウザ側にいつまでたっても応答が返ってこないという現象が発生します。(えっちょっと、TomcatやDB側の処理が 4 分以上って、そもそも・・・という話は置いておきます。使用頻度の低い保守環境で低スペックVMだったり、DBのチューニングしてなかったりと諸事情お察しください)
この場合、 Azure アイドルタイムアウトによって通信が切断されるため、クライアントには Apache からの応答コードが返ってこず、TCP の FIN、RST パケットも返ってこないため、ひたすら待ちになり、ブラウザにエラー画面も表示されない状態になります。
対策としては、タイムアウトを下記の設定とする必要があります。
Apache – Tomcat 間の通信タイムアウト < Azure アイドルタイムアウト
この場合に Apache – Tomcat 間が通信タイムアウトに達した場合、Apache は HTTP ステータスコード 500 (サーバに負荷かかって裁き切れない時にお馴染みのやつですね) を返します。アプリケーション的にハンドリングしたい場合、DB 側でクエリタイムアウトを設定する手もあります。(これが有効な対策になるかは要件によりますね)
DB クエリタイムアウト < Apache – Tomcat 間の通信タイムアウト < Azure アイドルタイムアウト
Azure VM の DB サーバへクライアントツールを接続するケース
ローカルから Azure VM へ接続セッションを張っておきたい場合も同様に注意が必要です。一例として Azure VM の DB サーバへ DB クライアントツールを接続するケースでの対策を紹介します。
DBMS | Oracle |
DB クライアントツール | SQLDeveloper |
クライアント OS | Windows |
SQLDeveloper から Oracle へ接続後、4 分放置して SQL を実行すると接続セッションが破棄されているためエラーとなります。対策として、Keep Alive 設定をします。SQLDeveloper で Keep Alive を設定できればよいのですが、標準機能でないためちょっと工夫が必要でした。
クライアント側の設定
Oracle 社提供の InstantClient をダウンロードし、zip ファイルを任意の場所へ展開します。
※接続先 Oracle のバージョンと同じバージョンンのものをダウンロードします。
InstantClient 展開先ディレクトリへ PATH を通します。
SQLDeveloper の「ツール>プリファレンス>データベース>拡張」を選択し、「Oracle Client の使用」にチェック。「構成」ボタンを押して、「クライアント・タイプ」に「インスタント・クライアント」を指定、「クライアントの場所」に InstantClient の展開先ディレクトリを指定します。
Oracle サーバ側の設定
%ORACLE_HOME%\network\admin\sqlnet.ora へ下記を追記します。
SQLNET.EXPIRE_TIME=1ちょっと面倒ですが、これで接続が保持されるようになります。Oracle の場合に限らず、使用ツールに合わせて Keep Alive に相当する設定をしてあげれば対応できると思います。
最後に
Azure のネットワークタイムアウトと下記のタイムアウト時間との兼ね合いによる影響と対策を考えてみました。
- DBコネクションプーリングのアイドルタイムアウト
- Web-APサーバ間の通信タイムアウト
- DB 側のクエリタイムアウト
制約の大きい限られた環境でのみ発生するような事象ではありますが、開発中には遭遇する可能性があるので簡単に整理してみました。また、本記事では、パブリック IP での例でしたが、Azure Load Balancer での TCP タイムアウト、クラシック VM での予約済み IP のタイムアウトもデフォルト 4 分となっていますので、なぜか4 分程度で接続が切れる時は確認してみると良いと思います。
最後までご覧いただき、ありがとうございました(^o^)