Java 卡夫卡9卡夫卡消费倍数';t似乎无法并行处理消息
我在3台服务器上有一个Kafka集群,所以我创建了一个分区3的主题,复制因子为3Java 卡夫卡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上运行时,它实际上不会并行
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}