在我的Spring Boot / Kafka项目中,我有以下消费者配置:
@Configuration
public class KafkaConsumerConfig {
@Bean
public ConsumerFactory<String, String> consumerFactory(KafkaProperties kafkaProperties) {
return new DefaultKafkaConsumerFactory<>(kafkaProperties.buildConsumerProperties(), new StringDeserializer(), new JsonDeserializer<>(String.class));
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory(KafkaProperties kafkaProperties) {
ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory(kafkaProperties));
factory.setConcurrency(10);
return factory;
}
@Bean
public ConsumerFactory<String, Post> postConsumerFactory(KafkaProperties kafkaProperties) {
return new DefaultKafkaConsumerFactory<>(kafkaProperties.buildConsumerProperties(), new StringDeserializer(), new JsonDeserializer<>(Post.class));
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, Post> postKafkaListenerContainerFactory(KafkaProperties kafkaProperties) {
ConcurrentKafkaListenerContainerFactory<String, Post> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(postConsumerFactory(kafkaProperties));
return factory;
}
}
这是我的PostConsumer
:
@Component
public class PostConsumer {
@Autowired
private PostService postService;
@KafkaListener(topics = "${kafka.topic.post.send}", containerFactory = "postKafkaListenerContainerFactory")
public void sendPost(ConsumerRecord<String, Post> consumerRecord) {
postService.sendPost(consumerRecord.value());
}
}
和application.properties:
spring.kafka.bootstrap-servers=${kafka.host}:${kafka.port}
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.group-id=groupname
spring.kafka.consumer.enable-auto-commit=false
kafka.topic.post.send=post.send
kafka.topic.post.sent=post.sent
kafka.topic.post.error=post.error
正如您所看到的,我添加了 factory.setConcurrency(10); ,但它不起作用。所有PostConsumer.sendPost
都在名为org.springframework.kafka.KafkaListenerEndpointContainer#1-8-C-1
我希望能够控制并发PostConsumer.sendPost
侦听器的数量,以便并行工作。请告诉我如何使用Spring Boot和Spring Kafka实现它。
答案 0 :(得分:3)
问题在于我们使用Apache Kafka Consumer在Spring Kafka中追求的一致性。这种并发性在所提供的主题中的分区之间分配。如果你只有一个主题和一个分区,那么确实不会有任何并发。重点是消耗同一线程中一个分区的所有记录。
文档中有关于此事的一些信息:https://docs.spring.io/spring-kafka/docs/2.1.7.RELEASE/reference/html/_reference.html#_concurrentmessagelistenercontainer
例如,如果提供了6个TopicPartition并且并发性为3;每个容器将获得2个分区。对于5个TopicPartition,2个容器将获得2个分区,第三个将获得1.如果并发性大于TopicPartitions的数量,则将调整并发性,以便每个容器将获得一个分区。
还有JavaDocs:
$arrayA = json_decode(file_get_contents('path/to/a.json'),true);
$arrayB = json_decode(file_get_contents('path/to/b.json'),true);
$result = array_diff_key($arrayA,$arrayB);
if(empty($result)){
//Same file
}else{
//Differences occured
}
答案 1 :(得分:1)
要创建和管理分区主题,
@Bean
public KafkaAdmin admin() {
Map<String, Object> configs = new HashMap<>();
configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_URL);
return new KafkaAdmin(configs);
}
@Bean
public NewTopic topicToTarget() {
return new NewTopic(Constant.Topic.PUBLISH_MESSAGE_TOPIC_NAME, <no. of partitions>, (short) <replication factor>);
}
要将邮件发送到不同的分区,请使用Partitioner界面
@Bean
public Map<String, Object> producerConfigs() {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_URL);
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, <your custom Partitioner implementation>);
return props;
}
要使用单个使用者使用多个分区中的消息(来自不同分区的每个消息将产生新线程,并且将并行调用使用者方法)
@KafkaListener(topicPartitions = {
@TopicPartition(
topic = Constant.Topic.PUBLISH_MESSAGE_TOPIC_NAME,
partitions = "#{kafkaGateway.createPartitionArray()}"
)
}, groupId = "group.processor")
public void consumeWriteRequest(@Payload String data) {
//your code
}
这里的使用者(如果启动了多个实例)属于同一组,因此将为每个消息调用其中一个。