Spring + Kafka:交易缓慢

时间:2018-04-10 13:31:56

标签: performance apache-kafka kafka-consumer-api spring-kafka

刚开始使用Spring Kafka(2.1.4.RELEASE)和Kafka(1.0.0)但是当我添加了事务时,处理速度大大降低了。

代码:

spring.kafka.consumer.max-poll-records=10
spring.kafka.consumer.specific.avro.reader=true
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.group-id=${application.name}
spring.kafka.consumer.properties.isolation.level=read_committed
spring.kafka.consumer.key-deserializer=io.confluent.kafka.serializers.KafkaAvroDeserializer
spring.kafka.consumer.value-deserializer=io.confluent.kafka.serializers.KafkaAvroDeserializer

在Java中我添加了:

@Bean
ProducerFactory<Object, Object> producerFactory(KafkaProperties properties) {
    DefaultKafkaProducerFactory<Object, Object> factory = new DefaultKafkaProducerFactory<>(properties.buildProducerProperties());
    factory.setTransactionIdPrefix(properties.getProducer().getTransactionIdPrefix());
    return factory;
}

@Bean
KafkaTemplate<Object, Object> kafkaTemplate(ProducerFactory<Object, Object> factory) {
    return new KafkaTemplate<>(factory, true);
}

@Bean("kafkaListenerContainerFactory")
ConcurrentKafkaListenerContainerFactory<Object, Object> listenerContainerFactory(Environment env, ConsumerFactory<Object, Object> consumerFactory, KafkaTransactionManager<Object, Object> transactionManager) {
    ConcurrentKafkaListenerContainerFactory<Object, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
    factory.setAutoStartup(true);
    factory.setConcurrency(1);
    factory.setConsumerFactory(consumerFactory);
    factory.getContainerProperties().setTransactionManager(transactionManager);
    factory.getContainerProperties().setGroupId(env.getRequiredProperty("spring.kafka.consumer.group-id"));
    return factory;
}

当我删除setTransactionManager(transactionManager)语句时,速度增加了很多。有什么我做错了吗?

1 个答案:

答案 0 :(得分:2)

Kafka交易相当昂贵 - 特别是如果您提交每次发送。

请参阅Transactions in Apache Kafka

向下滚动到&#34;交易如何执行,以及如何调整它们&#34;。

  

正如我们所看到的,开销与作为事务一部分写入的消息数量无关。因此,拥有更高吞吐量的关键是每个事务包含更多的消息。

使用Spring for Apache Kafka,您可以使用executeInTransaction方法在同一事务中执行多个发送。或者将Spring事务管理与KafkaTransactionManager一起使用,并在@Transactional方法中执行多个发送。

修改

我没有注意到监听器容器;我假设您正在使用消息,执行一些转换并发送到另一个主题。因此,在这种情况下,您无法在交易中发送多条消息&#34;因为容器管理事务,默认情况下,在每次交付后提交。

增加并发性不会影响事务语义;在您的情况下,(并发10),分区分布在10个线程中。每个线程都运行一个单独的事务。

您可以通过在容器工厂中将batchListener设置为true来进一步加快速度。

在这种情况下,@KafkaListener获得List<ConsumerRecord>(如果您使用转化,则为List<Foo>);您可以遍历列表并处理每个记录并使用模板发送它(不要使用executeInTransaction,因为已经存在由容器线程启动的事务)。然后,当批处理完成时,容器将提交事务。

您可以使用kafka max.poll.records使用者属性控制批量大小。