我正在编写一个概念验证应用程序来使用来自Apache Kafka 0.9.0.0的消息,看看我是否可以使用它而不是通用的JMS消息代理,因为Kafka提供了好处。这是我的基本代码,使用新的消费者API:
public class Main implements Runnable {
public static final long DEFAULT_POLL_TIME = 300;
public static final String DEFAULT_GROUP_ID = "ltmjTest";
volatile boolean keepRunning = true;
private KafkaConsumer<String, Object> consumer;
private String servers;
private String groupId = DEFAULT_GROUP_ID;
private long pollTime = DEFAULT_POLL_TIME;
private String[] topics;
public Main() {
}
//getters and setters...
public void createConsumer() {
Map<String, Object> configs = new HashMap<>();
configs.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, servers);
configs.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
configs.put("enable.auto.commit", "true");
configs.put("auto.commit.interval.ms", "1000");
configs.put("session.timeout.ms", "30000");
configs.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
configs.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
consumer = new KafkaConsumer<>(configs);
consumer.subscribe(asList(topics));
}
public static void main(String[] args) {
Main main = new Main();
if (args != null && args.length > 0) {
for (String arg : args) {
String[] realArg = arg.trim().split("=", 2);
String argKey = realArg[0].toLowerCase();
String argValue = realArg[1];
switch (argKey) {
case "polltime":
main.setPollTime(Long.parseLong(argValue));
break;
case "groupid":
main.setGroupId(argValue);
break;
case "servers":
main.setServers(argValue);
break;
case "topics":
main.setTopics(argValue.split(","));
break;
}
}
main.createConsumer();
new Thread(main).start();
try (Scanner scanner = new Scanner(System.in)) {
while(true) {
String line = scanner.nextLine();
if (line.equals("stop")) {
main.setKeepRunning(false);
break;
}
}
}
}
}
我使用默认设置创建了一个kafka服务器,并使用shell工具kafka-console-producer.sh
创建了一个kafka生成器来向我的主题编写消息。然后我使用这个代码连接两个消费者,发送适当的服务器连接和主题订阅,其他一切使用默认值,这意味着两个消费者具有相同的组ID。我注意到只有我的一个消费者消耗所有数据。我已经读过,默认行为应该是服务器必须平衡消费者,official tutorial:
如果所有消费者实例都具有相同的消费者群体,那么这就像传统的队列平衡消费者的负担一样。
如何修复消费者的行为?或者也许我错过了什么?
答案 0 :(得分:4)
有特征kafka.consumer.PartitionAssignor说明了如何为每个消费者分配分区。它有两个实现:RoundRobinAssignor和RangeAssignor。默认值为RangeAssignor。
可以通过设置param&#34; partition.assignment.strategy&#34;来改变。
Round Robin文档:
roundrobin指定者列出所有可用的分区和所有可用的消费者。然后它继续进行从分区到消费者的循环分配。如果所有使用者实例的订阅相同,则分区将均匀分布。 (即,分区所有权计数将在所有消费者中恰好为1的增量内。)例如,假设有两个消费者C0和C1,两个主题t0和t1,每个主题有3个分区,导致分区t0p0, t0p1,t0p2,t1p0,t1p1和t1p2。赋值将为:C0:[t0p0,t0p2,t1p1] C1:[t0p1,t1p0,t1p2]
范围分配器文档
范围分配器基于每个主题工作。对于每个主题,我们按字母顺序排列可用分区,按字典顺序排列使用者。然后,我们将分区数除以使用者总数,以确定要分配给每个使用者的分区数。如果它没有均匀分配,那么前几个消费者将有一个额外的分区。例如,假设存在两个消费者C0和C1,两个主题t0和t1,并且每个主题具有3个分区,从而产生分区t0p0,t0p1,t0p2,t1p0,t1p1和t1p2。赋值将为:C0:[t0p0,t0p1,t1p0,t1p1] C1:[t0p2,t1p2]
因此,如果我们所有主题只有一个分区,则只有一个消费者可以使用