JAvaスレッドプールモニタリング
4451 ワード
の原因となる
最近会社の基礎発表プラットフォームを完備する時、1つのスレッドを使っていくつかの非同期の事をして、開発環境とテスト環境の検証に何の問題もありませんが、プログラムが生産運行してしばらくの間、自分の望む結果が得られていないことを発見して、これのために長いバグの道を調査して、いくつかのスレッドを使ったため、しかし、実際にはこれらのスレッドを十分に監視していないので、問題を調査する際にも困難な障害を経験しています.
元のコード
最近会社の基礎発表プラットフォームを完備する時、1つのスレッドを使っていくつかの非同期の事をして、開発環境とテスト環境の検証に何の問題もありませんが、プログラムが生産運行してしばらくの間、自分の望む結果が得られていないことを発見して、これのために長いバグの道を調査して、いくつかのスレッドを使ったため、しかし、実際にはこれらのスレッドを十分に監視していないので、問題を調査する際にも困難な障害を経験しています.
元のコード
protected ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
/**
* jenkins
*/
public void threadASyncAppJenkinsStatus() {
executorService.scheduleAtFixedRate(() -> {
ListarchitectureApps = architectureAppMapper.listArchitectureApp();
architectureApps.parallelStream().forEach(architectureApp -> syncJenkinsBuild(architectureApp.getName(), ArchitectureType.APP));
}, 0, 6, TimeUnit.SECONDS);
}
/**
* jenkins
*/
public void syncComponentJenkinsStatus() {
executorService.scheduleAtFixedRate(() -> {
ListarchitectureComponents = architectureComponentMapper.listArchitectureComponent();
architectureComponents.parallelStream().forEach(architectureComponent -> syncJenkinsBuild(architectureComponent.getName(), ArchitectureType.COMPONENT));
}, 0, 6, TimeUnit.SECONDS);
}
これは一部のコードで、簡単なことをして、プログラムは6 sおきにコンポーネントとアプリケーションの状態をポーリングして、それから後でwebsocketを通じてフロントエンドページに同期します.これは簡単なコードで、このコードが間違っている可能性があるとは想像しにくい.しかし、予想に反して、開発とテスト環境のテストを通じて、生産まで2日間実行したところ、フロントエンドページのjenkins状態が同期していないことが分かった.ログを見ることで、問題がどこにあるかを観察することができないので、別の方法を探すしかありません.
ExecutorsMonitorスレッド監視クラス
スレッドプールの監視機能を実現し、リアルタイムでスレッドプールの使用情報をログに印刷することができ、問題のトラブルシューティング、システムのチューニングを容易にするスレッドプールツールクラスを開発しました.具体的なコードは以下の通りです.@Slf4j class ExecutorsMonitor extends ScheduledThreadPoolExecutor { private ConcurrentHashMap
startTimes; private String poolName; /** * , HashMap * * @param corePoolSize * @param poolName */ public ExecutorsMonitor(int corePoolSize, String poolName) { super(corePoolSize); this.startTimes = new ConcurrentHashMap<>(); this.poolName = poolName; } /** * ( ), */ @Override public void shutdown() { super.shutdown(); } /** * , */ @Override public List shutdownNow() { return super.shutdownNow(); } /** * , */ @Override protected void beforeExecute(Thread t, Runnable r) { startTimes.put(String.valueOf(r.hashCode()), new Date()); } /** * , */ @Override protected void afterExecute(Runnable r, Throwable t) { Date startDate = startTimes.remove(String.valueOf(r.hashCode())); Date finishDate = new Date(); long diff = finishDate.getTime() - startDate.getTime(); // 、 、 、 、 、 、 、 、 、 、 、 log.info(String.format(this.poolName + "-pool-monitor: Duration: %d ms, PoolSize: %d, CorePoolSize: %d, Active: %d, Completed: %d, Task: %d, Queue: %d, LargestPoolSize: %d, MaximumPoolSize: %d, KeepAliveTime: %d, isShutdown: %s, isTerminated: %s", diff, this.getPoolSize(), this.getCorePoolSize(), this.getActiveCount(), this.getCompletedTaskCount(), this.getTaskCount(), this.getQueue().size(), this.getLargestPoolSize(), this.getMaximumPoolSize(), this.getKeepAliveTime(TimeUnit.MILLISECONDS), this.isShutdown(), this.isTerminated())); } public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, String poolName) { return new ExecutorsMonitor(corePoolSize, poolName); } }
その後、生産がやっと問題を特定し、スレッドの内部が停止したことを発見し、同時に発見されたのは間違いで、資料を調べたところ、スレッドに異常が発生した後、退出し、try catchを通じてこの問題をよく解決した.