我在CentOS 6.4服务器上运行Java 7 Dropwizard应用程序,它基本上充当数据存储(Cassandra)之上的一个层,并进行一些额外的处理。它还有一个Zookeeper接口,使用Curator框架来处理其他一些东西。这一切都运行良好,大多数情况下,CPU和RAM负载从不超过50%,通常约为10%,我们的响应时间也很好。
我的问题是,最近我们发现偶尔我们会看到大约1-2秒的昙花一现,似乎所有通过线程池安排的任务都会被延迟。我们注意到了这一点,因为与Cassandra的连接超时和Zookeeper的会话超时。我们采取了哪些措施来缩小范围:
/proc/sys/kernel/threads-max
是190115,我们永远不会超过1000。#7代码(除了使用Socket和PrintWriter代替FileWriter外,#6相同):
public void start() throws IOException {
fileWriter = new FileWriter(this.fileName, false);
executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(this, 0, this.delayMillis, TimeUnit.MILLISECONDS);
}
@Override
public synchronized void run() {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date now = new Date();
String debugString = "ExecutorService test " + this.content + " : " + sdf.format(now) + "\n";
fileWriter.write(debugString);
fileWriter.flush();
} catch (Exception e) {
logger.error("Error running ExecutorService test: " + e.toString());
}
}
所以似乎Executor正在安排要运行的任务,但它们在启动时被延迟(因为时间戳被延迟而且{{1}的前两行没有办法try
方法中的块正在延迟任务执行)。关于什么可能导致我们可以尝试的这个或其他事情的任何想法?希望我们不会达到我们开始恢复代码的程度,直到找到导致它的变化为止......
TL; DR:计划任务正在延迟,我们不知道原因。
UPDATE 1:我们修改了执行程序任务,将每半秒的时间戳推送到环形缓冲区而不是直接输出到文件,然后每20秒转储一次缓冲区。这会删除I / O作为阻止任务执行的可能原因,但仍然提供相同的信息。从这一点开始,我们仍然看到了相同的时间戳模式,从中可以看出问题不是偶尔会阻塞下一次执行任务的任务,而是由于某种原因任务执行引擎本身会延迟执行。
答案 0 :(得分:2)
当您使用scheduleAtFixedRate
时,您表示希望您的任务尽可能接近该费率。遗嘱执行人将尽力保持,但有时却不能。
您使用Executors.newSingleThreadScheduledExecutor()
,因此执行程序只有一个线程可供使用。如果任务的每次执行花费的时间都超过了您在计划中指定的时间,那么执行程序将无法跟上,因为单个线程可能没有在执行中执行计划之前执行上一次运行下一次运行。结果将表现为计划的延迟。这似乎是一个合理的解释,因为你说你的真实代码是写入套接字。这可以很容易地阻止和发送你的时间。
您可以通过在run
方法的末尾添加更多日志记录(即在flush
之后)来确定是否确实如此。如果IO花费的时间太长,您会在日志中看到。
作为修复,您可以考虑使用scheduleWithFixedDelay
,这将在每次执行任务之间添加延迟,因此长时间运行的任务不会相互碰撞。如果失败了,那么你需要确保套接字写入按时完成,允许每个后续任务执行按计划开始。
答案 1 :(得分:0)
诊断活动问题的第一步通常是在系统停止时进行线程转储,并检查线程正在做什么。在您的情况下,执行程序线程将是特别感兴趣的。他们正在处理,还是在等待工作?
如果它们都在处理,则执行程序服务已耗尽工作线程,并且只能在当前任务完成后安排新任务。这可能是由于任务暂时需要更长时间才能完成。工作线程的堆栈跟踪可能会产生线索 需要更长的时间。
如果许多工作线程处于空闲状态,那么您在JDK中发现了一个错误。恭喜!