<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>WindowsServer管理者への道 &#187; BackEnd</title>
	<atom:link href="http://ebi.dyndns.biz/windowsadmin/tag/backend/feed/" rel="self" type="application/rss+xml" />
	<link>http://ebi.dyndns.biz/windowsadmin</link>
	<description>WindowsServer管理のノウハウを紹介します</description>
	<lastBuildDate>Sun, 01 Nov 2009 12:55:07 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>フロントエンド/バックエンドシステムでTCPポートが涸渇する問題への対処方法</title>
		<link>http://ebi.dyndns.biz/windowsadmin/2009/06/28/%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%a8%e3%83%b3%e3%83%89%e3%83%90%e3%83%83%e3%82%af%e3%82%a8%e3%83%b3%e3%83%89%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%81%a7tcp%e3%83%9d%e3%83%bc%e3%83%88/</link>
		<comments>http://ebi.dyndns.biz/windowsadmin/2009/06/28/%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%a8%e3%83%b3%e3%83%89%e3%83%90%e3%83%83%e3%82%af%e3%82%a8%e3%83%b3%e3%83%89%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%81%a7tcp%e3%83%9d%e3%83%bc%e3%83%88/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 13:43:04 +0000</pubDate>
		<dc:creator>ebi</dc:creator>
				<category><![CDATA[TCP/IP]]></category>
		<category><![CDATA[Windowsネットワーク]]></category>
		<category><![CDATA[ネットワーク障害]]></category>
		<category><![CDATA[BackEnd]]></category>
		<category><![CDATA[FrontEnd]]></category>

		<guid isPermaLink="false">http://ebi.dyndns.biz/windowsadmin/2009/06/28/%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%a8%e3%83%b3%e3%83%89%e3%83%90%e3%83%83%e3%82%af%e3%82%a8%e3%83%b3%e3%83%89%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%81%a7tcp%e3%83%9d%e3%83%bc%e3%83%88/</guid>
		<description><![CDATA[先日実際にお客さんのところで「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の状態遷移図 

今回は、「フロントエンド側に大量の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 

対処方法
このようにTCPのポート番号が涸渇してしまうようなケースにはどうやって対処すればいいのでしょうか?大きく3つの方法があります。
1.アプリケーションでネットワークの扱いを変更する
これが本来はいちばんいい対応方法です。TCPのコネクションを張るだけもパケットが3回も飛び交って時間がかかる(3ウェイハンドシェイク)わけですから、そんなに大量にコネクションを張らなくてはいけないくらい頻繁にデータを要求するなら、少数のTCPコネクションを張ったままにして、それをつど再利用すればいいわけです。これならポート涸渇の問題も発生しませんし、パフォーマンスすらよくなるでしょう。
ただし、もちろんこれは自分が作成しているアプリケーションならまだしも、製品であってはなかなか手がでる話ではありません。一応メーカーに文句はいいつつも、別の方法で問題を回避するより仕方が無いでしょう。
2. 一時的なポートの数を増やす
一時的なポートの数を増やすことでも対応できます。以下のレジストリの値を変更し、5000~65534までのポート番号までを使用できるようにできます。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

MaxUserPort(DWORD) 
5000～65534 



3.タイムアウトの時間を短くする
規定の状態ではTIME_WAITの状態で4分待ちます。さすがに4分というのは長すぎる気もしますので、これを短くすることで対応することもできます。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

TcpTimedWaitDelay(DWORD) 
30～240 



Windows VistaやWindows Server 2008ではTCPの一時的なポートの数は大幅に増えているのですから、ポートの数を増やしてしまうのがいいかもしれません。ですが、一応念のために書いておくと、やはりポート番号を管理するためにもOSのカーネルが仕事をしなければいけないわけですから、最悪の場合OSが不安定になったりする危険性があります。･･･とはいえ、ほとんどの環境で問題になることは無いと思いますけれども。
今回のポイント
今回のポイントは以下のあたりだと思います。

フロントエンド、バックエンドのシステムでどのように接続がなされ、どのようにデータが流れているのかの理解 
TCPのコネクションとポート番号との関係性の理解 

この手の問題は、しばらくほおっておくと勝手に問題が解決してしまって「たまにおかしくなる」「とりあえず再起動しておけば直る」というようなあいまいな認識になってしまうことが良くあります。想像力を働かせて、一つ一つ可能性を消していけば原因に到達できるはずですので、がんばっていきましょう。
]]></description>
		<wfw:commentRss>http://ebi.dyndns.biz/windowsadmin/2009/06/28/%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%a8%e3%83%b3%e3%83%89%e3%83%90%e3%83%83%e3%82%af%e3%82%a8%e3%83%b3%e3%83%89%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%81%a7tcp%e3%83%9d%e3%83%bc%e3%83%88/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
