Kafka源码分析13-Producer如何处理暂存状态的响应

412 阅读2分钟

欢迎大家关注 github.com/hsfxuebao/j… ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈

Kafka源码分析12-Producer处理拆包粘包完美方案 中,我们接受到服务端响应放入暂存消息

stagedReceives 本文分析如何处理stagedReceives. 查看selector 的poll()方法

public void poll(long timeout) throws IOException {
    if (timeout < 0)
        throw new IllegalArgumentException("timeout should be >= 0");

    clear();

    if (hasStagedReceives() || !immediatelyConnectedKeys.isEmpty())
        timeout = 0;

    /* check ready keys */
    long startSelect = time.nanoseconds();
    //从Selector上找到有多少个key注册了
    int readyKeys = select(timeout);
    long endSelect = time.nanoseconds();

    this.sensors.selectTime.record(endSelect - startSelect, time.milliseconds());
    //因为我们用场景驱动的方式
    //我们刚刚确实是注册了一个key
    if (readyKeys > 0 || !immediatelyConnectedKeys.isEmpty()) {
        //立马就要对这个Selector上面的key要进行处理。
        pollSelectionKeys(this.nioSelector.selectedKeys(), false, endSelect);
        pollSelectionKeys(immediatelyConnectedKeys, true, endSelect);
    }

    //TODO 对stagedReceives里面的数据要进行处理
    addToCompletedReceives();

    long endIo = time.nanoseconds();
    this.sensors.ioTime.record(endIo - endSelect, time.milliseconds());

    // we use the time at the end of select to ensure that we don't close any connections that
    // have just been processed in pollSelectionKeys
    maybeCloseOldestConnection(endSelect);
}

我们来看addToCompletedReceives()

private void addToCompletedReceives() {
    if (!this.stagedReceives.isEmpty()) {
        // 如果stagedReceives集合不为空,则遍历该集合
        Iterator<Map.Entry<KafkaChannel, Deque<NetworkReceive>>> iter = this.stagedReceives.entrySet().iterator();
        while (iter.hasNext()) {
            // 取出对应的键值对
            Map.Entry<KafkaChannel, Deque<NetworkReceive>> entry = iter.next();
            // 获取KafkaChannel
            KafkaChannel channel = entry.getKey();
            if (!channel.isMute()) {
                // 判断KafkaChannel是否是mute状态,如果不是才表示此时KafkaChannel已经完成了读写操作
                Deque<NetworkReceive> deque = entry.getValue();
                addToCompletedReceives(channel, deque);
                // 调用bytesReceived的record()方法进行记录
                // 如果队列空了,移除键值对
                if (deque.isEmpty())
                    iter.remove();
            }
        }
    }
}
private void addToCompletedReceives(KafkaChannel channel, Deque<NetworkReceive> stagedDeque) {
    // 获取队首networkReceive并添加到completedReceives
    // 对于客户端来说,获取到响应
    // 对于服务端来说,这接收的是请求
    NetworkReceive networkReceive = stagedDeque.poll();
    this.completedReceives.add(networkReceive);
    // 调用bytesReceived的record()方法进行记录
    this.sensors.recordBytesReceived(channel.id(), networkReceive.payload().limit());
}

在这里仅仅只会把每个连接对应的第一个响应消息会放到completedReceives里面去,放到后面去进行处理。

参考文档:

史上最详细kafka源码注释(kafka-0.10.2.0-src)

kafka技术内幕-图文详解Kafka源码设计与实现

Kafka 源码分析系列