在这里还要回顾一下sender线程,其中的步骤八
这次还是要来到Selector的poll方法中
if (readyKeys > 0 || !immediatelyConnectedKeys.isEmpty()) {
//立马就要对这个Selector上面的key进行处理。
pollSelectionKeys(this.nioSelector.selectedKeys(), false, endSelect);
pollSelectionKeys(immediatelyConnectedKeys, true, endSelect);
}
看对key的处理
/* if channel is ready read from any connections that have readable data */
if (channel.ready() && key.isReadable() && !hasStagedReceive(channel)) {
NetworkReceive networkReceive;
//接收服务端发送回来的响应
//networkReceive代表的就是一个服务端发送回来的响应
while ((networkReceive = channel.read()) != null)
addToStagedReceives(channel, networkReceive);
}
这个分支下的addToStagedReceives方法
private void addToStagedReceives(KafkaChannel channel, NetworkReceive receive) {
//channel代表的就是一个网络连接,一台kafka主机就对应一个channel连接
if (!stagedReceives.containsKey(channel))
stagedReceives.put(channel, new ArrayDeque<NetworkReceive>());
Deque<NetworkReceive> deque = stagedReceives.get(channel);
//往队列里面存放接收到的响应
deque.add(receive);
}
接下来就要到poll方法的这里,来处理响应
//TODO 对stagedReceives里面的数据进行处理
addToCompletedReceives();
进来看一下
private void addToCompletedReceives() {
//判断stagedReceives里面有没有数据,刚刚存进去了
if (!this.stagedReceives.isEmpty()) {
//迭代里面的数据
Iterator<Map.Entry<KafkaChannel, Deque<NetworkReceive>>> iter = this.stagedReceives.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<KafkaChannel, Deque<NetworkReceive>> entry = iter.next();
//获取到channel
KafkaChannel channel = entry.getKey();
if (!channel.isMute()) {
Deque<NetworkReceive> deque = entry.getValue();
//获取到一个一个的响应
NetworkReceive networkReceive = deque.poll();
//把响应存入到completedReceives
this.completedReceives.add(networkReceive);
this.sensors.recordBytesReceived(channel.id(), networkReceive.payload().limit());
if (deque.isEmpty())
iter.remove();
}
}
}
}
到这里还是没有对这个响应实际做处理的
所以还要回到sender线程,之前我们一直在selector.poll这个方法
接下来就要到下一个步骤了,是我们之前看到过的一个方法,也是在NetworkClient的poll方法里面
//步骤三:处理响应,响应里面就会有我们需要的元数据
/**
* 上次看到这里是在生产者获取元数据的时候来到的这里
* 可以发现kafka获取元数据和发送消息流程是一样的
* 获取元数据 -》 判断网络是否建立好 -》 建立网络连接
* —》 发送请求(获取元数据请求)-》 服务端发送回来的响应(带有元数据信息)
*
*/
handleCompletedReceives(responses, updatedNow);
进来看一下
private void handleCompletedReceives(List<ClientResponse> responses, long now) {
//迭代completedReceives
for (NetworkReceive receive : this.selector.completedReceives()) {
//获取broker id
String source = receive.source();
/**
* kafka允许发送请求,每个连接可以容忍5个发送出去了,但是还没有接收到响应的请求
*
*/
//从inFlightRequests里面移除已经接收到响应的请求
//把之前存入进去的请求也获取到了
ClientRequest req = inFlightRequests.completeNext(source);
//解析服务端发送回来的请求,这里解析主要是因为kafka传输数据是二进制的
Struct body = parseResponse(receive.payload(), req.request().header());
//TODO 如果是关于元数据信息的响应
if (!metadataUpdater.maybeHandleCompletedReceive(req, now, body))
//解析之后就封装成一个一个的ClientResponse
//body存储的是响应的内容
//req 是发送出去的那个请求信息
responses.add(new ClientResponse(req, now, false, body));
}
}
这里最终就是把响应存到了这个List里面。
响应消息流转流程图