Java 卡夫卡9卡夫卡消费倍数';t似乎无法并行处理消息

Java 卡夫卡9卡夫卡消费倍数';t似乎无法并行处理消息,java,multithreading,apache-kafka,Java,Multithreading,Apache Kafka,我在3台服务器上有一个Kafka集群,所以我创建了一个分区3的主题,复制因子为3 bin/kafka-topics.sh --create --zookeeper tstaapp001:52181,ewdlxsrv283:52181,devcapp001:52181 --replication-factor 3 --partitions 3 --topic TEST_PARTITION 我有一个使用Kafka 9.0从博客中复制的多线程消费者示例程序,但在我的8核PC上运行时,它实际上不会并行

我在3台服务器上有一个Kafka集群,所以我创建了一个分区3的主题,复制因子为3

bin/kafka-topics.sh --create --zookeeper tstaapp001:52181,ewdlxsrv283:52181,devcapp001:52181 --replication-factor 3 --partitions 3 --topic TEST_PARTITION
我有一个使用Kafka 9.0从博客中复制的多线程消费者示例程序,但在我的8核PC上运行时,它实际上不会并行接收消息。有人能告诉我我的设置或代码是否有任何问题吗

public class Consumer implements Runnable {
    private final KafkaConsumer<String, String> consumer;
    private final List<String> topics;
    private final int id;

    public Consumer(int id, String groupId, List<String> topics) {
        this.id = id;
        this.topics = topics;
        Properties props = new Properties();
        props.put("bootstrap.servers",
                "tstaapp001:59092,ewdlxsrv283:59092,devcapp001:59092");
        props.put("group.id", groupId);
        props.put("key.deserializer", StringDeserializer.class.getName());
        props.put("value.deserializer", StringDeserializer.class.getName());
        this.consumer = new KafkaConsumer<>(props);
    }

    @Override
    public void run() {
        try {
            consumer.subscribe(topics);

            while (true) {
                ConsumerRecords<String, String> records = consumer
                        .poll(Long.MAX_VALUE);
                for (ConsumerRecord<String, String> record : records) {
                    Map<String, Object> data = new HashMap<>();
                    data.put("partition", record.partition());
                    data.put("offset", record.offset());
                    data.put("value", record.value());
                    System.out.println(this.id + ": " + data);
                }
            }
        } catch (WakeupException e) {
            // ignore for shutdown
        } finally {
            consumer.close();
        }
    }

    public void shutdown() {
        consumer.wakeup();
    }

    public static void main(String[] args) {
        int numConsumers = 3;
        String groupId = "TEST-GROUP";
        List<String> topics = Arrays.asList("TEST_PARTITION");

        ExecutorService executor =     Executors.newFixedThreadPool(numConsumers);

        final List<Consumer> consumers = new ArrayList<>();
        for (int i = 0; i < numConsumers; i++) {
            Consumer consumer = new Consumer(i, groupId, topics);
            consumers.add(consumer);
            executor.submit(consumer);
        }

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                for (Consumer consumer : consumers) {
                    consumer.shutdown();
                }
                executor.shutdown();
                try {
                    executor.awaitTermination(5000, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
马丁

你的消费代码看起来不错。您是否尝试运行多个消费者实例。例如,看看我的消费者

如果您有一个包含3个分区的say topic,并且您希望并行地使用所有3个分区的消息(您不能并行地使用一个分区),那么启动3个消费者实例,您会注意到Kafka为每个消费者分配了一个分区,他们将并行地接收消息。在我的示例消费者中,有一个ConsumerBalanceListener,它将帮助您调试正在发生的事情

苏尼尔

马丁

你的消费代码看起来不错。您是否尝试运行多个消费者实例。例如,看看我的消费者

如果您有一个包含3个分区的say topic,并且您希望并行地使用所有3个分区的消息(您不能并行地使用一个分区),那么启动3个消费者实例,您会注意到Kafka为每个消费者分配了一个分区,他们将并行地接收消息。在我的示例消费者中,有一个ConsumerBalanceListener,它将帮助您调试正在发生的事情


Sunil

我建议您使用一个库,为您提供这些并行性内容

ConsumerConfig.<String, String>builder()
.prop(KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName())
.prop(VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName())
.prop(GROUP_ID_CONFIG, "stocks")
.topics("stock_changed")
.consumers(7)
.callback((ctx, record) -> {
  log.info("status=consumed, value={}", record.value());
})
.build()
.consume()
.waitFor();
ConsumerConfig.builder()
.prop(键\反序列化器\类\配置,StringDeserializer.CLASS.getName())
.prop(值\反序列化器\类\配置,StringDeserializer.CLASS.getName())
.prop(组ID配置,“股票”)
.主题(“库存变化”)
.消费者(7)
.回调((ctx,记录)->{
log.info(“status=consumered,value={}”,record.value());
})
.build()
.消费()
.waitFor();

我建议您使用一个库,为您提供并行性方面的内容

ConsumerConfig.<String, String>builder()
.prop(KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName())
.prop(VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName())
.prop(GROUP_ID_CONFIG, "stocks")
.topics("stock_changed")
.consumers(7)
.callback((ctx, record) -> {
  log.info("status=consumed, value={}", record.value());
})
.build()
.consume()
.waitFor();
ConsumerConfig.builder()
.prop(键\反序列化器\类\配置,StringDeserializer.CLASS.getName())
.prop(值\反序列化器\类\配置,StringDeserializer.CLASS.getName())
.prop(组ID配置,“股票”)
.主题(“库存变化”)
.消费者(7)
.回调((ctx,记录)->{
log.info(“status=consumered,value={}”,record.value());
})
.build()
.消费()
.waitFor();

Sunil,我不确定我是否看到了你的消费者和我的消费者之间的根本区别。Sunil,我不确定我是否看到了你的消费者和我的消费者之间的根本区别。另一个意外的行为是,当将numConsumers设置为1时,我得到的消息顺序不正确
0:{partition=1,offset=192,value=MARTIN2}0:{partition=1,offset=193,value=MARTIN5}0:{partition=1,offset=194,value=MARTIN8}0:{partition=0,offset=195,value=MARTIN0}0:{partition=0,offset=196,value=MARTIN3}0:{partition=0,offset=197,value=MARTIN6}0:{partition=2,offset=191,value=MARTIN1}0:{partition=2,offset=192,value=MARTIN4}0:{partition=2,offset=193,value=MARTIN7}
Sunil,我不确定我是否看到了您的消费者和我的消费者之间的根本区别。Sunil,我不确定我是否看到了您的消费者和我的消费者之间的根本区别。另一个意外行为是,当numConsumers设置为1时,我收到的消息顺序不正确
0:{partition=1,offset=192,value=MARTIN2}0:{partition=1,offset=193,value=MARTIN5}0:{partition=1,offset=194,value=MARTIN8}0:{partition=0,offset=195,value=MARTIN0}0:{partition=0,offset=196,value=MARTIN3}0:{partition=0,offset=197,value=MARTIN6}0:{partition 0:{partition=2,offset=192,value=MARTIN1}0:{partition 2,offset=192,value=1937}