1、主线程尝试啦取元数据
2、唤醒sender线程并wait等待拉取完成,sender线程通过NetWorkClient从kafka集群拉取元数据
3、kafka集群给networkclient返回元数据响应
4、拉取到元数据以后,跟新version版本号,并唤醒主线程
5、主线程继续往下执行
/**
* 步骤一:
* 同步等待拉取元数据。
* maxBlockTimeMs 最多能等待多久。
*/
ClusterAndWaitTime clusterAndWaitTime = waitOnMetadata(record.topic(), record.partition(), maxBlockTimeMs);
...
/**
* 很明显,真正去获取元数据是这个线程完成。
*/
waitOnMetadata.sender.wakeup(); -> this.sender = new Sender -> sender.run -> this.client.poll(pollTimeout, now);
-> this.selector.poll
-> handleCompletedReceives -> metadataUpdater.maybeHandleCompletedReceive -> handleResponse
-> this.metadata.update(cluster, now);
public synchronized void update(Cluster cluster, long now) {
// 更新版本号,metadata.awaitUpdate while (this.version <= lastVersion) 退出循环
this.version += 1;
...
//直接把刚刚传进来的对象赋值给了这个cluster。
//cluster代表的是kafka集群的元数据。
//初始化的时候,update这个方法没有去服务端拉取数据。
this.cluster = cluster;//address
...
// 唤醒awaitUpdate.wait
notifyAll();
}
-----------------------------------------------------------------------------
waitOnMetadata.metadata.awaitUpdate(version, remainingWaitMs);
public synchronized void awaitUpdate(final int lastVersion, final long maxWaitMs) throws InterruptedException {
if (maxWaitMs < 0) {
throw new IllegalArgumentException("Max time to wait for metadata updates should not be < 0 milli seconds");
}
//获取当前时间
long begin = System.currentTimeMillis();
//看剩余可以使用的时间,一开始是最大等待的时间。
long remainingWaitMs = maxWaitMs;
/**version是元数据的版本号。
//如果当前的这个version小于等于上一次的version。
//说明元数据还没更新。
//因为如果sender线程那儿 更新元数据,如果更新成功了,sender线程肯定回去累加这个version。*/
while (this.version <= lastVersion) {
//如果还有剩余的时间。
if (remainingWaitMs != 0)
//让当前线程阻塞等待。
//我们这儿虽然没有去看 sender线程的源码
//但是我们知道,他那儿肯定会做这样的一个操作
//如果更新元数据成功了,会唤醒这个线程。
//这儿被唤醒有两个情况:要么获取到元数据了,被sender线程唤醒,要么就是时间到了。
wait(remainingWaitMs);
//如果代码执行到这儿 说明就要么就被唤醒了,要么就到点了。
//计算一下花了多少时间。
long elapsed = System.currentTimeMillis() - begin;
//已经超时了
if (elapsed >= maxWaitMs)
//报一个超时的异常。
throw new TimeoutException("Failed to update metadata after " + maxWaitMs + " ms.");
//再次计算 可以使用的时间。
remainingWaitMs = maxWaitMs - elapsed;
}
}