使用OpenJDK8进行垃圾收集设置

时间:2018-05-10 00:27:33

标签: java docker garbage-collection spring-data-jpa spring-integration

我需要帮助调整我们的一个微服务。

我们在OpenJDK8容器中的jetty服务器上运行基于Spring的微服务(Spring Integration,Spring Data JPA)。我们也使用Mesosphere作为我们的集装箱编排平台。

应用程序使用来自IBM MQ的消息,进行一些处理,然后将处理后的输出存储在Oracle DB中。

我们注意到,在 5月2日的某个时刻,队列处理从我们的应用程序停止了。我们的MQ团队仍然可以看到队列中存在打开的连接,但应用程序只是不再读取了。它并没有完全死亡,因为DCOS击中的healthCheck Api仍显示健康。

enter image description here 我们使用AppD进行性能监控,我们可以看到在同一天完成了垃圾收集,从那里应用程序从未从队列中获取消息。上图显示了在不同日期执行GC所花费的时间。

作为Java Opts的一部分,我们使用它来运行我们声明的应用程序

-Xmx1024m

每个微服务的Mesosphere预留如下所示

enter image description here

有人可以指出我正确的方向为我的应用程序配置垃圾收集的正确设置。

此外,如果您认为GC只是一个症状,感谢您分享您对我应该寻找的潜在缺陷的看法。

干杯 克里斯

4 个答案:

答案 0 :(得分:0)

您应该检查您的代码。

GC操作将触发STW(停止世界)操作,该操作将阻止代码中创建的所有线程。但是STW不会影响代码运行状态。

但如果你使用System.currentTimeMillis来控制你的代码运行逻辑,那么gc会影响你的代码逻辑。

gc操作也会影响非强引用,如果你使用WeakReference,SoftReference,WeakHashMap,在完整的gc之后,这些组件可能会改变它们的行为。

完成了一个完整的gc操作,释放内存并且允许你的代码分配新的对象,你的代码将抛出一个“OutOfMembryException”#39;' OutOfMembryException'这会中断你的代码执行。

我认为你现在应该做的事情是:

首先,检查“GC原因”,确定System.gc()来电或Allocate failed中是否发生了完整的gc。

然后,如果GC原因为System.gc(),您应该检查代码中使用的非强引用。

最后,如果GC原因为Allocate failed,您应该检查日志以确定代码中出现OutOfMembryException的天气,如果发生,您应该分配更多内存以避免{{1} }。

作为建议,您不应该将mq消息保留在微服务应用程序内存中。最重要的是,gc问题的根源在你的代码中是不好的做法。

答案 1 :(得分:0)

我不认为此处的垃圾收集存在问题,或者您应该尝试通过调整GC参数来解决此问题。

我认为这是两件事之一:

  1. 巧合。相关(对于单个数据点)并不意味着因果关系。

  2. 有关垃圾收集或触发垃圾收集的事件导致应用程序出现问题。

  3. 对于后者,有许多可能性。但需要注意的是某些东西(例如请求)导致应用程序线程分配一个非常大的对象。这触发了一个完整的GC,试图寻找空间。 GC失败了;即在GC做到最好之后仍然没有足够的空间。然后变成了一个杀死线程的OOME。

    如果被OOME杀死的(假设的)线程对于操作应用程序至关重要,并且应用程序的其余部分没有注意到"它已经死了,那么整个申请就会破裂。

    寻找的一个线索是线程死亡时记录的OOME。但也有可能(如果没有正确编写/配置应用程序)OOME不会出现在日志中。

答案 2 :(得分:0)

关于ApppD图表?这是几秒钟的时间吗?你有多少个全GC?也许你应该为垃圾收集器启用日志。

答案 3 :(得分:0)

我刚看到你对CPU的评论

  

将CPU分配从0.5 CPU增加到1.25 CPU

请记住,为了执行并行GC,您至少需要两个核心。我认为使用您的配置您正在使用串行收集器,并且当您可以利用多个核心时,没有理由使用串行垃圾收集器。您是否考虑尝试至少两个核心?在生产和性能方面,我经常使用四个作为应用服务器的最小数量。

您可以在此处查看更多信息:

  

在具有N个大于8的N个硬件线程的机器上,并行收集器使用N的固定分数作为垃圾收集器线程的数量。对于大的N值,该分数约为5/8。当N值低于8时,使用的数字是N.在选定的平台上,分数降至5/16。可以使用命令行选项(稍后描述)调整垃圾收集器线程的特定数量。 在具有一个处理器的主机上,由于并行执行所需的开销(例如,同步),并行收集器的性能可能不如串行收集器。但是,在运行具有中型到大型堆的应用程序时,它通常在具有两个处理器的计算机上的性能优于串行收集器,并且当有两个以上处理器可用时,通常比串行收集器的性能要好得多。

来源:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/parallel.html

劳尔