很高兴看到您正在使用 jHiccup,并且它似乎显示了基于现实的打嗝。
jHiccup 观察到运行在 JVM 上的应用程序线程也会看到的“打嗝”。它没有收集原因 - 只是报告事实。原因可能是任何会导致进程无法运行完全准备好运行的代码的原因:GC 暂停是常见原因,但键盘上的临时 ^Z 或跨虚拟主机的“实时迁移”事件之一将是也观察到了.. 有多种可能的原因,包括操作系统或管理程序级别的调度压力(如果存在)、电源管理的疯狂、交换以及许多其他原因。我已经看到 Linux 文件系统压力和透明大页面“背景”碎片整理也会导致多秒的打嗝......
隔离暂停原因的第一步是使用 jHiccup 中的“-c”选项:它启动一个单独的控制进程(具有其他空闲工作负载)。如果您的应用程序和控制进程都显示大小和时间大致相关的打嗝,您就会知道您正在寻找系统级别(而不是进程本地)的原因。如果它们不相关,你就会怀疑你的 JVM 内部——这很可能表明你的 JVM 暂停了一些大事;GC 或其他东西,如锁去偏或类加载派生去优化,如果由于某种原因到达安全点的时间很长(并且在大多数 JVM,有很多可能的原因导致很长一段时间到达安全点)。
jHiccup 的测量非常简单,很难出错。整个东西不到650行java代码,大家可以自己看逻辑。jHiccup 的 HiccupRecorder 线程反复休眠 1 毫秒,当它醒来时,它会记录任何大于 1 毫秒的时间差(从休眠前开始)作为打嗝。一个简单的假设是,如果一个准备运行的线程(HiccupRecorder)没有运行 5 秒,同一进程中的其他线程也会看到类似大小的打嗝。
正如您在上面提到的,jHiccups 观察结果似乎在您的独立网络日志中得到证实,您在其中看到了 5 秒的响应时间,请注意,网络日志不会观察到所有的打嗝,因为只有在打嗝期间实际发出的请求才会有被网络记录器观察到。相比之下,没有大于 ~1 毫秒的打嗝可以隐藏 jHiccup,因为即使没有其他活动,它也会每秒尝试唤醒 1,000 次。
这可能不是 GC,但在您排除 GC 之前,我建议您多查看 GC 日志记录。首先,将暂停时间限制为 200 毫秒的 JVM 提示在所有已知的 JVM 上都是无用的。暂停提示相当于说“请”。此外,不要相信您的 GC 日志,除非您在选项中包含 -XX:+PrintGCApplicationStoppedTime (并且即使在那时也怀疑它们)。除非您包含此标志,否则有些停顿和部分停顿可能会很长并且未报告。例如,我看到偶尔长时间运行的计数循环需要 15 秒才能达到安全点而导致的暂停,其中 GC 仅报告暂停的 0.08 秒部分,它实际上做了一些工作。还有很多暂停的原因不被认为是“GC”的一部分
——吉尔。[jHiccup的作者]