美文网首页
Netty的Reactor多线程模型,NioEventLoop,

Netty的Reactor多线程模型,NioEventLoop,

作者: alonwang | 来源:发表于2020-01-09 09:59 被阅读0次

    前言

    Reactor多线程

    如果在Google上搜索"Netty 高性能 易用",在找到的一大批文章,你大概率会看到这张图,外加关键字

    NIO,Reactor多线程模型,异步串行无锁化,堆外内存,pipeline ,翻看完这些文章后可以让你对Netty的原理有大致了解,但是Netty如何实现这些的呢? 本文将尽可能简单的解释Netty中Reactor多线程的实现,如有错误感谢指出.

    Selector

    Selector是NIO的重要组件, Selector上可以注册Channel. Channel在注册的时候会标注自己感兴趣的事件:

    • OP_CONNECT: 可连接 这个事件仅有客户端能使用
    • OP_ACCEPT: 新的客户端接入,即新的客户端连接.这个事件能且仅能服务端使用.
    • OP_READ: 可读 可以从Channel中读取数据
    • OP_WRITE: 可写 可以向Channel中写入数据

    Channel,通道,为了便于理解,我把它分为三类

    • ServerSocketChannel 服务端Channel 它负责新连接接入
    • SocketChannel 客户端Channel, 它负责客户端与服务端的连接,读,写
    • SocketChannel ServerSocketChannel收到连接请求时,会生成一个SocketChannel,它负责后续服务端与这个客户端的读,写

    Reactor多线程模型

    Reactor多线程

    Reactor多线程模型可以分为三块

    • 1~3 mainReactor负责客户端接入
    • 4~5 acceptor负责将接入的连接移交给subReactor
    • 6~9 subReactor负责连接的读写

    mainReactor负责客户端接入

    1. serverSocketChannel注册到mainSelector上,监听新连接接入(OP_ACCEPT)
    2. client1开始连接
    3. mainSelector通知serverSocketChannel有新连接接入

    acceptor负责将接入的连接移交给subReactor

    1. serverSocketChannel接受新连接,获得socketChannel

    2. socketChannel按照规则(轮询调度)注册到subSelector{n}上,监听读事件(OP_READ)

    subReactor负责连接的读写

    1. client发送数据

    2. subSelector通知SocketChannel有数据到达,socketChannel做相应的业务处理

    3. socketChannel需要对client发送数据,先向subSelector监听可写事件(OP_WRITE).

    4. subSelector通知socketChannel可写,socketChannel进行相应的业务处理

    关键知识:

    • Selector,多路复用器(multiplexer),是NIO的关键基础组件,主要功能是多路复用
    • acceptor是mainReactor和subReactor的连接桥梁. 运行时,它只是作为mainReactor中的一段逻辑存在.
    • subReactor有多个,新的连接会按照规则选择其中一个进行注册监听.多线程说的subReactor
    • Selector和线程的关系是1:1.也就是说 mainReactor占据一个线程, 每个subReactor占据一个线程.

    NioEventLoop

    NioEventLoop
    NioEventLoop就是对Reactor的封装. EventLoopGroup的基本组成如下图,结合Reactor模型,上面的mainReactor就是只有一个NioEventLoop的NioEventLoopGroup(为什么只有一个? 因为ServerSocketChannel只有一个),subReactor就是有多个NioEventLoop的EventLoopGroup
    • task queue 是一个 MPSCQ( multi producer single consumer queue),Netty中,channel的很多操作在执行前都会检查是否在对应的NioEventLoop线程中(SingleThreadEventExecutor.inEventLoop()),如果不在会将操作封装成任务丢到task queue里,以此实现Netty的异步串行无锁化
    • schedule task queue 是一个非线程安全的Priority Queue

    运行流程图

    NioEventLoop运行流程

    关键知识:

    • 当外部线程第一次向NioEventLoop的task queue放入任务时,会启动NioEventLoop对应的线程并开始这个流程
    • 就绪事件包含所有事件类型.OP_CONNECT(客户端会用到),OP_ACCEPT,OP_READ,OP_WRITE, 也就是说mainReactor和subReactor都在这里处理.
    • selector阻塞获取阶段和运行task queue中的所有task阶段的运行时间有一个平衡, 确保事件处理和任务执行的平衡.
    • schedule task在运行结束后会放回到schedule task queue里

    ChannelPipeline

    ChannelPipeline

    ChannelPipeline的设计思想是责任链设计模式,是由ChannelHandlerContext组成的双向链表, ,首尾固定为HeadContextTailContext,它们作为哨兵存在.当我们添加一个ChannelHandler到ChannelPipeline时,会先包装成ChannelHandlerContext再添加进去.

    inbound事件传播

    客户端向服务端发送消息,这个流向就称为inbound. 消息会从Head开始由左向右传递直到Tail,由Tail进行收尾操作

    outbound事件传播

    服务端向客户端发送信息,这个流向称为outbound,消息会从Tail开始由右向左传递知道Head,由Head进行收尾操作

    异常传递

    当某个ChannelHandler操作抛出异常,会从该handler开始向Tail传递.由Tail做收尾操作.

    结语

    学习Netty,要理解Reactor模型,并把它和Netty的实现结合起来, 我学习Netty的时候就因为这块认识不深刻,浪费了很多时间也没有成效,共勉


    https://blog.csdn.net/difffate/article/details/69458588

    https://blog.csdn.net/jjzhk/article/details/39553613

    https://www.jianshu.com/p/a9b2fec31fd1

    https://www.jianshu.com/p/a9d030fec081

    https://juejin.im/post/5b4570cce51d451984695a9b

    https://www.jianshu.com/p/2461535c38f3

    https://juejin.im/post/5a126b146fb9a0450c490201

    相关文章

      网友评论

          本文标题:Netty的Reactor多线程模型,NioEventLoop,

          本文链接:https://www.haomeiwen.com/subject/ooiloctx.html