1. ホーム
  2. ジャワ

IOException Broken pipe Solution ClientAbortException: java.io.

2022-02-22 02:03:13

    今日、会社のサポートから、あるお客様のサービスがうまくいかないと報告があったので、問い合わせをしました。

    データを取得したtomcatのログを見る。 まずログの最後までスクロールするのが通例です 例外が印刷されていないか確認するために、案の定、いくつかの例外メッセージが見つかりましたが、中でもこのメッセージは

24-Nov-2016 09:54:21.116 SEVERE [http-nio-8081-Acceptor-0] org.apache.tomcat.util.net.NioEndpoint$Acceptor.run Socket accept failed
 java.io.IOException: Too many open files
	at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:241)
	at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:688)
	at java.lang.Thread.run(Thread.java:745)

    問題は明白で、ファイル記述子が限界を超えているため、ファイルを開いたり、ネットワーク接続を作成したりすることができず、その結果、他の問題を引き起こすことになります。

[root@sdfassd logs]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 62819
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 65535
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 62819
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

     開いているファイルは65535ですが、最適化されています。tomcatなどのサービスを先に起動してから、ulimitを最適化したのでしょうか?可能性があります。その場合、サービスを再起動すればOKなので、すべてのサービスを再起動したところ、問題なく動作し、レポートにもあっという間にデータが表示され、サポートに問題が解決したことを伝え、他の案件に取り掛かりました。

    その結果、20分もしないうちにテクニカルサポートから「レポートにまたデータがない」と言われ、データ収集アプリケーションのtomcatログを再度調べると、例外がたくさん見つかり、すべて1つのエラーで終わってしまいました。

24-Nov-2016 09:54:24.574 WARNING [http-nio-18088-exec-699] org.apache.catalina.core.StandardHostValve.throwable Exception Processing ErrorPage[exceptionType=java.lang.Throwable, location=/views/error/500.jsp]
 ClientAbortException: java.io.IOException: Broken pipe
	at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:393)
	at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:426)
	at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:342)
	at org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:295)
	at org.apache.catalina.connector.Response.finishResponse(Response.java:453)
	at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:378)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
	at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)



    この例外は非常に多く、エラーメッセージを見て、書き込み操作の実行でtomcatのコネクタは、ブロークン管の例外が発生したときに、コネクタは、ネットワーク要求を処理するtomcatですが、そこにネットワークの問題は、なぜ例外が発生した書かれている、問題で読んでそれではないでしょう?ネットワークの問題かどうかを判断するために、私はローカルでサーバー上のインターフェイスにアクセスするwgetコマンドを使用して、長い時間待っても応答がないことがわかったが、通常の状況下ですぐに応答があるはずです、それはネットワークではなく、サーバーの問題であることを意味します。

[root@sdfassd logs]# netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
CLOSE_WAIT 3853
TIME_WAIT 40
ESTABLISHED 285
LAST_ACT 6




    CLOSE_WAITの状態は、クライアントが最初に接続を閉じていることを意味し、正常ではない3853接続を持って、サーバー側は、サーバー側の結果、接続を閉じるには操作を実行しませんでしたCLOSE_WAITの状態で維持されている、オペレーティングシステムの最適化を行うにはない場合keepalive、この状態はデフォルトで2時間、システムをチェック維持されますサーバー側は、CLOSE_WAIT状態に滞在するサーバー側の原因シャットダウン操作を行っていないことです。

[root@sdfassd logs]# sysctl -a |grep keepalive
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75

    確かに7200秒でした。これで、最初にtomcatのログをチェックしたときに最後のエラーが "オープンファイルが多すぎる" だった理由がわかりました。close_wait 状態が2時間急増したために、ファイル記述子の上限65535を越えてしまったのでしょう。

    そしてこの状態は、パイプ切れ例外の結果であるはずですが、パイプ切れ例外の原因は何だったのでしょうか?なぜプローブは接続を閉じたのに、データ収集サーバーは接続を閉じなかったのでしょうか?この例外はtomcatのコネクタから報告されており、tomcatがcloseメソッドを呼び出して接続を閉じるのを忘れるということは考えにくいので、プログラムを除外した結果、何が原因なのかがわかりません。

    そこで、データを収集サーバーにアップロードするプローブのログを見てみると、大量の例外が発生していました。

2016-11-24 16:27:36,217 [TingYun Harvest Service 1] 166 WARN - Error occurred sending metric data to TingYun. there can be intermittent connection Please wait for a short period of time: java.net.SocketTimeoutException: Read timed out
SocketTimeoutException: Read timed out
	at java.net.SocketInputStream.socketRead0(Native Method) ~[na:1.7.0_60]
	at java.net.SocketInputStream.read(SocketInputStream.java:152) ~[na:1.7.0_60]
	at java.net.SocketInputStream.read(SocketInputStream.java:122) ~[na:1.7.0_60]
	at com.tingyun.agent.libs.org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SourceFile:136) ~[tingyun-agent-java.jar:2.1.3]
        .................


    どちらもタイムアウト例外を読んでいるので、問題は明確です、プローブ側は、タイムアウト、切断を読んで、この時点でデータ収集サーバーはまだリクエストを処理している、それはプローブ側が切断されていることを知らない、リクエストを処理し、プローブに処理結果を送信する、壊れたパイプ。

<スパン     クライアントの読み込みタイムアウトで接続が閉じられ、サーバー側がクライアントの切断された接続にデータを書き込んでしまい、パイプ切れ例外が発生したということが判明しました

    プローブの読み取りタイムアウトは2分でしたが、なぜこんなに長い時間サーバーが応答しないのでしょうか?そこで、jstackコマンドを使って、tomcatのスレッドスタック情報をエクスポートして解析してみたところ、最終的に、コードの中にロックを追加する時間のかかる操作があり、それが原因でスレッドがブロックされていることが分かりました(機密保持のため、ここではコードを掲載しません)。

ここに要約すると、私にプライベートメッセージを送った私の友人の一部は、タイムアウトだけでなく、ブロークンPipleの問題のポイントを取得していない限り、接続が切断され、切断接続に書き込み操作を実行するには、この例外が発生します、クライアントのタイムアウトは、唯一の事件の一つである。

また、あなたは"Too manayオープンファイル"例外を見たとき、ulimitシステムの制限をチェックするだけでなく、プロセスによって開かれたファイルハンドルの数を見て、システムハンドルの合計数、現在のアプリケーションls -l /proc/< を使用してオープンファイルハンドルの数を見て猫 /proc/sys/fs/file-nr コマンドべきである。 pid>/fd | wc -l コマンドを使用すると、このステップを無視するのは良いことです、さもなければ、システムの本当の問題を見つけるためにもう少し時間がかかったかもしれません。

このケースは、問題をトラブルシューティングするとき、場合によっては、最初に見た例外が問題の根本ではなく、その後の何らかの連鎖反応かもしれないことを示しています。特に同じ例外がたくさんある場合、最後の例外ログを見るのではなく、まずログの内側を見て、例外が発生した最初の場所を探し、例外が発生する前にシステムがどうだったかを確認すべきなのです。

Java の tcp/ip 例外

  • 1 java.net.SocketTimeoutException . 

この例外は、より一般的なもので、ソケットタイムアウトです。一般的にこれが投げられる場所は2つあり、1つは接続時で、connect(SocketAddress endpoint,int timeout)で後者がタイムアウトのパラメータを決定し、もう1つはsetSoTimeout(int timeout)で読み込み時のタイムアウトを設定するものである。どちらも0を指定することで無限大を表します。

  • 2 java.net.BindException:Address already in use: JVM_Bind 

この例外は、サーバー側で新規に ServerSocket(port) または socket.bind(SocketAddress bindpoint) 操作を行ったときに発生します。

原因:ポートのようなポートが起動し、リッスン中である。この場合、netstat -anコマンドでListending状態のポートを確認します。問題の解決には、占有されていないポートを探せばよい。

  • 3 java.net.ConnectException: 接続が拒否されました: 接続

この例外は、クライアントが new socket(ip, port) または socket.connect(address, timeout) を実行したときに、指定した ip アドレスのマシンが見つからない (つまり、現在のマシンから指定した ip へのルートがない) か、ip は存在するが指定したポートで listen できるものが見つからないために発生するものです。まず、クライアントのipとポートの書き方が間違っていないか確認し、正しい場合はクライアントからサーバーにpingを打って、pingが通るかどうか確認し、通れば(サービスのサーバー側がpingを無効にする場合は別の対処が必要)、サーバー側で指定したポートをリッスンするプログラムが起動するかどうか確認する必要があります。

  • 4 java.net.SocketException: ソケットが閉じられました 

この例外は、クライアントとサーバーの両方で発生する可能性があります。例外が発生する理由は、積極的に接続を閉じ(ソケットのcloseメソッドを呼び出す)、その後、ネットワーク接続に対して読み取りと書き込みを行ったからです。

  • 5 java.net.SocketException: 接続リセットまたは相手による接続リセット:ソケット書き込みエラー

接続相手による接続のリセットは、書き込みまたは読み出しのいずれかが呼び出されたときに発生します。glibcによると、リモートマシンのリブートや回復不能なプロトコル違反などによるもので、文字通りリモートマシンがリブートしたか、回復不能なエラーが発生したことを意味します。私のテストでは、現在のところ、相手側でプロセスが直接killされたときのみ発生します。この2つのケースの違いは何でしょうか?tcpdumpのパケットインターセプトと比較すると、リモート側のプロセスを直接killした場合は、相手側にパイプを閉じたことを伝えるためにFIN番号を送らず、直接RST番号を送りますが、リモート側がcloseやshutdownを呼んだ場合はFIN番号を送ります。TCPの4つの波動によれば、シーケンス番号のFINが必要なのだそうです。個人的な推測ですが、ローカルエンドが相手側のFIN番号を受信せず、直接RST番号を受信した場合、相手側でマシンの再起動や回復不能なプロトコル違反があったことを示し、このパイプでのIO操作はピアエラーでコネクションリセットされるのではないでしょうか?

1つ目は、ソケットの一方の端が(能動的に、または異常終了によって)閉じられ、もう一方の端がまだデータを送信している場合、最初に送信したパケットで例外(Connect reset by peer)を発生させます。もう1つは、一方の端が終了したが、終了時に接続が閉じられておらず、他方の端が接続からデータを読み出している場合に例外を発生させるものです(Connection reset)。簡単に言えば、接続が切れた後の読み書きの操作で発生するものです。

また、一方の端がRSTパケットを送信してTCP接続を切断した場合、もう一方の端もこの例外を投げるケースがあり、tomcatの場合、以下のようになります。

org.apache.catalina.connector.ClientAbortException: java.io.IOException。ピアによる接続のリセット

Aliのtcp方式によるヘルスチェックでは、パフォーマンスを向上させるためにwavingインタラクションを保存し、接続を終了するために直接RSTを送信すると、サーバー側でこの例外が発生します。

サーバーの場合、一般的な理由としては、以下のように考えられます。

a) サーバが処理できる以上の同時接続があり、サーバがそれらの接続のいくつかを積極的にシャットダウンしている。

b) データ転送の途中で、サーバーからクライアントへのデータ送信中に、ブラウザまたは受信側のクライアントがシャットダウンしてしまう。

  • 6 java.net.SocketException: 壊れたパイプ

より詳細なリンクはこちら https://www.cnblogs.com/metoy/p/6565486.html

この例外は、クライアントとサーバーの両方で発生する可能性があります。SocketExcepton:Connect reset by peer:Socket write エラーがスローされた後、データの書き込みが継続された場合にスローされます。最初の2つの例外に対する解決策は、まず、プログラムが終了する前にすべてのネットワーク接続を閉じるようにすること、次に、相手側が接続を閉じたときにそれを検出して、接続自体を閉じるようにすることです。

broken pipeはwriteが呼ばれたときのみ発生します。broken pipeは相手側のパイプが壊れていることを意味し、リモート側がread/writeパイプを閉じてしまって読み書きができなくなったときによく発生します。このままパイプにデータを書き込むと、初めて、リモート側からRST信号が送られてきます。パイプにデータを書き続けると、OSはSIGPIPE信号を送り、errnoに壊れたパイプ(32)を設定します。パイプ(32)は、あなたのプログラムがデフォルトでSIGPIPEを処理しない場合、プログラムはブレークして終了します。一般的には シグナル(SIGPIPE,SIG_IGN) このシグナルを無視した場合、プログラムは終了しませんが、writeは-1を返し、errnoにBroken pipe (32)をセットします。broken pipeは、相手側の閉じたパイプに書き込む場合のみ発生します(相手側のRST番号を受け取った後の最初の書き込みは、broken pipeではなく、writeは-1を返します)。この時点で正しいのはパイプも閉じることで、そのまま書き込みを続けるとこのエラーになる)。

java.net.SocketException: Broken pipe (Write failed)
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
        at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:431)
        at sun.security.ssl.OutputRecord.write(OutputRecord.java:417)
        at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:886)
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:857)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
        at org.apache.http.impl.io.SessionOutputBufferImpl.streamWrite(SessionOutputBufferImpl.java:124)
        at org.apache.http.impl.io.SessionOutputBufferImpl.write(SessionOutputBufferImpl.java:160)
        at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:113)
        at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:120)
        at org.apache.http.entity.StringEntity.writeTo(StringEntity.java:167)
        at org.apache.http.impl.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:156)
        at org.apache.http.impl.conn.CPoolProxy.sendRequestEntity(CPoolProxy.java:160)
        at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:238)
        at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123)
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
        at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)

ケース4と5の例外については、接続の維持に特別な注意を払う必要があります。短い接続の場合はいいのですが、長い接続の場合、接続状態が適切に維持されていないと、非常に簡単に例外が発生します。基本的に長い接続の場合に必要なことは

a) アクティブな切断を検出する(相手側がソケットのcloseメソッドを呼び出したとき)。相手側がアクティブに切断しているため、相手側が読み込み中であれば戻り値は-1なので、切断を検出したら、アクティブに接続を閉じる(ソケットのcloseメソッドを呼び出す)。

b) 相手側のダウンタイム、異常終了、ネットワーク障害の検出は、一般にハートビート検出で行われる。双方は、定期的に相手側にデータを送信し、また、他の側から&quot;ハートビートデータ&quotを受信します。いくつかの連続したサイクルは、ハートビートの相手側を受信していない場合は、他の側またはダウンタイムまたは異常終了またはネットワーク障害を決定することができ、あなたも自分の接続を閉じるには主導権を握る必要がある、クライアントが一定の遅延後に接続を再インチすることができます場合。クライアントは、一定の遅延後に接続を再初期化することができる場合。ソケットには接続を維持するキープアライブというオプションがありますが、このオプションを使うと、相手側のダウン、異常終了、ネットワーク障害が判明するまでに通常2時間かかります。

  • 7 java.net.SocketException: あまりにも多くのファイルが開かれています。

原因 オペレーティングシステムのオープンファイルハンドルの最大数は制限されています。これは、多くの同時アクセスユーザーがサーバーにアクセスする場合によく起こります。アプリケーションサーバーは、各ユーザーのアプリケーションを実行するために多くのファイルをロードする必要があるため(新しいソケットにはファイルハンドルが必要)、オープンファイルハンドルが不足する結果になります。

解決方法

a) クラスをjarパッケージとしてパッケージングしてみてください。jarパッケージは1つのファイルハンドルしか消費しませんが、そうでなければ、クラスは1つのファイルハンドルを消費します。

b) javaのGCは、ネットワーク接続によって開かれたファイルハンドルを閉じることができません。close()が実行されないと、そのファイルハンドルは常に存在し、閉じることができません。

また、この問題を抑制するために、オープンソケットの最大数を設定することも検討できます。ファイルハンドルの最大数を増やすために、オペレーティングシステムを何とかしてください。

ulimit -a でシステムの現在のリソース制限を確認し、ulimit -n 10240 で変更します。これは、現在のウィンドウに対してのみ機能します。

  • 要求されたアドレスが割り当てられない                                    

<スパン 1.  <スパン ポート番号が占有されているため、アドレスのバインドができない。

java.net.BindException: 要求されたアドレスを割り当てることができません: bind: が原因です。 によるIPアドレスの変更

<スパン 2. サーバーのネットワーク構成の異常。

etc/hostsに設定されているアドレスが正しくありません。

3. また、ループアドレスの設定ファイルがないため、ipconfigがループアドレスを発見しないケースもあります。