フロントエンド/バックエンドシステムでTCPポートが涸渇する問題への対処方法

先日実際にお客さんのところで「TCPポートが涸渇する」という問題が起きたのでそのことについて書いてみようと思います。 実際のシステムはMicrosoft Dynamics CRMだったのですが、これは通常のフロントエンド/バックエンドシステムであればどのシステムでも起こりうる問題です。 フロントエンド/バックエンドシステム 「フロントエンド」、「バックエンド」という言葉が耳慣れない方もいると思うので簡単に説明しておきます。「フロントエンド」というのは実際にクライアントからの接続を受け、結果を返す役割のサーバーを指します。基本的にクライアントから見えるのはこのサーバーだけです。1台だけでは性能的にさばききれない、1台だけでは単一障害点になってしまう、というような理由から複数台配置されることが多いです。性能が足りなくなってきたらフロントエンドのサーバーの台数を単純に足してスケールアウトさせることができるというのもメリットです。 「バックエンド」というのはフロントエンドサーバーからデータの要求を受けつけ、それを返すサーバーです。フロントエンドは複数台で構成されることが多いのですが、その1台1台に実際にクライアントに応答を返すためのデータを全て保持していては、コストもかかりますし、それらをどのように更新、同期させるのかなど、色々と難しい問題が出てきてしまいます。そこで、データ自体は「バックエンド」のサーバーに持たせておき、必要なものをつど「バックエンド」から取得して、クライアントに応答する、ということにします。「バックエンド」にはデータベースサーバーが配置されることがほとんどです。また、「バックエンド」のサーバー自体も冗長化されることが多いですが、データベースサーバーを複数同時に稼動させるとデータの同期が難しいため、実際に稼動しているのは1台だけのActive-Passive構成を取る事が多いです。 フロントエンド/バックエンド構成の場合には、上記の図のようにTCP/IPのコネクションが張られます。フロントエンドの上の矢印はクライアントからの接続を意味しています。フロントエンドが複数台ある場合には、複数台に接続が分散されるように別途構成する必要があります。 Windows系のシステムでは - フロントエンドサーバーではIISが稼動 - クライアントからのHTTPの要求を受け付ける - バックエンドで稼動しているMS SQLサーバーから必要なデータを取得 - 結果のHTMLページを生成 - クライアントに返す ・・・というような処理が行われているのが一般的です。この際、フロントエンドの冗長化および負荷分散にはWindows標準のNLB(ネットワーク負荷分散)が使われ、バックエンドのMS SQLの冗長化には、Microsoft Cluster Service(フェールオーバークラスタ)が使われることが多いです。 何がおきていたのか 今回のトラブルは、フロントエンドサーバーにアクセスすると、特定のページでエラーが表示されてしまう、というトラブルでした。色々と可能性が考えられますが、結局はフロントエンドサーバーとバックエンドサーバー間のTCPコネクションに問題が発生していました。フロントエンドとバックエンド間では、SQLサーバーからのデータを取得するために、多数のコネクションが発生しています。そして今回のケースではフロントエンド側に大量にTIME_WAITのセッションが残ってしまっていて、それが原因でTCPのポートが涸渇し、バックエンドからデータを取得できない状態になってしまっていました。 TIME_WAITというのはTCPの状態を表すものです。通信の始まりから終わりまでどのようにTCPの状態が遷移するのか、ということはRFC793で定義されていて、その中のひとつです。以下の@ITの記事がこのあたりについてわかりやすく書いてあります。 - [@IT:連載 基礎から学ぶWindowsネットワーク 第16回 信頼性のある通信を実現するTCPプロトコル(3) 2.TCPの状態遷移図](http://www.atmarkit.co.jp/fwin2k/network/baswinlan016/baswinlan016_03.html) 今回は、「フロントエンド側に大量のTIME_WAIT」「バックエンド側には特におかしな点は無い」ということでした。これはつまりフロントエンド側がアクティブクローズを行っているわけです。ですが、その量が半端な数ではありませんでした。netstat -anで確認したところ、負荷が対してかかっていない状況でも100コネクション程度はTIME_WAITが確認でき、負荷が高い時間帯では数千コネクション程度確認されました。 TCPのコネクションはいくつまで使えるのか? 数千オーダーになってくると、そもそもきちんと動くのか?と心配になるかもしれませんが、実際に今回のシステムではこのTCPのポートが涸渇してしまい、正常に接続できない状態になってしまいました。そもそもTCPのポート番号(=コネクション)はいくつまで使えるのでしょうか? 規定の状態では、Windows XPとWindows 2003では一時的なポートの範囲は1024~5000です。つまり4024個を同時に使ってしまうとそれ以上接続にいけなくなってしまいます。Windows VistaとWindows2008では49152~65535と大幅に数が増えました。 - [The default dynamic port range for TCP/IP has changed in Windows Vista and in Windows Server 2008](http://support.microsoft.com/?scid=kb%3Ben-us%3B929851&x=10&y=14) 対処方法 このようにTCPのポート番号が涸渇してしまうようなケースにはどうやって対処すればいいのでしょうか?大きく3つの方法があります。 1.アプリケーションでネットワークの扱いを変更する これが本来はいちばんいい対応方法です。TCPのコネクションを張るだけもパケットが3回も飛び交って時間がかかる(3ウェイハンドシェイク)わけですから、そんなに大量にコネクションを張らなくてはいけないくらい頻繁にデータを要求するなら、少数のTCPコネクションを張ったままにして、それをつど再利用すればいいわけです。これならポート涸渇の問題も発生しませんし、パフォーマンスすらよくなるでしょう。 ただし、もちろんこれは自分が作成しているアプリケーションならまだしも、製品であってはなかなか手がでる話ではありません。一応メーカーに文句はいいつつも、別の方法で問題を回避するより仕方が無いでしょう。 2. 一時的なポートの数を増やす 一時的なポートの数を増やすことでも対応できます。以下のレジストリの値を変更し、5000~65534までのポート番号までを使用できるようにできます。 ...

June 28, 2009 · 1 min · 胡田昌彦