Kafka Client源码中的NIO使用

豆包 先给你一套可直接啃、面试也高频、架构最清晰的 Kafka 源码分析路线(基于 Kafka 2.x/3.x Java 版),从整体架构 → 核心模块 → 关键流程 → 必看类/方法 先给你一套可直接啃、面试也高频、架构最清晰的 Kafka 源码分析路线(基于 Kafka 2.x/3.x Java 版),从整体架构 → 核心模块 → 关键流程 → 必看类/方法,一步步带你读。2. Client 端(生产者 + 消费者,kafka-clients 模块):生产、拉取消息。1. Broker 端(服务端,kafka-server 模块):接收、存储、复制、转发消息。Client(生产者)→ Client(消费者)→ Broker(核心流程) 阅读详情

本源码使用的Kafka Client是0.10.0.1

NetworkClient是一个通用的网络客户端实现,Kafka生产者和消费者都使用NetworkClient组件和服务端Broker之间进行通讯。

public class NetworkClient implements KafkaClient {

    private static final Logger log = LoggerFactory.getLogger(NetworkClient.class);

    /* the selector used to perform network i/o */
    //网络I/O,发送和接受消息
   private final Selectable selector;

   ......
}

  NetworkClient中负责网络I/O的是Selectable selector接口,接下来主要分析下Selectable接口的实现Selector类。

 

 Selector类

       Selector类(在org.apache.kafka.common.network包下),Selector底层封装了Java NIO,使用一个单独的线程可以管理多条网络连接上的链接、读、写等操作。该类的核心属性如下:

 核心属性及作用

//java.nio.channels.Selector类型,用来监听网络I/O事件。
private final java.nio.channels.Selector nioSelector;  

//维护了NodeId与KafkaChannel之间的映射关系,表示生产者客户端与各个Node之间的网络链接。
//KafkaChannel是在SocketChannel上的又一层封装。其中Send和NetworkReceive分别表示读和写时用的缓存,此等通过ByteBuffer实现,
    //TransportLayer封装了SocketChannel及SelectionKey,TransportLayer根据网络协议的不同,提供不同的子类,而对KafkaChannel提供统一的接口
private final Map<String, KafkaChannel> channels;

//记录已经完全发送出去的请求
private final List<Send> completedSends;  

//记录已经完全接受到的请求
private final List<NetworkReceive> completedReceives; 

//记录从连接中读取到的消息
//暂停一次OP_READ事件处理完成之后,会将stagedReceives集合中的请求保存到completeReceives集合中
private final Map<KafkaChannel, Deque<NetworkReceive>> stagedReceives; 

//记录刚刚创建的连接SelectionKey,因为是异步的,所以不知道该连接是否连接完成
private final Set<SelectionKey> immediatelyConnectedKeys; 

//记录一次poll过程中发现的断开链接
private final List<String> disconnected; 

//记录一次poll过程中新建立的连接
private final List<String> connected;  

//记录向哪些Node发送的请求失败了
private final List<String> failedSends; 

//用于创建KafkaChannel的Builder。根据不同配置创建不同的TransportLayer的子类,然后创建KafkaChannel。
private final ChannelBuilder channelBuilder;  

//LinkedHashMap类型,用来记录各个链接的使用情况,并根据此关闭空闲时间超过connectionsMaxIdleNanos的链接
private final Map<String, Long> lruConnections; 

//连接最大空闲的时间,单位:ns
private final long connectionsMaxIdleNanos;  

//最大接受的消息大小
private final int maxReceiveSize;  

   

接下来主要看一下Selector类中的常用方法

构造器

 public Selector(int maxReceiveSize, long connectionMaxIdleMs, Metrics metrics, Time time, String metricGrpPrefix, Map<String, String> metricTags, boolean metricsPerConnection, ChannelBuilder channelBuilder) {
        try {
            this.nioSelector = java.nio.channels.Selector.open(); //创建一个新的nioSelector
        } catch (IOException e) {
            throw new KafkaException(e);
        }
        this.maxReceiveSize = maxReceiveSize;
        this.connectionsMaxIdleNanos = connectionMaxIdleMs * 1000 * 1000;
        this.time = time;
        this.metricGrpPrefix = metricGrpPrefix;
        this.metricTags = metricTags;
        this.channels = new HashMap<>();
        this.completedSends = new ArrayList<>();
        this.completedReceives = new ArrayList<>();
        this.stagedReceives = new HashMap<>();
        this.immediatelyConnectedKeys = new HashSet<>();
        this.connected = new ArrayList<>();
        this.disconnected = new ArrayList<>();
        this.failedSends = new ArrayList<>();
        this.sensors = new SelectorMetrics(metrics);
        this.channelBuilder = channelBuilder;
        // initial capacity and load factor are default, we set them explicitly because we want to set accessOrder = true
        this.lruConnections = new LinkedHashMap<>(16, .75F, true);
        currentTimeNanos = time.nanoseconds();
        nextIdleCloseCheckTime = currentTimeNanos + connectionsMaxIdleNanos;
        this.metricsPerConnection = metricsPerConnection;
}

  构造器中主要对nioSelector和一些属性进行初始化操作

 

  connect方法

public void connect(String id, InetSocketAddress address, int sendBufferSize, int receiveBufferSize) throws IOException {
        if (this.channels.containsKey(id)) //已经包含该node的id,则抛出异常
            throw new IllegalStateException("There is already a connection for id " + id);

        //创建SocketChannel
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false); //配置成非阻塞模式
        Socket socket = socketChannel.socket();
        socket.setKeepAlive(true); //设置为长连接
        if (sendBufferSize != Selectable.USE_DEFAULT_BUFFER_SIZE)
            socket.setSendBufferSize(sendBufferSize); //设置SO_SNDBUF大小
        if (receiveBufferSize != Selectable.USE_DEFAULT_BUFFER_SIZE)
            socket.setReceiveBufferSize(receiveBufferSize);//设置SO_RCVBUF大小
        socket.setTcpNoDelay(true); //Tcp无延迟
        boolean connected;
        try {
            /*
            * 因为是非阻塞方式,所以SocketChannel.connect()方法是发起一个连接,
            * connect方法在连接正式建立之前就可能返回,在后面会通过Selector.finishConnect()方法确认连接
            * 是否真正建立了。
            * */
            connected = socketChannel.connect(address); //发起连接到kafka服务端
        } catch (UnresolvedAddressException e) {
            socketChannel.close();
            throw new IOException("Can't resolve address: " + address, e);
        } catch (IOException e) {
            socketChannel.close();
            throw e;
        }
        //将这个socketChannel注册到nioSelector上,并关注OP_CONNECT事件
        SelectionKey key = socketChannel.register(nioSelector, SelectionKey.OP_CONNECT);
        //创建KafkaChannel
        KafkaChannel channel = channelBuilder.buildChannel(id, key, maxReceiveSize);
        key.attach(channel); //将KafkaChannel注册到key上
        this.channels.put(id, channel);//将NodeId和KafkaChannel绑定,放到channels中管理

        if (connected) {
            // OP_CONNECT won't trigger for immediately connected channels
            log.debug("Immediately connected to node {}", channel.id());
            immediatelyConnectedKeys.add(key);
            key.interestOps(0);
        }
}

 

       创建SocketChannel并配置成非阻塞模式,将SocketChannel关联的Socket设置成长连接,SocketChannel连接到远程地址,并将SocketChannel注册到nio的Selector对象上,注册的事件为SelectionKey.OP_CONNECT,并返回SelectionKey key

        创建KafkaChannel对象,并将该对象附加(attach)到key上,后续有事件发生时会获取该KafkaChannel对象。KafkaChannel中维护了当前key,用于处理最终的读写

       由于java NIO是异步的,所以无法知道该连接是否完成,所以先将该key添加到immediatelyConnectedKeys中,稍后处理。

 

select方法

    private int select(long ms) throws IOException {
        if (ms < 0L)
            throw new IllegalArgumentException("timeout should be >= 0");

        if (ms == 0L)
            return this.nioSelector.selectNow();
        else
            return this.nioSelector.select(ms);
    }

   我看到select方法主要调用java NIO的Selector对象获取就绪的事件,

   selectNow()不会阻塞,如果没有事件就绪也会直接返回

   select(ms) 会阻塞直到事件产生或者超时

 

poll方法

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

        clear(); //将上一次poll()方法的结果全部清除掉

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

        /* check ready keys */
        long startSelect = time.nanoseconds();
        //调用nioSelector.select()方法,等待I/O事件发送
        int readyKeys = select(timeout);
        long endSelect = time.nanoseconds();
        currentTimeNanos = endSelect;
        this.sensors.selectTime.record(endSelect - startSelect, time.milliseconds()); //统计select阻塞的时间

        //有事件发生 或者 immediatelyConnectedKeys集合不为空
        if (readyKeys > 0 || !immediatelyConnectedKeys.isEmpty()) {
            //处理I/O事件
            pollSelectionKeys(this.nioSelector.selectedKeys(), false);
            pollSelectionKeys(immediatelyConnectedKeys, true);
        }
        //将stagedReceives复制到completedReceives集合中
        addToCompletedReceives();

        long endIo = time.nanoseconds();
        this.sensors.ioTime.record(endIo - endSelect, time.milliseconds());
        maybeCloseOldestConnection(); //关闭长期空闲的连接
    }

 

       首先将上一次poll()方法的结果全部清除掉,并获取select的参数timeout,即最长阻塞时间。调用java nio Selector的select方法获取就绪的SelectionKey,即readyKeys。

      如果有事件发生或immediatelyConnectedKeys集合(刚刚创建连接,还不确定是否连接完成的SelectionKey)不为空,则调用pollSelectionKeys方法进行处理。

 
pollSelectionKeys方法

pollSelectionKeys方法主要处理已经就绪的Key 和 immediatelyConnectedKeys集合不为空的情况

private void pollSelectionKeys(Iterable<SelectionKey> selectionKeys, boolean isImmediatelyConnected) {
        Iterator<SelectionKey> iterator = selectionKeys.iterator();
        while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            iterator.remove();
            //之前创建连接时,将KafkaChannel注册到key上,就是为了在这里获取
            KafkaChannel channel = channel(key);

            // register all per-connection metrics at once
            sensors.maybeRegisterConnectionMetrics(channel.id());
            lruConnections.put(channel.id(), currentTimeNanos); //更新lru信息

            try {

                /* complete any connections that have finished their handshake (either normally or immediately) */
                //对connect方法返回true或OP_CONNECTION事件的处理
                if (isImmediatelyConnected || key.isConnectable()) {
                    //finishConnect方法会先检测socktChannel是否建立完成,完成后,
                    //会取消OP_CONNECT事件关注,开始关注OP_READ事件
                    if (channel.finishConnect()) {
                        this.connected.add(channel.id());//添加到"已连接"的集合中
                        this.sensors.connectionCreated.record();
                    } else
                        continue; //连接未完成,则跳过对此Channel的后续处理
                }

                /* if channel is not ready finish prepare */
                //调用KafkaChannel.prepare()方法进行身份验证,
                if (channel.isConnected() && !channel.ready())
                    channel.prepare();

                /* if channel is ready read from any connections that have readable data */
                if (channel.ready() && key.isReadable() && !hasStagedReceive(channel)) {
                    //OP_READ事件处理
                    NetworkReceive networkReceive;
                    while ((networkReceive = channel.read()) != null)
                        /*
                        * 上面channel.read()读取到一个完整的NetworkReceive,则将其添加到stagedReceives中保存
                        * 若读取不到一个完整的NetworkReceive,则返回null,下次处理OP_READ事件时,继续读取,
                        * 直至读取到一个完整的NetworkReceive
                        * 将读取到的消息记录到stagedReceives中
                        * */
                        addToStagedReceives(channel, networkReceive);
                }

                /* if channel is ready write to any sockets that have space in their buffer and for which we have data */
                if (channel.ready() && key.isWritable()) { //OP_WRITE事件处理
                    //上面的channel.write()方法将KafkaChannel.send字段发送出去,如果未完成发送,则返回null
                    //如果发送完成,则返回send,并添加到completeSends集合中,待后续处理
                    Send send = channel.write();
                    if (send != null) {
                        this.completedSends.add(send); //添加到completedSends集合
                        this.sensors.recordBytesSent(channel.id(), send.size());
                    }
                }
                    /*
                    * completedSends和completedReceives分别表示在Selector端已经发送的和接受到的请求,它们会在NetworkClient的poll调用之后被不同的
                    * handleCompleteXXX()方法处理
                    * */
                /* cancel any defunct sockets */
                if (!key.isValid()) {
                    close(channel);
                    this.disconnected.add(channel.id());
                }
                /*
                * 通过isValid()的返回值以及执行过程中是否抛出异常来判断连接的状态,
                * 并将断开的连接收集到disconnected集合,并在后续操作中进行重连。
                * */
            } catch (Exception e) {
                //抛出异常,则任务连接关闭,将对应NodeId添加到disconnected集合
                String desc = channel.socketDescription();
                if (e instanceof IOException)
                    log.debug("Connection with {} disconnected", desc, e);
                else
                    log.warn("Unexpected error from {}; closing connection", desc, e);
                close(channel);
                this.disconnected.add(channel.id());
            }
        }
    }

 

遍历已经就绪的SelectionKey,首先从集合中删除当前key。调用channel方法获取当前key对应的KafkaChannel。

  private KafkaChannel channel(SelectionKey key) {

        return (KafkaChannel) key.attachment();

  }

 

解析来分别处理OP_CONNECTION、OP_READ和OP_WRITE事件

 

处理OP_ CONNECTION事件

   调用KafkaChannel的finishConnect方法判断连接是否完成

   finishConnect方法底层调用KafkaChannel通讯层TransportLayer的finishConnect进行判断,我们看TransportLayer其中一个实现类PlaintextTransportLayer的finishConnect方法   

  public boolean finishConnect() throws IOException {
        boolean connected = socketChannel.finishConnect();
        if (connected)
            key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT | SelectionKey.OP_READ);
        return connected;
    }

KafkaChannel的通讯层TransportLayer封装了SocketChannel通道,首先调用socketChannel的finishConnect()判断当前SocketChannel对应的Socket连接是否完成,如果已完成,会取消OP_CONNECT事件关注,开始关注OP_READ事件。

 

如果已完成则将该KafkaChannel对应的Node Id添加到属性connected集合中

 

 

处理OP_READ事件

     将读取到的完整消息,写入到stagedReceives

 

处理OP_WRITE事件

      如果有缓存的等待发送的消息,则发送缓存的消息。待发送的消息缓存在KafkaChannel的Send send字段中。如果消息发送成功,则将已发送的消息添加到completedSends集合。

 

 

  send方法

  

send方法主要对外提供发送消息的功能
   

    //并没有网络I/O
    public void send(Send send) {
        KafkaChannel channel = channelOrFail(send.destination());
        try {
            channel.setSend(send);
        } catch (CancelledKeyException e) {
            this.failedSends.add(send.destination());
            close(channel);
        }
    }

 

将之前创建的RequestSend对象缓存到KafkaChannel的send字段中,并开始关注此连接的OP_WRITE事件。

 

wakeup方法

  唤醒阻塞在I/O的线程

  public void wakeup() {
        this.nioSelector.wakeup();
  }

 

 

       其他方法就不在累述,以上是Selector中主要使用Java NIO进行处理的方法。当然KafkaChannel中的TransportLayer对象中存储了SocketChannel socketChannel,以上的pollSelectionKeys方法处理读写事件都是调用该socketChannel进行读写,有兴趣可自行阅读。

Kafka源码深度解析-序列3 -Producer -Java NIO 在上一篇我们分析了Metadata的更新机制,其中涉及到一个问题,就是Sender如何跟服务器通信,也就是网络层。同很多Java项目一样,Kafka client的网络层也是用的Java NIO,然后在上面做了一层封装。下面首先看一下,在Sender和服务器之间的部分: 可以看到,Kafka client基于Java NIO封装了一个网络层,这个网络层最上层的接口是KakfaClient。其层次关系 阅读详情

相关推荐

kafka源码---源码目录介绍

目录 介绍: 一.client 包 二 core包 介绍: 了解kafka项目的目录结构,才能去更好的阅读kafka源码,我觉得我们重点关注其中两个目录下源码就行了,他们分别是client 目录和core目录,client目录下类是java语言开发,实现了消费者和生产者功能,core目录下类是scala语言开发,实现了集群管理,分区副本管理,消息存储和消息获取,网络通...

trntaken的博客 1047

kafka源码学习(一)Producer源码

以为例,异步调用send方法执行后,调用的doSend()方法,核心流程如下:同步等待,拉取元数据maxBlockTimeMs:最长等待时间this.maxBlockTimeMs - waitedOnMetadataMs:还剩余多长时间可以使用对消息的key和value进行序列化根据分区器选择消费应该发送的分区确认消息的大小是否超过了最大值,默认是1M,实际使用过程会修改根据元数据信息,封装分区对象给每一条消息都绑定回调函数,因为样例中使用的是异步调用的方式把消息放入。

weixin_37172178的博客 1285

Java Kafka-Client源码深度解析与元分析及阅读注释

Apache Kafka是一个分布式流处理平台,广泛应用于构建实时数据管道和流应用程序。Kafka-Client是Java客户端库,允许用户轻松地与Kafka集群交互。本文将对Kafka-Client进行源码层面的深度剖析,帮助开发者更好地理解其工作原理,从而提高应用性能和稳定性。幂等性是指执行多次相同操作,结果不会发生变化的特性。在消息处理系统中,幂等性至关重要,以确保消息在生产者到消费者的过程中不会被重复处理。

weixin_35307279的博客 1208

(3.3)client源码——kafka网络通信客户端-NetworkClient类

位置:org.apache.kafka.clients; 作用:用于异步请求/响应网络i/o的网络客户端。这是一个内部类,用于实现面向用户的生产者和消费者客户端,也就是说我们的生产请求和消费请求最后都会交给NetworkClient类处理。 在sender线程中run时调用去。用于发送请求 通过连接处理实际的读写操作............

weixin_43930865的博客 1352

kafka-clients源码.zip

kafka-clients源码,此版本是2.*,java开发kafka客户端

kafka-client

kafka客户端

Kafka源码解析(一)-生产者

kafka生产者源码

qq_40344505的博客 1851

java开发kafka-clients所需要的所有jar包以及源码

Java使用kafka-clients开发kafka生产者与消费者,内有源码

Kafka源码解析(基于3.0.0版本)

以kakfa3.0.0为例,从生产者,消费者,服务端入门kafka源码

桑凯旋的博客 2420

cuda2 but found one of them on device cuda 0

cuda2 but found one of them on device cuda 0 上面问题的重点是,不是cpu和gpu之间的常规问题,而是出现在不同gpu之间的数据。 出问题地方: model = nn.DataParallel(model, device_ids=[2,4]) 先说解决方法: 方案一: model = nn.DataParallel(model, device_ids=[0,2,4]) 前面一定要给一个0的序号,如果0被别人占了呢? 方案二: os.environ["CUDA_

binqiang2wang 665

<Verilog实现除法器> Verilog实现牛顿-拉夫逊(Newton-Raphson)除法器

阿斯顿阿斯顿啊啊是打发士大夫

IC跳跳鱼的博客 3586

(九)Kafka网络设计

文章目录前期回顾 前期回顾 /** * 步骤二: * 首先是判断哪些partition有消息可以发送,获取到这个partition的leader partition * 对应的broker主机。 * * 哪些broker上面需要我们去发送消息? */ RecordAccumulator.ReadyCheckResult result = this.ac

weixin_37850264的博客 411

瑞芯微rv1126 rtsp+mpp+rga取流

瑞芯微rv1109 rtsp+mpp+rga取流

ZuoSeDiao的博客 6340

kafka源码分析---NIO

我们直接跑到最底层,看看kafka的网络层处理是怎么处理的。因为Java的NIO还是偏底层,不能直接用来做应用开发,所以一般都使用像netty的框架或者按照自己的需要封装一些nio,让上层业务不用关心网络处理的细节,只需要创建服务监听端口、接受请求、处理请求、写返回就可以了。我在看netty、thrift等涉及到网络的Java框架时比较喜欢去看他们的nio是怎么封装的,这里也是能够体现作者水平的地...

wjandy0211的博客 457

qt5.14.2+vs2019配置msvc2017编译器

qt5.14.2+vs2019配置msvc2017编译器 在使用qt编译程序时此前一直使用的是自带的MinGW 32-bit和64-bit,现在想使用msvc编译器。本次使用的是qt5.14.2,vs2019,需要配置msvc2017的32-bit和64-bit编译器。 1、首先安装好qt5.14.2和vs2019,其次在visual studio installer选择修改,然后选择msvc2017对应的组件,本次安装的是这两个 2、打开qt creator的工具–选项–kits–编译器,选择Manu

bangtanhui的博客 1万+

STM32F103模拟SSI时序解析:实现高精度绝对式编码器位置读取

本文详细解析了如何在STM32F103微控制器上通过软件模拟SSI协议时序,实现高精度绝对式编码器的位置读取。文章从项目驱动出发,深入剖析了SSI通信原理、硬件电平转换连接、核心软件模拟代码实现及关键时序参数调试方法,并提供了使用示波器进行波形对齐与优化的实战指南,为成本敏感型工业控制与机器人项目提供了高性价比的解决方案。

weixin_29196315的博客 143

消息中间件—简谈Kafka中的NIO网络通信模型

作者:胡宗棠 来源:匠心独运的博客文章摘要:很多人喜欢把RocketMQ与Kafka做对比,其实这两款消息队列的网络通信层还是比较相似的,本文就为大家简要地介绍下Kafk...

程序猿DD 1455

S7-1200 Modbus TCP客户端配置实战:从基础设置到数据交互详解

本文详细介绍了S7-1200 Modbus TCP客户端的配置方法,从基础设置到数据交互的完整流程。涵盖硬件准备、TIA Portal配置、MB_CLIENT指令参数详解、数据缓冲区管理及实战测试,帮助工程师快速掌握西门子PLC与Modbus TCP通信的关键技术。

fire9的博客 312

(3.4)client源码——Kafka 网络层实现机制之 Selector 多路复用器

org.apache.kafka.common.network.Selector,该类是 Kafka 网络层最重要最核心的实现,也是非常经典的工业级通信框架实现转发自 图解 Kafka 网络层实现机制之 Selector 多路复用器

weixin_43930865的博客 555

57. SAP UI5 应用基于 OData 注解的 Smart Field 使用方法学习

所谓 SAP UI5 Smart Field,顾名思义,是一类比较`智能`的控件,这类控件同 SAP UI5 传统的控件不同,会根据 SAP UI5 应用程序连接的 OData 服务中元数据里提供的注解(`annotations`),在运行时动态生成底层的 SAP UI5 控件。...

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2774

AutoSAR系列讲解(深入篇)14.7-Mcal Adc配置(上)

详细讲解了ADC的各个配置项的作用

雪云飞星的博客 1万+

Kafka的源码解读(一)-- 生产者

Kafka的源码解读(一)-- 生产者 ​ 该文档及之后的的kafka源码解读均以kafka2.4.0版本进行解读。kafka是用NIO作为通信基础的,这里不做赘述,如有需要连接NIO基础的课参考以下链接: https://editor.youkuaiyun.com/md/?articleId=113486103 生产者发送数据流程解读 ​ 生产者发送消息的流程简图如下: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iEmm4Tn2-1612792370084)(/Users/deng

guoqing2017的博客 1706

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

kafka源码生产者消息笔记

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200318160824859.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0phbWVzQmFpTG92ZQ==,size_16,color_FFFF...

JamesBaiLove的博客 235

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

apache kafka系列之源码分析走读-kafkaApi详解

Kafka源码中数据交互流程 图1 1.概述 kafka启动时做很多初始化运行环境工作,具体请参考:apache kafka系列之源码分析走读-kafka内部模块分析 其中SockeServer类启动时,首先初始化NIO网络环境、启动监听、创建主线程、工作线程池、设置参数等等。 从上图1中可以看到整个交互过程中,kafka的所有逻辑处理和交互实际是交给KafkaApi类来处理的。

李志涛的专栏 4673

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Kafka源码分析-序列4 -Producer -network层核心原理

在上一篇我们分析了Java NIO的原理和使用方式,本篇将进一步分析Kafka client是如何基于NIO构建自己的network层。 [size=large]network层的分层架构[/size] 下图展示了从最上层的KafkaProducer到最底层的Java NIO的构建层次关系: 图中淡紫色的方框表示接口或者抽象类,白色方框是具体实现。 整个架构图也体现了“面向接...

{丸の子} 121

Kafka2.0生产者客户端源码分析 - Sender线程

  Kafka 在初始化生产者客户端时,创建并启动 Sender 线程。通过 Sender 线程来发送消息、处理消息的响应。通过“volatile boolean running”状态控制 Sender 线程不断轮询,调用 NetworkClient 的 poll 方法。NetworkClient 是 Kafka 实现的用来和 broker 通信的类,实现了 KafkaClient 接口,底层实...

O'Neal 218
上一篇: Reactor模型示例
下一篇: Golang sync.WaitGroup源码详细分析
思维的深度
博客等级 码龄11年 2万+粉丝 391原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值