1在这里我们先来梳理一下consumeGroup的相关知识
1、首先,我们会给每个consume设置groupId,对于相同groupId且订阅相同topic的consume,会组成consumeGroup,如图一所示
2、对于Server端的topic来说,会有partition这个概念,如图二所示
图二
3、现在我们有多个consume及多个partition,到底由哪个consume来消费哪个partition呢?就由consume启动时的分区分配策略来决定。
-
如果consume数量小于partition的数量,则一个consume有可能消费多个分区,如图三所示
-
如果consume数量大于partition的数量,则会有consume线程空跑,如图四所示
4、kafka的内置topic:consumer_offsets专门记录消费位点信息,既然是内置topic,那自然也会有partition及partition leader的概念,对于同一个groupId的消费位点都会记录在同一个partition中,在这篇文章中findCoordinator即是找到该groupId对应的partition的leader节点,我们知道这个节点才能将位移信息提交到这里保存,如果该partition还有其他副本,则该节点还会与其他副本同步位移信息。与该节点交互都是由GroupCoordinator完成的。
在这里插入图片描述
2findCoordinator流程展示
在这里插入图片描述
3客户端源码分析
这里还是放一下findCoordinator的代码,看其他consume的代码就发现客户端跟kafkaServer通信的格式大多是这样的,如果通信一次发现该GroupCoordinator的信息还未获取到则继续重试,直到超时,这里的超时时间即为poll时传入的超时时间,这个时间设置贯穿了整个consume的运行代码。
protected synchronized boolean ensureCoordinatorReady(final Timer timer) {
//如果还未加入group则与group通信
if (!coordinatorUnknown())
return true;
do {
if (findCoordinatorException != null && !(findCoordinatorException instanceof RetriableException)) {
final RuntimeException fatalException = findCoordinatorException;
findCoordinatorException = null;
throw fatalException;
}
final RequestFuture<Void> future = lookupCoordinator();
client.poll(future, timer);
//如果还没回调完成则说明是超时的
if (!future.isDone()) {