使用ThreadPool消费Kafka无法确保订购?

时间:2018-04-25 08:41:46

标签: apache-kafka spring-kafka

我有Kafka topic 1-partition1 listener在我的spring-boot应用中使用@KafkaListener定义。 listener使用ThreadPoolTaskExecutor选择ConsumerRecord并对其进行处理。但是,我可以看到kafka承诺的严格排序,在这种情况下,因为我可以看到offset有时跳转(使用时间戳验证)并行线程开始处理...所以问题:

  1. 为什么Ordering不遵循其中的并行线程 听者?
  2. 我们如何同时实现并行和排序呢? 并行线程拾取下一个偏移而不是跳转?
  3. 编辑1

    public class DefaultTopicListener {
        @Autowired
        ThreadPoolTaskExecutor executorPool;
    
        @KafkaListener(topicPartitions=@TopicPartition(topic="defaultTopic", 
    partitions={"0"}))
        public void onMessage(ConsumerRecord<String, CustomPayload> request) {
            CustomPayload message = request.value();
            try {
                executorPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        logger.info(
                                "onMessage : executorPool_THREAD_{}-> -> Offset {}.... ",
                                Thread.currentThread().getId(), request.offset());
                    }
                });
            }  catch (RejectedExecutionException ex) {
                logger.error(
                        "onMessage : executorPool -> Queue Full Request Rejected for offset -> {}", ex, );
            }
        }
    public class Config {
        @Bean("executorPool")
        public ThreadPoolTaskExecutor executorPool(){
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(3);
            executor.setMaxPoolSize(5);
            executor.setQueueCapacity(5);
    
            return executor;
        }
    }
    

    请告知。

2 个答案:

答案 0 :(得分:2)

不清楚你的意思。线程池不会选择&#34;事情,他们被赋予了运行的任务。您需要显示您的代码。

...投机

如果您的侦听器正在将ConsumerRecord移交给线程池,那么当然,记录排序会丢失,因为记录是在不同的线程上处理的(除非池的大小为1)。

对于单个分区,侦听器容器在单个线程上调用侦听器。如果您想保留订单,则不得将工作交给其他线程。

实现并发的唯一方法是使用多个分区并增加容器的并发性。分区将分布在容器线程中。

或者,您需要在代码中管理确认,以确保没有&#34;跳转&#34;承诺。

仅在分区内保证订购,因此,您不能将其移交给另一个线程。

答案 1 :(得分:1)

Kafka通常建议每个消费者使用一个帖子。如果您想将处理与消耗分离,那么将ConsumerRecords实例移交给实际处理记录处理的处理器线程池所消耗的阻塞队列。

https://kafka.apache.org/090/javadoc/index.html?org/apache/kafka/clients/consumer/KafkaConsumer.html

然而,在这种情况下排序并不能保证,因为线程将独立执行,因为线程执行时间的好运,实际上可以在稍后的数据块之后处理较早的数据块。

订购和并行可以通过让多个分区和一个负责分区的线程来实现,分区中的所有记录都将由线程按顺序处理。