对于不应暂停超过 200 毫秒的软实时系统的上下文,我们正在寻找一种在 Full GC 迫在眉睫之前发出预警的方法。我们意识到我们可能无法避免它,但我们希望在系统停止之前故障转移到另一个节点。
我们已经能够提出一个方案,在即将到来的完全 GC 之前为我们提供预先警告,这可能会导致系统停顿几秒钟(我们需要避免这种情况)。
我们能够提出的依赖于 CMS 空闲列表统计信息:-XX:PrintFLSStatistics=1
. 这会在每个 GC 周期(包括年轻 GC)之后将空闲列表统计信息打印到 GC 日志中,因此该信息在很短的时间间隔内可用,并且在内存分配率较高的时间间隔内会更频繁地出现。就性能而言,它可能会花费一些成本,但我们的工作假设是我们可以负担得起。
日志的输出如下所示:
Statistics for BinaryTreeDictionary:
------------------------------------
Total Free Space: 382153298
Max Chunk Size: 382064598
Number of Blocks: 28
Av. Block Size: 13648332
Tree Height: 8
特别是,最大空闲块大小为 382064598 个字。对于 64 位字,这应该刚好低于 2915MB。这个数字一直在非常缓慢地下降,以大约每小时 1MB 的速度下降。
我们的理解是,只要最大空闲块大小大于年轻代(假设没有巨大的对象分配),每个对象提升都应该成功。
最近,我们进行了为期数天的压力测试,发现 CMS 能够将最大块大小保持在旧区域总空间的 94% 以上。最大空闲块大小似乎以小于 1MB/小时的速度减少,这应该没问题——据此我们不会很快达到完全 GC,并且服务器可能会因维护而停机比完全 GC 更频繁地发生。
在之前的测试中,在系统内存效率较低的时候,我们已经能够运行系统长达 10 个小时。在第一个小时内,最大空闲块大小已降至 100MB,并保持了 8 多个小时。在运行的最后 40 分钟内,最大空闲块大小以稳定的速度减少到 0,此时发生了完整的 GC——这非常令人鼓舞,因为对于那个工作负载,我们似乎能够提前 40 分钟警告(当块大小开始稳步下降到 0 时)。
我的问题是:假设这一切都反映了长时间的峰值工作量(生产中任何给定时间点的工作量只会更低),这听起来像是一种有效的方法吗?您认为我们应该能够从 GC 日志中获得最大空闲块大小统计信息的可靠性到什么程度?
我们绝对愿意接受建议,但要求它们仅限于 HotSpot 上可用的解决方案(至少目前对我们来说没有 Azul)。此外,G1 本身并不是解决方案,除非我们能提出一个类似的指标,在 Full GC 或任何显着超过我们 SLA 的 GC 之前给我们提前警告(这些情况偶尔会发生)。