Netty解析-线程模型

本文中心路线

  1. 传统IO模型(NIO出现之前,也就是BIO)
  2. Reactor模型(异步、非阻塞,事件驱动模型)
  3. Netty对Reactor模型的实现

1、传统IO模型(NIO出现之前,也就是BIO)

我们先来看BIO的线程通讯模型

Netty解析-线程模型

解释

  1. Application(应用端)发起请求(用户线程)到Kernel(计算机内核)
  2. 内核处理中数据尚未准备好,测试Application端请求处于等待数据状态
  3. 直到Kernel数据处理完毕,将数据从内核拷贝到用户线程
  4. 拷贝完数据后返回到Applicatoin,处理数据

题外话:整个过程,线程从发起从用户态到内核态再到用户态都是同步的,并且用户线程一直处于等待状态直到结果返回

2、Reactor模型(异步、非阻塞,事件驱动模型)

Reactor模型(反应器模式)分为3类:单线程、多线程、主从多线程

   1、单线程Reactor模型

Netty解析-线程模型

解释

  1. 多个Client同时发送请求到Server后注册通知事件,直接返回,不阻塞等待(Selecter单线程死循环扫描)
  2. Server端用一个线程去接收请求并分配Handler去处理(每个handler是一个线程)
  3. Handler处理完毕后调用第1步注册的通知事件返回结果

缺点:

      虽然我们实现了Client请求不阻塞,请求异步处理,单图中可看到接收请求并分配handler仍是单线程处理,依然存在问题

     1、单线程浪费CPU资源

     2、如果在图中单线程部分有处理异常,就会出现阻塞,Client并发太多时也会出现瓶颈

所以引来多线程

2、多线程Reactor模型

Netty解析-线程模型

解释

  1. 和单线程相比目前只有接收请求线程的地方是处于单线程
  2. 接收线程分配handler处理时使用线程池技术进行多线程异步处理,handler之间互不影响

缺陷:

       我们看到acceptor线程部分仍处于单线程接收状态,如果有大IO操作势必影响其它

从而引入了主从多线程

3、主从多线程Reactor模型

Netty解析-线程模型

 解释:

      1、与多线程相比,Reactor由一个分为mainReactor和subReactor

      2、mainReactor:主要用于接收客户端请求,将接收到的SocketChannel传递给subReactor,由subReactor负责跟客户端进行通讯

      3、好处:mainReactor只负责接收客户端请求并适配subReactor不负责真正通讯,每个subReactor线程存在独立的Selector、线程、事件逻辑,不会因为大IO阻塞其它线程

3、Netty对Reactor模型的实现

    1、模式对应:
        Netty服务端使用了“多Reactor线程模式”
        mainReactor ———— bossGroup(NioEventLoopGroup) 中的某个NioEventLoop
        subReactor ———— workerGroup(NioEventLoopGroup) 中的某个NioEventLoop
        acceptor ———— ServerBootstrapAcceptor
        ThreadPool ———— 用户自定义线程池

   2、Netty启动流程(摘自网络,尚未验证,大概流程应该正确)

  1.  当服务器程序启动时,会配置ChannelPipeline,ChannelPipeline中是一个ChannelHandler链,所有的事件发生时都会触发Channelhandler中的某个方法,这个事件会在ChannelPipeline中的ChannelHandler链里传播。然后,从bossGroup事件循环池中获取一个NioEventLoop来现实服务端程序绑定本地端口的操作,将对应的ServerSocketChannel注册到该NioEventLoop中的Selector上,并注册ACCEPT事件为ServerSocketChannel所感兴趣的事件。
  2.  NioEventLoop事件循环启动,此时开始监听客户端的连接请求。
  3. 当有客户端向服务器端发起连接请求时,NioEventLoop的事件循环监听到该ACCEPT事件,Netty底层会接收这个连接,通过accept()方法得到与这个客户端的连接(SocketChannel),然后触发ChannelRead事件(即,ChannelHandler中的channelRead方法会得到回调),该事件会在ChannelPipeline中的ChannelHandler链中执行、传播。
  4.  ServerBootstrapAcceptor的readChannel方法会该SocketChannel(客户端的连接)注册到workerGroup(NioEventLoopGroup) 中的某个NioEventLoop的Selector上,并注册READ事件为SocketChannel所感兴趣的事件。启动SocketChannel所在NioEventLoop的事件循环,接下来就可以开始客户端和服务器端的通信了。