可能的原因
以下问题通常会表现出非常相似的症状(您的程序:
诊断工具
开发者机器上的调试器
死锁和类似问题通常很难重现,因此无法使用调试器轻松分析。该问题通常发生在实时系统上,而不是开发人员机器上。原因可能是不同的工作负载、不同的数据星座甚至不同的操作系统或不同的硬件(更多 CPU 内核、NUMA architecture 等)
远程调试器
您可以尝试使用remote debugger 附加到生产系统。仅当您可能冒生产机器完全停止的风险时(例如,由于 HVM 崩溃!),您才应该这样做。您应该只在一对调试会话中执行此操作,并与同行讨论每个步骤。
记录和可视化
使用过多的日志记录并将日志数据可视化(R Studio、Mathematica 等)。请注意,日志记录可能会更改您的系统。朴素的日志记录会根据性能和额外的日志记录来改变你的实时系统。尝试asynchronous logging 并在将其部署到实时系统之前测试日志记录的性能影响。计划您希望如何可视化您的日志数据,以及对于上述不同的可能原因您希望看到的内容。否则,您可能会错过可以帮助您显示根本原因的一条日志语句。
REPL
通过引入“命令行”(REPL) 来查询您的实时系统。通过向您的实时系统添加命令行,您可以对其进行查询并更改其部分内容以诊断根本原因。您可以使用Clojure REPL、Scala SBT REPL、Bean shell 或使用JRebel 与外部触发器一起添加实时更改以运行交换的代码(WebService、调度程序、消息队列等)。成对工作(在运行之前讨论每个命令)并记住保护 REPL 免受外部访问(在 localhost 或 Unix 套接字上绑定,使用命名管道,仔细检查你的防火墙,使用公钥授权,记录每个访问特殊日志等)!
JMX
通常,您可以使用 Java 管理扩展 (JMX) 连接到正在运行的 Java VM。使用JConsole 或Java Visual VM,您可以检查每个线程的当前堆栈跟踪,并且可以搜索死锁。此外,您可以在应用程序中部署自己的传感器。使用DTrace(当您的系统支持此功能时,例如 Solaris、FreeBSD、NetBSD、Mac OS X),您甚至可以监控操作系统的某些部分。
您可以通过提供MBeans 或MXBeans(更严格的输入,更好的兼容性)来添加自己的传感器。
诊断
死锁
JConsole 和 VisualVM 都具有查找死锁并显示死锁所涉及的线程的功能。结合显示每个线程的当前堆栈跟踪的功能,诊断死锁变得轻而易举。
活锁和资源匮乏
当您在工作人员中添加计数器时,当工作人员获得锁并且工作人员已成功取得实际进展时,计数器会增加,很容易发现您的应用程序是否取得进展,或者哪些工作人员只是在处理周围的资源而没有实现任何目标。
您可以使用远程调试器、JMX(如果添加传感器)、REPL 或添加相应的日志消息来查询计数器。使用 REPL 或通过替换实时系统中的代码,您可以在需要时引入计数器、日志消息或 JMX 传感器。
交换或操作系统过载
使用 JMX 和 DTrace,您可以分析操作系统的各个部分。使用 REPL,您可能能够从正在运行的进程中获取 OS 和 JVM 统计信息。使用日志语句或自定义 JMX 传感器,您可以监控应用程序的性能指标。
衡量应用程序运行良好时的性能至关重要,因此您有一些基准值。否则您将无法判断测量值是否正常或是否表明存在问题。