`
vinceall
  • 浏览: 10300 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Netty源码分析2---服务端读写流程

阅读更多

上次分析了服务端bind流程,今天继续看服务端读写流程。

 

术语:worker---NioWorker对象,BT---boss线程,IOT---worker线程,UT---用户线程

 

先说一下前提条件:所有与具体连接相关的IO操作都是由IOT负责完成的,并且handler也是在IOT执行的,所以才说耗时的操作要自己起线程,不要交给IOTIOT不是拿给你独占的。

 

服务端读

① bind并注册OP_ACCEPTselector后,BT一直不停轮询selection key,当有连接上来时acceptnew一个NioAcceptedSocketChannel对象channel,把它传给NioWorker.RegisterTask对象,投递给IOT,让IOT去注册OP_READ到它对应的workerselector上(注册时把channel当做attachment同时注册上去):

 

public void run() {

            SocketAddress localAddress = channel.getLocalAddress();

            SocketAddress remoteAddress = channel.getRemoteAddress();

            if (localAddress == null || remoteAddress == null) {

                if (future != null) {

                    future.setFailure(new ClosedChannelException());

                }

                close(channel, succeededFuture(channel));

                return;

            }

            try {

                if (server) {

                    channel.channel.configureBlocking(false);

                }

                channel.channel.register(

                        selector, channel.getRawInterestOps(), channel);

……

NioWorker内部类RegisterTask.run

 

然后IOT去轮询上面的selectorselection key

 

② 当收到数据时,selector返回selection key,从中可以获取注册时放进去的channel(个人认为attachment可以作为一种保存物理连接和逻辑连接映射关系的手段),然后从channel中读取数据。

 

③ NioWorker.read方法负责具体读数据,主要逻辑是调channel.read读数据,前面是根据预设的sizerecvBufferPool缓存池中获得一个ByteBuffer,以及设置字节顺序等操作。成功读完就清理ByteBuffer,把channelbuffer传给handler,然后fireMessageReceived。通常我们处理request的业务逻辑就放在这里,所以从这儿也可以看出确实是IOT在执行messageReceivedIOT耗不起啊。。。如果读失败则fireExceptionCaught

 

服务端写

写是IOT负责的,发起写数据请求的可能是IOTmessageReceived发起的写就是IOT本身)或者其它线程(如UT

 某线程在Netty层发起写操作,经过之前讲的down stream层层处理、转发后,最终到NioServerSocketPipelineSink.eventSunkàhandleAcceptedSocket,从MessageEvent中获取channel和消息,将消息放入channel对应的writeBufferQueue中,这一步实现了数据的入队操作。

 

 然后继续调worker.writeFromUserCode,其中对当前线程是否为IOT作了判断:

    1) 如果不是则投递一个writeTaskworker.taskQueue上,等IOT下次processTaskQueuepoll出来执行,这一步实现了writeTask的入队操作。

    2) 如果是则直接调write0写数据。

  这样设计的优势:可以避免当前线程是IOT时,投递task带来的线程切换开销,因为当前线程是IOT时,如果直接投递,则只能等下一次IOT获取到CPU进行循环时才能从taskQueue pollwriteTask了,这样的话既有线程切换开销,还会带来延迟,所以判断一次可以优化写的效率。

 

③ 如果是UT投递的任务,会调writeFromTaskLoop,另外还有个writeFromSelectorLoop,是当selectOP_WRITEIOT发起的,用户发起的写操作都是调用writeFromUserCode,这三个write方法最终都调用write0

 

④ write0内部流程:

    1) channel.writeLock加锁,锁住写操作,目的是防止其它线程调cleanUpWriteBuffer,从writeBufferQueuepoll,导致write0 poll不到任务(例如其它线程调channel.close就会去操作writeBufferQueue

    2) 检查channel.currentWriteEvent,若未被清空则说明之前的写操作还未完成,则继续从currentWriteBuffer中获取之前的byteBuf;若已清空则说明上次写操作成功完成,此时则从writeBufferQueuepollbyteBuf,然后将byteBuf包装为sendBuffer

    3) 根据预先配置的writeSpinCount,尝试多次写入数据,类似于自旋,这里作了写优化:当selectOP_WRITE,而在写入时返回0,不一定代表连接被关闭。在该情况下,一般可通过再次注册OP_WRITE等待下次select,但缺点是selectOS发起的系统调用,涉及到用户态和内核态的切换,开销大。所以这里的优化方式是通过自旋多尝试几次,尽量延迟注册。

    4) 发送完后清空currentWriteBuffer等,若未写完(可能kernel buffer满了)则设addOpWritechannel.writeSuspended标记,前者用于再次注册OP_WRITE,等kernel buffer可用时由发起writeFromSelectorLoop,并根据channel是否open确定是addOpWrite or removeOpWrite;后者控制的是用户发起的和taskQueue /selector发起的写操作,同时只能有一个。

    5) 最后根据当前线程是否为IOT,确定fireWriteComplete/fireWriteCompleteLater

注:write时判断若为IOT则直接写的缺点是当前线程若被中断会引起channel关闭,这个还不理解。。。

 

总的来说读写都不复杂,读比写简单,最近时间稍微多一点,简单分析了一下服务端的线程模型,有些自己的理解,也不晓得对不对,改天贴上来大家讨论。

 

本人辛苦分析、码字,请尊重他人劳动成果,转载不注明出处的诅咒你当一辈子一线搬砖工,嘿嘿~

欢迎讨论、指正~~

 

下篇预告:服务端线程模型分析

1
0
分享到:
评论

相关推荐

    精通并发与netty视频教程(2018)视频教程

    47_Netty服务器与客户端编码模式回顾及源码分析准备 48_Netty与NIO系统总结及NIO与Netty之间的关联关系分析 49_零拷贝深入剖析及用户空间与内核空间切换方式 50_零拷贝实例深度剖析 51_NIO零拷贝彻底分析与Gather...

    精通并发与netty 无加密视频

    第47讲:Netty服务器与客户端编码模式回顾及源码分析准备 第48讲:Netty与NIO系统总结及NIO与Netty之间的关联关系分析 第49讲:零拷贝深入剖析及用户空间与内核空间切换方式 第50讲:零拷贝实例深度剖析 第51讲...

    精通并发与 netty 视频教程(2018)视频教程

    52_NioEventLoopGroup源码分析与线程数设定 53_Netty对Executor的实现机制源码分析 54_Netty服务端初始化过程与反射在其中的应用分析 55_Netty提供的Future与ChannelFuture优势分析与源码讲解 56_Netty服务器地址...

    基于springcloud+Netty+MQ+mysql的分布式即时聊天系统源码+数据库+项目说明.zip

    2. conntector 与 connector-2 这两个模块并不一样,connector-2 使用了 Dubbo 进行消息转发(实验阶段),而 connector 使用 Feign 进行 HTTP 调用转发消息。启动 connector 就行了。 3. 每个服务都允许运行多个...

    java开源包3

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    JAVA上百实例源码以及开源项目源代码

    Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...

    JAVA上百实例源码以及开源项目

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术,...

    java开源包2

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包8

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包1

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包10

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包11

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包6

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包5

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包4

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包7

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包9

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包101

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    Java资源包01

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

Global site tag (gtag.js) - Google Analytics