【发布时间】:2019-10-11 20:00:08
【问题描述】:
我正在尝试了解有关 kafka 流(kafka 流客户端到 kafka)的一些细节。
我知道 KafkConsumer(java 客户端)会从 kafka 获取数据,但是我无法理解客户端轮询 kakfa 主题以获取数据的频率?
【问题讨论】:
标签: apache-kafka kafka-consumer-api apache-kafka-streams
我正在尝试了解有关 kafka 流(kafka 流客户端到 kafka)的一些细节。
我知道 KafkConsumer(java 客户端)会从 kafka 获取数据,但是我无法理解客户端轮询 kakfa 主题以获取数据的频率?
【问题讨论】:
标签: apache-kafka kafka-consumer-api apache-kafka-streams
投票的频率由您的代码定义,因为您负责调用 poll。 使用 KafkaConsumer 的用户代码的一个非常幼稚的示例就像 following
public class KafkaConsumerExample {
...
static void runConsumer() throws InterruptedException {
final Consumer<Long, String> consumer = createConsumer();
final int giveUp = 100; int noRecordsCount = 0;
while (true) {
final ConsumerRecords<Long, String> consumerRecords =
consumer.poll(1000);
if (consumerRecords.count()==0) {
noRecordsCount++;
if (noRecordsCount > giveUp) break;
else continue;
}
consumerRecords.forEach(record -> {
System.out.printf("Consumer Record:(%d, %s, %d, %d)\n",
record.key(), record.value(),
record.partition(), record.offset());
});
consumer.commitAsync();
}
consumer.close();
System.out.println("DONE");
}
}
在这种情况下,频率由处理consumerRecords.forEach 中的消息的持续时间定义。
但是,请记住,如果您没有“足够快”地调用 poll,您的消费者将被代理协调器视为已死亡,并且将触发重新平衡。
这个“足够快”是由 kafka >= 0.10.1.0 中的max.poll.interval.ms 属性决定的。详情请见this answer。
max.poll.interval.ms 默认值为五分钟,因此如果您的consumerRecords.forEach 花费的时间超过该时间,您的消费者将被视为死亡。
如果您不想直接使用原始的 KafkaConsumer,您可以使用 alpakka kafka,这是一个以 安全 和背压方式(基于在 akka 流上)。
有了这个库,轮询的频率由配置akka.kafka.consumer.poll-interval决定。
我们说是安全的,因为它会继续轮询以避免消费者被认为已死亡,即使您的处理无法跟上速率。它能够做到这一点是因为KafkaConsumer 允许暂停消费者
/**
* Suspend fetching from the requested partitions. Future calls to {@link #poll(Duration)} will not return
* any records from these partitions until they have been resumed using {@link #resume(Collection)}.
* Note that this method does not affect partition subscription. In particular, it does not cause a group
* rebalance when automatic assignment is used.
* @param partitions The partitions which should be paused
* @throws IllegalStateException if any of the provided partitions are not currently assigned to this consumer
*/
@Override
public void pause(Collection<TopicPartition> partitions) { ... }
要完全理解这一点,您应该阅读有关 akka-streams 和背压的内容。
【讨论】:
KafkaConsumer 构建的消费者都使用这种机制。即使他们不使用KafkaConsumer,他们必须使用kafka协议,尤其是消息Fetch来获取记录。