许多消费者引发了卡夫卡经纪人内存泄漏

时间:2017-05-25 15:54:59

标签: java memory-leaks apache-kafka

我正在构建一个Java 8应用程序,它只查询一个Kafka主题的消息。每个请求都会创建一个新的Consumer对象(独立于任何现有的Consumer个对象),它会轮询我的Kafka主题,获取一条记录,并关闭Consumer。这种情况每天发生〜200k次,每个请求都独立于其他请求,所以我认为我不能重复使用消费者。基本上,用户从主题请求消息并为其创建消费者,然后关闭。这平均每秒发生约2次,但是是任意的,所以它可能发生10次/秒或1次/小时,没有办法知道。

过了一会儿,Kafka服务器上的堆大小(不是运行代码的服务器,而是运行Kafka的实际服务器)变得庞大,垃圾收集无法清除它。最终,专用于GC的CPU时间比其他任何东西都多,并且在我重新启动Kafka之前一切都崩溃了。

这是导致问题的代码的近似版本,其中while(true)近似于实际行为(在生产中,消费者不是在while循环中创建的,而是在用户请求时按需创建的来自主题的消息):

Properties props = new Properties();
props.put("bootstrap.servers", "SERVER_IP:9092");
props.put("session.timeout.ms", 30000);
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", 1000);

while(true){
    Consumer<String, String> consumer = new KafkaConsumer<>(props);
    TopicPartition tp = new TopicPartition("TOPIC", 0);
    consumer.assign(Arrays.asList(tp));
    consumer.seekToEnd(Arrays.asList(tp));

    // I've narrowed down the memory leak to this line
    ConsumerRecords<String, String> cr = consumer.poll(1000); 
    // If I remove this line ^, the memory leak does not happen

    /* CODE TO GET ONE RECORD */

    consumer.unsubscribe();
    consumer.close();
}

在20个JVM上运行此代码会导致内存泄漏大约20分钟。以下是Kafka服务器上的堆(蓝色)和GC暂停时间(绿色)的样子: KafkaMemoryLeak

我做错了什么(或者有更好的方法来解决这个问题),或者当很多消费者被创建和关闭时,这是Kafka的一个错误吗?

我在客户端运行Kafka 0.10.2.1,在服务器上运行Kafka 0.10.2.0。

3 个答案:

答案 0 :(得分:1)

无论您收到的请求数量和频率如何,您仍可以重复使用KafkaConsumer实例。您只能在请求到达时进行轮询,但每次都不需要创建和关闭消费者。

话虽如此,如果内存使用量增加且未被GC回收,您对使用者的使用可能会在代理上发现内存管理问题。我已经看到报告代理的问题在生产者被频繁回收时耗尽直接内存。因此,可能存在改进的余地。可能最好在issues.apache.org上提一张票,看看它。

答案 1 :(得分:0)

您每天轮询Kafka~200k次,即每小时约8k次/每分钟~140次/每秒两次 - 为什么每次都创建(并关闭)新的消费者实例?只需安排KafkaConsumer按照您所需的时间间隔触发(您可以使用JDK ScheduledExecutorService)并重用相同的消费者实例

答案 2 :(得分:0)

Kafka 2.4.0(可能还有以前的版本)存在资源泄漏,其中某些MBean未在Consumer.close()上注销。

当您最初问这个问题时可能就是这种情况,当然Tony在上面对您的问题的评论中提出了这一点。

https://issues.apache.org/jira/browse/KAFKA-9504?jql=project%20%3D%20KAFKA%20AND%20text%20~%20%22Consumer%20Leak%22