[前][次][番号順一覧][スレッド一覧]

mysql:9648

From: ML account <ML account <ml@xxxxxxxxxx>>
Date: Tue, 15 Jun 2004 13:16:05 +0900
Subject: [mysql 09648] Re: Insert 毎に接続・切断を繰り返すと不特定な場所でエラーが発生する。

 こんにちは。

"Kageyama Takahiro" <kageyama329@xxxxxxxxxx>さんの
<BAY7-F33mRBaYFkuutS0001a0b6@xxxxxxxxxx>
"[mysql 09646] Re: Insert 毎に接続・切断を繰り返すと不特定な場所でエラーが発生する。"


> > エラーが発生した直後にDOS窓で"netstat"を実行するとどうなるでしょう?異
> >様に長いリストが表示されませんか?
> 
> はい、以下のように非常に長いリストが表示されます。
> コネクトする度に Local Address に連番が
> 振られているようですが、これは一体何なのでしょうか?

 JavaのJDBCやソケットがどの様な実装になっているかは知らないので、その下
の層の話をします。MySQLへのTCP/IPでの接続は、サーバ側ポート3306に対して
のTCPで行われます。MySQLに限らず、TCPを使用した通信を行うクライアントの
接続処理は、大体こんな感じになります。

・事前準備。サーバのホスト名からIPアドレスを引く、接続先ポート番号を確定
  する等。
・ソケットの作成。
・作成したソケットでサーバへ接続
・通信開始

 TCPで接続や通信を行うには、接続を行う2ホストのアドレス(IPアドレスとポー
ト番号の組)が必要です。クライアントから見て、自分のアドレスをローカルア
ドレス、サーバ側のアドレスをリモートアドレスと呼びます。通常のTCPを使っ
たアプリケーション(AP)では、クライアントはローカルアドレスを指定しないで、
スタック(ソケットを実装している層)に適当に決めて貰う様にします。スタック
が適当に決めるポート番号が連番である事が「Local Address に連番が」の理由
です。


 さて、この問題の原因ですが、実はあまり良く分かりません。ソケット/スタッ
クのレベルで原因として考えられるのは、

・ソケットを使い切った(最大ソケット数の上限にヒット)、またはメモリ不足で
  ソケットが作れない
・ポート番号を使い切った、または利用可能ポート数の上限にヒット

辺りでしょう。「ポート番号を使い切った、利用可能ポート数の上限にヒット」
をもうちょっと説明すると、TCPでは接続を閉じた後、少しの間そのローカルア
ドレスは使えません。TCPの遷移図、
http://www.atmarkit.co.jp/fwin2k/network/baswinlan016/baswinlan016_03.html
中の「(4)アクティブクローズ」の部分の下側にあるTIME_WAITの状態に落ち込む
のです。短時間に大量の接続/切断を繰り返すと、全ポートが TIME_WAITの状態
を含めて使用中になってしまい、使えるポートが無くなってしまいます。そうす
れば"Address already in use: connect"なエラーが出ても不思議ではないです。
このエラーが本当にローカルアドレスの重複によって出るのであれば、ですが。

 もっとも、Windows2000(そしてXPもだと思いますが)には、ポートが足りなく
なった場合に、TIME_WAITに遷移してから60秒以上経過した接続を強制的に
CLOSEDの状態へ遷移させる(つまりポートを空ける)緊急クリーンアップの機能を
持っていますし、短時間に大量の接続/切断を繰り返すのはプログラミング的に
アウチですから、通常はあまりポートが足りなくなってエラーが発生する事はあ
りません。けれども、MSのTCP/IP関係のレジストリ設定を変更するして(例えば、
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parametersで、
MaxFreeTWTCBsを6000、MaxUserPortを5000とするとか)、短時間に大量の接続/切
断を繰り返すと、ポートが足りなくてエラーが出る状態を作りだす事が出来ます。

 かげやまさんのメッセージからすると、大体4000回の接続/クエリ送出/切断を
繰り返すとエラーになるみたいですが、CとMySQLクライアントライブラリで作っ
たテストプログラムでは、20万を越えてもエラーは発生しません。ボクが使って
いるWindows2000サーバは、TCP関係のレジストリで、上限を設定しないか、設定
する場合にはかなり大きくしてあるかをやっているのがその理由でしょう。

 スタック/ソケット以外にに原因を求めるとすればJavaのクラスライブラリの
実装ですが、これはボクには分かりません。どなたか識者の方にお願いしましょ
う。

 と言う事で、何が何だか全然分かりませんね(笑)。



 原因は良く分からないですが、問題の解決法の指摘は簡単です。まずはレジス
トリをいじる事ですね。HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
\Tcpip\ParametersのMaxUserPortを大きくする、MaxFreeTWTCBsを小さくする、
である程度は改善されるでしょう。同時にメモリの増設も考えるべきです。しか
しこれは、場当たり的、姑息的な解決法で、問題の発生を先送りしているだけと
なってしまう事もあるでしょう。よって、あまりお勧めは出来ません。

 抜本的な解決法はコードの修正です。短時間に接続/切断を繰り返さない、は、
問題を起こす起こさない以前の話です。waitを入れるのはお勧めではありません。
現在行っている、1クエリ毎に接続/切断を繰り返す必要性が本当にあるのかを
もう一度考えましょう。必要性があるなら仕方が無いですが、「ただ何となく」
でやってませんか?


    松枝知直    <tomom@xxxxxxxxxx>
            http://www.argus.ne.jp/~tomom/



[前][次][番号順一覧][スレッド一覧]

      9646 2004-06-15 10:37 ["Kageyama Takahiro" ] Re: Insert 毎に接続・切断を繰り返すと不特定な場所でエラーが発生する。
      9647 2004-06-15 12:57 ┣[UNO Shintaro <uno@xx]                                       
->    9648 2004-06-15 13:16 ┗[ML account <ml@xxxxx]                                       
      9649 2004-06-15 17:49  ┗[深海水草 <VYG01106@x]                                     
      9650 2004-06-15 18:00   ┗[<yasuyuki@xxxxxxxxxx]