ハンドルリークのトラブルシューティングの経験を記録する(開いているファイルが多すぎる)

本日、お正月のランタンフェスティバルが終わり、サーバーログやメンテナンスを毎日監視していたので、大きな問題はありませんでした。しかし、旧正月の休暇中は日記が大きすぎました。毎日100万件のログを生成するのが普通ですが、年の半ばにサーバーをチェックしたところ、42Gのログがあり、オンライン機能も少し異常でした。緊張してすぐに起動しました。調査旅行。

1.サーバー
の異常ログをバックアップし、オンライン機能を復元します。Linuxシステムのcpコマンドを使用して、異常ログをコピーしてバックアップします。

cp [OPTION]... SOURCE... DIRECTORY

サーバープロセスを再起動すると、関数は通常に戻ります。

次に、ログを確認し、予備的なポジショニングを行います

機能が回復したら、異常の原因を探し始めます。異常ログが大きすぎてダウンロードが遅いため、splitコマンドを使用してログファイルを分割します。各ブロックのサイズは1Gです。しかし、1 Gはまだ非常に大きいので、最初の小さなブロックをもう一度分割します。各ブロックは100Mです。

split -b 100M mylog.txt

最後に、最初の100Mファイルをダウンロードして表示します。
最終的にダウンロードされたログは次のように表示されます。

java.net.SocketException: Too many open files
at sun.nio.ch.Net.socket0(Native Method)
at sun.nio.ch.Net.socket(Net.java:411)
at sun.nio.ch.DatagramChannelImpl.<init>(DatagramChannelImpl.java:142)
at sun.nio.ch.SelectorProviderImpl.openDatagramChannel(SelectorProviderImpl.java:46)
at java.nio.channels.DatagramChannel.open(DatagramChannel.java:182)
at lbms.plugins.mldht.kad.utils.AddressUtils.getDefaultRoute(AddressUtils.java:254)
at lbms.plugins.mldht.kad.RPCServerManager.startNewServers(RPCServerManager.java:147)
at lbms.plugins.mldht.kad.RPCServerManager.refresh(RPCServerManager.java:51)
at lbms.plugins.mldht.kad.DHT.update(DHT.java:929)
at lbms.plugins.mldht.kad.DHT.lambda$started$11(DHT.java:767)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

java.net.SocketException: Too many open files
at sun.nio.ch.Net.socket0(Native Method)
at sun.nio.ch.Net.socket(Net.java:411)
at sun.nio.ch.DatagramChannelImpl.<init>(DatagramChannelImpl.java:142)
at sun.nio.ch.SelectorProviderImpl.openDatagramChannel(SelectorProviderImpl.java:46)
at java.nio.channels.DatagramChannel.open(DatagramChannel.java:182)
at lbms.plugins.mldht.kad.utils.AddressUtils.getDefaultRoute(AddressUtils.java:254)
at lbms.plugins.mldht.kad.RPCServerManager.startNewServers(RPCServerManager.java:147)
at lbms.plugins.mldht.kad.RPCServerManager.refresh(RPCServerManager.java:51)
at lbms.plugins.mldht.kad.DHT.update(DHT.java:929)
at lbms.plugins.mldht.kad.DHT.lambda$started$11(DHT.java:767)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
...

上に示したように、java.net.SocketException:開いているファイルが多すぎる例外がループ内のログに継続的に書き込まれ、停止していません。そこで、主要なIT Webサイトで関連する問題を検索し、いくつかの解決策を試しました。
一般的な説明は次のとおり
です。Linuxシステムファイルハンドルが十分ではなく、使い果たされています。
オンラインプログラムによると、ulimit -aを使用してファイルハンドル構成ファイルをクエリし、永続的に変更すると、クエリの数は65535
ここに画像の説明を挿入
設定されます。これは機能するはずです

3.推測が漏れて推測を確認する
しかし、そうではありません。サーバーが1週間稼働し続けた後、例外が再び発生しました。
そこで、ハンドルの漏れが原因と思われるこの例外を再考し、このウェブサイトのアイデアに従ってチェックしました。
プログラムハンドルリークを検出するための統計的方法
プロンプトに従って、プロセスハンドルを監視するバックグラウンドプログラムがLinuxシステムに書き込まれ、監視します。
ここに画像の説明を挿入
次のコマンドは、プロセスが現在占有しているハンドルの数を照会します。

 ls -l /proc/进程ID/fd |wc -l 

600秒ごとにハンドル占有統計を設定し、1日待ってから、Excelテーブルを使用して割引傾向チャートを作成します。
ここに画像の説明を挿入
折れ線グラフから、ハンドルの漏れの原因であることがさらに確認されます。

4.漏れの場所を特定し、問題を解決します

ハンドルリークはプログラムが原因である必要があります。ハンドルは通常、ファイル、ソケット、またはその他を指します。ハンドルのリークは、Javaでのファイル操作フローが原因であるか、ソケットが閉じられていません。そのため、各設定ファイル操作の位置を何度も確認し、閉じられていない状況がないことを確認しました。
戦場をローカルIDEに転送し、Windowsタスクプロセスマネージャーを使用してデバッグし、各ビジネスを繰り返しテストし、ハンドルとスレッドの使用状況を観察します。
ウィンドウズタスクマネージャー
各事業を繰り返しテストする過程で、各事業の糸と柄の占有率は事業終了後に解放されます。事業は1つだけです。終了しても、占有されている糸とハンドルの数は解放されていません。したがって、このビジネスを再度詳細にテストし、JVMスタックコマンドを使用して各スレッドの使用状況を照会します。

	jstack -l 进程ID

このビジネスの終了後、次のように、多数のスレッドがまだRUNNABLE状態にあり、ソケットデータパケットを受信するために実行されていることがわかりました。
ここに画像の説明を挿入
これらのスレッドのプロンプトに従って、コードに戻り、最終的に、プロジェクトのビジネスロジックブランチプロセスにあることがわかりました。ランタイムオブジェクト実行タイムアウトの場合、シャットダウンプロセスが実行されなかったため、タイムアウトがあっても、このサービスを使用するプロセスで多くのユーザーが発生しました。フロントエンドはプロンプトを返しましたが、バックエンドは閉じてリサイクルされず、実行されています。

V.リークが解決されたことを確認します。
このパッチを適用し後、オンライン観測を再リリースし、折れ線グラフを描画します。
ここに画像の説明を挿入

ハンドルの占有率は600以内で安定しており、今回はハンドルリークの調査が終了しました。

6.まとめ
この経験を通して、私はコードを再賞賛しました。問題に遭遇することはひどいことではありません、そしてそれは徹底的な研究と少しずつによって解決することができます。
私の経験が、問題に遭遇した人々にトラブルシューティングのアイデアと参考資料を提供できることを願っています。

おすすめ

転載: blog.csdn.net/weixin_43901067/article/details/114113036