前言
本文暂时只是对KafkaConsumer#poll方法展开解析。
poll
private ConsumerRecords<K, V> poll(final Timer timer, final boolean includeMetadataInTimeout) {
/* 确保KafkaConsumer没有关闭。 */
acquireAndEnsureOpen();
try {
/* 如果订阅类型是none。 */
/* 也就是没有订阅topic或者手动分配分区 */
if (this.subscriptions.hasNoSubscriptionOrUserAssignment()) {
throw new IllegalStateException("Consumer is not subscribed to any topics or assigned any partitions");
}
do {
/* 可能会触发唤醒,终止拉取消息 */
client.maybeTriggerWakeup();
if (includeMetadataInTimeout) {
/* 主要处理消费者加入消费者组的相关逻辑、位移的自动提交以及对丢失位移的分区进行位移重置 */
if (!updateAssignmentMetadataIfNeeded(timer)) {
return ConsumerRecords.empty();
}
} else {
while (!updateAssignmentMetadataIfNeeded(time.timer(Long.MAX_VALUE))) {
log.warn("Still waiting for metadata");
}
}
final Map<TopicPartition, List<ConsumerRecord<K, V>>> records = pollForFetches(timer);
if (!records.isEmpty()) {
/* 如果发起了多个获取数据的请求。*/
/* 或者:客户端还有没有发送的请求 以及 已发送但是没有得到响应的请求 */
if (fetcher.sendFetches() > 0 || client.hasPendingRequests()) {
/* 进行底层网络io,立即返回 */
client.pollNoWakeup();
}
/* 拦截器拦截处理 */
return this.interceptors.onConsume(new ConsumerRecords<>(records));
}
/* 只要拉取时间没有失效,就会一直拉取消息 */
} while (timer.notExpired());
return ConsumerRecords.empty();
} finally {
release();
}
}

确保KafkaConsumer没有关闭。

获取锁。

释放锁。

ConsumerCoordinator#poll 方法 主要处理消费者加入消费者组的相关逻辑、位移的自动提交。
返回false的情况是以下几种之一:
如果协调者未知 && 客户端无法与协调者节点连接就绪。
元数据更新失败。
新的消费者尝试加入组失败。

如果产生了新的Leader导致Follower的分区的位移截断,需要验证位移的正确性。
如果当前所有已分配分区的FetchState都为FETCHING状态,直接返回true。
如果从协调者获取的已提交的位移为空,直接返回false。
根据位移重置策略对丢失的位移发起重置请求。
对需要重置位移的分区,进行重置位移。
private Map<TopicPartition, List<ConsumerRecord<K, V>>> pollForFetches(Timer timer) {
long pollTimeout = coordinator == null ? timer.remainingMs() :
Math.min(coordinator.timeToNextPoll(timer.currentTimeMs()), timer.remainingMs());
// if data is available already, return it immediately
final Map<TopicPartition, List<ConsumerRecord<K, V>>> records = fetcher.fetchedRecords();
if (!records.isEmpty()) {
return records;
}
// send any new fetches (won't resend pending fetches)
fetcher.sendFetches();
if (!cachedSubscriptionHashAllFetchPositions && pollTimeout > retryBackoffMs) {
pollTimeout = retryBackoffMs;
}
Timer pollTimer = time.timer(pollTimeout);
client.poll(pollTimer, () -> {
// since a fetch might be completed by the background thread, we need this poll condition
// to ensure that we do not block unnecessarily in poll()
return !fetcher.hasCompletedFetches();
});
timer.update(pollTimer.currentTimeMs());
// after the long poll, we should check whether the group needs to rebalance
// prior to returning data so that the group can stabilize faster
/* 如果消费者需要加入组 或者 加入组的请求还未完成。 */
if (coordinator != null && coordinator.rejoinNeededOrPending()) {
return Collections.emptyMap();
}
return fetcher.fetchedRecords();
}
拉取数据。
本文重点探讨KafkaConsumer的核心功能——poll方法,详细解析该方法在Kafka消费者架构中的作用,如何进行数据拉取。
1086

被折叠的 条评论
为什么被折叠?



