クライアント サーバー アプリ、1 サーバー、約 10 クライアントがあります。これらは、カスタム クエリを使用して tcp ソケット経由で通信します。
システムは何ヶ月もスムーズに動作していましたが、ある時点で、毎日スケジュールされたサーバー FULL GC に約 50 秒かかった後、クライアントから送信されたクエリとサーバーから受信した応答の間の時間が長いことがわかりました。 > 10~20代。約 3 時間後にシステムが回復し、すべてが正常に動作するようになりました。
この問題を調査したところ、次のことがわかりました。
- クライアントとサーバーの両方でガベージ コレクションの問題がない
- サーバーでのクエリ処理時間はわずかでした。
- サーバーの負荷が高かった。
- ネットワーク帯域幅は飽和状態ではありませんでした。
- FULL GC 中に接続がリセットされませんでした (毎日の FULL GC はそれまで通常のイベントでした)。
- 最近、マシンと OS が Centos 6 (カーネル 2.6.32) から Centos 7 (カーネル 3.10.0) に変更されましたが、新しい構成は広範囲にテストされています。また、Oracle JDK のバージョンが 1.7.65 から 1.7.75 に変更されました。
サーバーでスレッド ダンプを取得しました。
java.lang.Thread.State: RUNNABLE
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at util.network.BytesBasedSocketConnection$ReadConnectionRunnable.run(BytesBasedSocketConnection.java:293)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
はFilterInputStream.read()
次のとおりです。
public int read() throws IOException {
return in.read();
}
in
私たちのコードの はですBufferedInputStream
。
問題は、フル GC の一時停止後にほとんどの接続が遅くなったのはなぜですか? スタックトレースが で終わるのはなぜFilterInputStream.read()
ですか? ソケット入力ストリームまたはソケット入力ストリームのどこかで終了するべきではありませんBufferedInputStream
か? この読み取りにより、サーバーの負荷が高くなる可能性はありますか?
読み取りに使用するコード:
int constructLength = _socketDIS.readInt();
ByteArrayOutputStream constructBOAS = new ByteArrayOutputStream(constructLength);
for (int i = 0; i != constructLength; i++)
constructBOAS.write(_socketDIS.read());
constructBOAS.close();
byte[] bytes = constructBOAS.toByteArray();
どこ:
_socketDIS = new DataInputStream(new BufferedInputStream(_socket.getInputStream()));
正常に動作しているクライアント接続からのスタック トレースを次に示します。
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
- locked <0x00007f522cbebca8> (a java.io.BufferedInputStream)
at java.io.DataInputStream.readInt(DataInputStream.java:387)
at util.network.BytesBasedSocketConnection$ReadConnectionRunnable.run(BytesBasedSocketConnection.java:287)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
アップデート:
EJPの回答について:
EOS は関与しておらず、接続は確立されていましたが、非常に遅かったです。
EOS があったとしても、コードが EOS でどのように回転するかはわかりません。値
for
によって制限されconstructLength
ます。それでも、提案された改善は有効です。問題のあるスタックトレースは、から継承された
DataInputStream
( ) で行われた読み取りで終了します。上記のコードを参照してください。、ないは欠落しています。ここには a が呼び出されており、これには独自のメソッドが定義されています。しかし、スタック トレースは途中で停止し、到達していません。なんで?(_socketDIS.read()
FilterInputStream.read()
DataInputStream
BufferedInputStream
read()
FilterInputStream.read()
in.read()
BufferedInputStream
read()
BufferedInputStream.read()