1. 原生NIO存在的问题

  1. NIO的类库和API繁杂,使用麻烦。需要熟练掌握Selector, ServerSocketChannel, SocketChannel, ByteBuffer等。
  2. 开发工作量和难度都非常大:例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常流的处理等等。

2. Netty官方说明

在这里插入图片描述

  1. Netty 是由JBOSS提供的一个Java开源框架,Netty提供异步的,基于事件驱动的网络应用程序框架,用以快速开发高性能,高可靠的网络IO程序。
  2. Netty 可以帮助你快速、简单的开发出一个网络应用,相当于简化和流程化了 NIO 的开发过程。
  3. Netty 是目前最流行的 NIO 框架,Netty 在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,知名的 Elasticsearch 、Dubbo 框架内部都采用了 Netty。

3. Netty的优点

  1. 设计优雅:适用于各种传输类型的统一 API 阻塞和非阻塞 Socket;基于灵活且可扩展的事件模型,可以清晰地分离关注点;高度可定制的线程模型 - 单线程,一个或多个线程池.
  2. 高性能、吞吐量更高:延迟更低;减少资源消耗;最小化不必要的内存复制。

4. 线程模型基本介绍

  1. 目前存在的线程模型:
  • 传统阻塞IO服务模型
  • Reactor模式

5. Reactor模式

5.1 单Reactor单线程

在这里插入图片描述
前面的群聊实例就是这种方式:服务器端用一个线程通过多路复用搞定所有的 IO 操作(包括连接,读、写等),编码简单,清晰明了,但是如果客户端连接数量较多,将无法支撑,前面的 NIO 案例就属于这种模型。
方案优缺点分析:

  1. 优点:模型简单,没有多线程,进程通信,资源竞争问题。全部在一个线程中完成。
  2. 缺点:性能问题,只有一个线程,无法完全发挥多核CPU的性能
  3. 使用场景:客户端的数量有限,业务处理非常快速,比如 Redis在业务处理的时间复杂度 O(1) 的情况

5.2 单Reactor多线程

在这里插入图片描述

说明:

  1. Reactor对象通过select 监控客户端请求时间,收到事件后,通过dispatch进行分发。
  2. 如果建立连接请求,则acceptor荣国accept处理请求,然后创建handler对象处理完成连接后的各种事件
  3. 如果不是连接请求,则由reactor分发调用连接对应的handler处理。
  4. handler只负责响应事件,不做具体的业务处理,通过read读取数据后,分发给后面的worker线程池的某个线程处理任务。
  5. worker线程池会分配独立线程完成真正的业务,并将结果返回给handler.
  6. handler收到响应后,通过send将结果返回client
    方案优缺点分析:
  7. 优点:可以充分利用多核cpu的处理能力
  8. 缺点:多线程数据共享和访问比较复杂,reactor处理所有的事件的监听和响应,在单线程运行,在高并发场景容易出现性能瓶颈。
  9. 使用场景:客户端的数量有限,业务处理非常快速,比如 Redis在业务处理的时间复杂度 O(1) 的情况

5.3 主从Reactor多线程

在这里插入图片描述

说明:

  1. Reactor主线程MainReactor对象通过select监听连接事件,收到事件后,通过acceptor处理连接事件。
  2. 当acceptor处理连接事件后,MainReactor将连接分配给SubReactor.
  3. subreactor将连接加入连接队列进行监听,并创建handler进行各种事件处理
  4. 当有新事件发生时,subreactor调用对应的handler进行处理
  5. handler通过reade读取数据,分发给后面的worker线程池处理
  6. worker线程池分配独立的线程进行业务处理,并返回结果
  7. handler收到响应的结果后,再通过send将结果返回给client
  8. reactor主线程可以对应多个reactor子线程,即MainReactor可以关联多个subreactor
    方案优缺点分析:
  9. 优点:父线程和子线程的数据交互简单职责明确,父线程只需要接受新连接,子线程完成后续的业务处理。
  10. 缺点:编程难度高。
  11. 使用场景:这种模型在许多项目中广泛使用,包括 Nginx 主从 Reactor 多进程模型,Memcached 主从多线程,Netty 主从多线程模型的支持

6. Reactor模式小结

  1. 单Reactor单线程,前台接待员和服务员是同一个人
  2. 单Reactor多线程,1个前台接待员,多个服务员。
  3. 主从Reactor多线程,多个前台接待员,多个服务员。
    Reactor模式优点:
  4. 响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的
  5. 可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销
  6. 扩展性好,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源
  7. 复用性好,Reactor 模型本身与具体事件处理逻辑无关,具有很高的复用性

7. Netty模型

7.1 Netty简单版

Netty主要基于主从reactors多线程模型做了一定的改进,其中主从reactor多线程模型有多个reactor
在这里插入图片描述
说明:

  1. BossGroup线程维护selector,他只关注accept
  2. 当接收到accept事件后,获取到对应的socketchannel,封装成NIOsocketChannel并注册到worker线程(事件循环),并进行维护
  3. 当worker线程监听到selector中通道发生自己感兴趣的事件后,就进行处理(hanlder).注意handler已经加入到通道中。

7.2 Netty进阶版

在这里插入图片描述

7.2 Netty详细版

在这里插入图片描述说明:

  1. Netty抽象出两组线程池BossGroup专门负责接受客户端的连接,workerGroup专门负责网络的读写
  2. BossGroup和workerGroup类型都是NIOEventLoopGroup
  3. NIOEventLoopGroup 相当于是一个事件循环组,这个组中包含多个事件循环,每一个事件循环都是NIOEventLoop.
  4. NIOEventLoop表示一个不断循环的执行处理任务的线程,每个NIOEventLoop都有一个selector,用户监听绑定在其上的socket网络通讯。
  5. NIOEventLoopGroup可以有多个线程,即可以含有多个NIOEventLoop
  6. 每个bossNIOEventLoop循环执行的步骤有三步
  • 轮询accept事件
  • 处理accept事件,与client建立连接,生成NIOsocketChannel并将其注册到某个wokerNIOEventLoop上的selector。
  • 处理任务队列的任务,即runAllTasks
  1. 每个workerNIOEventLOOP循环执行的步骤
  • 轮询read,write事件
  • 处理IO事件,即read,write事件,在对应NIOSocketChannel处理
  • 处理任务队列的任务,即runAllTasks
  1. 每个workerNIOEventLoop处理业务时,会使用pipeline(管道)pipeline中包含了channel,即通过pipeline可以获取到对应的管道,管道中维护了很多的处理器。