我有一个并行运行的java应用程序,它消耗大量日志文件并应用一些自定义逻辑。使用“即发即弃”方法在单独的线程中处理每个日志行。
然而,有时java进程只是停止处理,我的意思是java应用程序没有被分配CPU来执行进程,即使应用程序仍然没有完成使用该文件。
运行 top 考虑到我拥有16个核心,我的平均负载相当低:
运行 vmstat 我可以看到非用户进程既没有运行内核进程,也没有运行99%
iostat 的输出显示我没有正在运行的待处理IO任务:
我还没有发现线程转储的任何死锁或饥饿。大多数线程都是WAITING或RUNNABLE。
我错过了什么?我迷路了,而且我不知道在哪里进一步调查。
= UPDATE =
这是启动并行执行的部分,此后有数千行代码应用修改包括。 elasticsearch,akka等
所以我真的不知道可能会导致任何麻烦的相关代码是什么。
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(100);
ExecutorService executorService = new MetricsThreadPoolExecutor(numThreadCore, numThreadCore, idleTime, TimeUnit.SECONDS, workQueue, new ThreadPoolExecutor.AbortPolicy(), "process.concurrent", metrics);
FileInputStream fileStream = new FileInputStream(file);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new GZIPInputStream(fileStream));
String strRow = bufferedReader.readLine();
while (strRow != null) {
final Row row = new Row(strRow);
try {
executorService.submit(new Runnable() {
@Override
public void run() {
if (!StringUtil.isBlank(row.getLine())) {
processor.process(row);
}
}
});
strRow = bufferedReader.readLine();
} catch (RejectedExecutionException ree) {
try {
logger.warn(ree.getMessage());
Thread.sleep(50L);
} catch (InterruptedException ie) {
logger.warn("Wait interrupted", ie);
}
}
答案 0 :(得分:1)
然而,有时java进程只是停止处理,我的意思是java应用程序没有被分配CPU来执行进程,即使应用程序仍然没有完成使用该文件。
不要在CPU / vmstat / iostat级别考虑这个问题。这只是混淆了问题的调试。您应该仅考虑线程,并相信操作系统可以适当地安排它们。
我认为没有理由在提交所有行进行处理后主线程不能完成。顺便说一句,您可能只想阻止生成器,而不是像您正在做的那样重新生成旋转/睡眠循环中的行。请参阅:RejectedExecutionException free threads but full queue
如果应用程序未完成,则处理行时可能会挂起其中一个工作线程,或者MetricsThreadPoolExecutor
尚未关闭。我怀疑后者。生成器线程退出while (strRow != null) {
循环后应调用executorService.shutdown()
。否则,线程将等待添加更多行。
您可以在应用程序上执行线程转储,以查看它是否卡在了工作程序中。您可以在生产者线程完成时添加日志记录,这可以让您知道它是否完成了它的工作。两者都可能有助于找出问题所在。