为什么在记录,生产者和消费者数量不变的情况下,卡夫卡经纪人的GC时间会增加?

时间:2018-12-28 13:50:27

标签: java apache-kafka garbage-collection

我使用Kafka 2.1.0。

我们有一个包含5个代理(r5.xlarge机器)的Kafka集群。我们经常观察到,GC时序增加太​​多,而传入消息的速率却没有任何变化,从而不会严重影响群集的性能。现在,我不知道是什么原因导致GC时间突然增加。

我尝试了一些没有太大改进的事情,但是我真的不明白它们背后的原因。

export KAFKA_HEAP_OPTS="-Xmx10G -Xms1G"
export KAFKA_JVM_PERFORMANCE_OPTS="-XX:MetaspaceSize=96m -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1HeapRegionSize=16M -XX:MinMetaspaceFreeRatio=50 -XX:MaxMetaspaceFreeRatio=80"

我想了解在Kafka代理中调整GC时最重要的参数。 看到上面的配置,我哪里出错了?该如何纠正?

所有生产者和消费者都工作正常,并且传入消息的速率保持相当恒定。到目前为止,我们还无法找出GC时间突然增加背后的任何模式,这似乎是随机的。

更新

经过一些进一步的分析,事实证明每秒的数据量确实有所增加。主题之一已将消息输入从大约10 KBps增加到200 KBps。但我相信Kafka可以轻松处理大量数据。

有什么我想念的吗?

Grafana快照 enter image description here

2 个答案:

答案 0 :(得分:1)

我首先要查看问题是否是GC调整问题之外的其他问题。这有两种可能:

  • 一次硬内存泄漏将导致GC时间增加。 GC的工作是通过跟踪和复制可到达对象来控制。如果发生泄漏,那么(错误地)可以到达越来越多的对象。

  • 保留太多可访问对象的缓存也会增加GC时间。

  • 过度使用引用类型,终结器等可能会增加GC时间。

我将启用GC日志记录,并查找GC报告的内存和空间利用率模式。如果您怀疑内存泄漏是因为内存利用率从长期来看会更高,请转到下一步并使用内存配置文件来跟踪泄漏。

无论哪种方式,在尝试解决问题之前,了解导致问题的原因都很重要。


  

经过一些进一步的分析,事实证明,每秒的数据量确实有所增加。主题之一已将消息输入从大约10 KBps增加到200 KBps。但我相信Kafka可以轻松处理大量数据。

很有可能。但是,吞吐量提高20倍将不可避免地导致更多对象的创建和丢弃……并且GC将需要更频繁地运行以解决此问题。


  

在5个经纪人之间分配的200 Kbps数据为何能够打破GC。

是什么让您认为您已经“打破”了GC? GC中15%的时间并不意味着它已损坏。

现在,我可以想象GC可能难以满足您的最大20ms暂停时间目标,并且可能因此触发偶尔的完整GC。您的暂停时间目标是“雄心勃勃”,尤其是如果堆可能增长到10GB。我建议减少堆大小,增加暂停时间目标,和/或增加可用于JVM的物理核心数。

  

“打破”是指提交补偿以及其他生产者和消费者补偿的延迟增加。

所以...您只担心负载增加20倍,导致GC使用多达15%的可用CPU。好吧,那还没坏。这是(IMO)的预期。垃圾收集器不是魔术。它需要花费CPU时间来完成工作。它要做的工作越多,则需要使用更多的CPU。如果您的应用程序的工作量涉及大量对象分配,则GC必须处理该问题。

除了上述调整思路之外,我怀疑您应该将G1HeapRegionSize的大小设置得小得多。根据莫妮卡·贝克维斯(Monica Beckwith)的"Garbage First Garbage Collector Tuning",默认值是基于最小堆大小具有2048个区域。但是您的设置将提供1G / 16M == 64个初始区域。

最后,如果您的 overall 目标是降低GC的CPU利用率,那么您应该使用吞吐量GC,而不是G1GC。这将最大程度地减少GC开销。不利之处在于,最小化GC暂停不再是目标,因此偶尔会出现较长的暂停。

如果您打算继续使用G1GC,建议使用最新版本的Java。即Java 11(请参见"G1 Garbage Collector is mature in Java 9, finally"

答案 1 :(得分:0)

Kafka 2.1默认情况下使用G1GC,所以我想您可以忽略该参数。我假设您没有使用JDK11。与以前的版本相比,JDK 11为G1GC带来了重大改进。现在,它可以运行并行处理,而不是运行单线程完整的GC周期。即使那不能大幅度改善最好的情况,但最坏的情况应该有所改善。如果可能的话,请在迁移到JDK 11之后分享您的结果。

注意:我怀疑这是根本原因,但让我们看看。