Sponsored Link
以前というかこの頃Javaで簡単な分散処理サーバ・クライアントシステムのモデルを実装中にこのjava.io.StreamCorruptedExceptionという例外が発生しました。
StreamCorruptedExceptionの発生原因
結論から言えば、恐らく実行中のスレッドの数がマシンスペックに対して多すぎたのではないかと推定しました。
サーバが複数のクライアントを受け付けるので、クライアントのソケット接続(accept時)毎にスレッドを生成する方法を採りました。この時はブロッキング型のモデルを採りました(この頃ノンブロッキング型は知りませんでした)。
例外の発生状況はサーバプログラムをテスト動作時、絶えず約1000クライアントからのリクエストを受け付け、かつレスポンス等を行った場合です。なお送受信データはシリアライズされたオブジェクトで、サイズは平均5KB。その時テストマシンで走らせたスレッド数が約5000(…ぉぃ)。
シリアライズの復元の問題かと思ったんですが、送受信するオブジェクトのクラスとそのserialVersionUIDは揃えており、500クライアント位ではこれといった異常なく動作していたし・・・。
スレッド数が多いと、その分スレッドの切り替えが頻発したり、待たされるスレッドが出てきます。その為、ソケットの部分で受信データが許容量以上に溜まって、I/Oのどこかがオバーフローか変になったのかも・・・うーん。
実際にある時間のクライアントの送信データ数とサーバの受信データ数を確認してみたら、両数値の差が生じていて、約200リクエストがソケット部分で溜まったところでダウンしました。
例外発生時のスタックトレースの一部抜粋
java.io.StreamCorruptedException: unexpected reset; recursion depth: 1 at java.io.ObjectInputStream.handleReset(Unknown Source) at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.skipCustomData(Unknown Source) at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source) at java.io.ObjectInputStream.readClassDesc(Unknown Source) at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.readObject(Unknown Source)
また、これ以外にOptionalDataExceptionという例外も併発しましたが、これも同じ原因かと推定します。
java.io.OptionalDataException at java.io.ObjectInputStream.readObject0(Unknown Source) at java.io.ObjectInputStream.readObject(Unknown Source)
試した解決策
スレッド数を抑える
これは解決策とは言えないですが・・・。マシンスペック(CPU[コア]数やクロックなど)に対してスレッド数が多すぎるのが問題だと推定したので、ある程度スレッド数を抑えて運用したところ例外は発生しませんでした。
もう一度接続しなおす
まぁ例外をtry-catchブロックでキャッチできるので、それに合わせて接続しなおしてリクエストorレスポンスを再送することで済みました。・・・対処策ですね。抜本的な解決策は次の方法です。
ノンブロッキング型にする
nio(New I/O)ライブラリが用意されているので、それを用いたノンブロッキング型の機構にして、スレッドプールを用意することでスレッド数やコンテキストスイッチ、オーバヘッドをある程度抑えることが可能です。
関連すると思われる記事:
- java.lang.OutOfMemoryErrorが発生する原因とその解決法の一例
- C++, boost::thread : スレッドグループの生成と実行
- Java: TCP Socket Echo Server/Client サンプル
- C++, pthread: スレッドの同期と排他制御 – MutexとCondition Variable
- C++, boost::thread : スレッドの生成と実行
Sponsored Link

推定するな、計測せよ。(よく言われる話。
Javaは今勉強中でよくわからんが、I/O系の問題がおきてるなら、OS側のlogなり、sarあたりでI/O待ち時間とか、計測してみたら原因つかめるかも。
java VMのマルチスレッドがどういう風にカーネルに仕事を投げてるかわからんが、カーネル側の設定の可能性もあるかも。
おじさん、勉強しなきゃならんこと多くて、ようわからんけど最近サーバ関係の最適化の話で似たような話があったから、そこで書いてあったことを書いてみたw
> 推定するな、計測せよ。
いやもう全くその通りで、耳が痛いです。ナイス突っ込みです(>_< )b
実際、記事を書いているとき、この「推定」という言葉を使うこと自体に歯痒さを感じていました。
このプログラムは複数サーバを用いて効率的に分散処理を行う為、いくつかのネットワークトポロジーのモデルをそれぞれ評価するのに作成したもでした。その為、今回のI/O例外の原因分析に関してはそこそこに、モデルのおおよその性能を掴んだ後、直にC++での本(?)実装する段に入ってしまい、あまり突っ込んだ分析をしませんでした(>_< )
C++の実装では書き手が低レイヤーまで面倒見易いので、もしまた今回のようなI/Oエラーが発生した場合は、とことん分析しようと考えています。
> OS側のlogなり、sarあたりでI/O待ち時間
> カーネル側の設定
> サーバ関係の最適化の話
色々とアドバイスありがとうございます(^-^)
何かまた進展がありましたら記事にしようと思います。
お互い勉強頑張りましょう(^^)b