常用的NIO框架-Netty

架构师-网络文章汇总
1. Netty简介Netty是一个高性能、异步事件驱动的NIO框架 , 基于JAVA NIO提供的API实现 。 它提供了对TCP、UDP和文件传输的支持 , 作为一个异步NIO框架 , Netty的所有IO操作都是异步非阻塞的 , 通过Future-Listener机制 , 用户可以方便的主动获取或者通过通知机制获得IO操作结果 。作为当前最流行的NIO框架 , Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用 , 一些业界著名的开源组件也基于Netty的NIO框架构建 。
2. Netty线程模型在JAVA NIO方面Selector给Reactor模式提供了基础 , Netty结合Selector和Reactor模式设计了高效的线程模型 。 先来看下Reactor模式:
2.1 Reactor模式
Wikipedia这么解释Reactor模型:“The reactor design pattern is an event handling pattern for handling service requests delivered concurrently by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to associated request handlers.” 。 首先Reactor模式首先是事件驱动的 , 有一个或者多个并发输入源 , 有一个Server Handler和多个Request Handlers , 这个Service Handler会同步的将输入的请求多路复用的分发给相应的Request Handler 。 可以如下图所示:
常用的NIO框架-Netty文章插图
从结构上有点类似生产者和消费者模型 , 即一个或多个生产者将事件放入一个Queue中 , 而一个或者多个消费者主动的从这个队列中poll事件来处理;而Reactor模式则没有Queue来做缓冲 , 每当一个事件输入到Service Handler之后 , 该Service Handler会主动根据不同的Evnent类型将其分发给对应的Request Handler来处理 。
2.2 Reator模式的实现
关于Java NIO 构造Reator模式 , Doug lea在《Scalable IO in Java》中给了很好的阐述 , 这里截取PPT对Reator模式的实现进行说明
1.第一种实现模型如下:
常用的NIO框架-Netty文章插图
这是最简单的Reactor单线程模型 , 由于Reactor模式使用的是异步非阻塞IO , 所有的IO操作都不会被阻塞 , 理论上一个线程可以独立处理所有的IO操作 。 这时Reactor线程是个多面手 , 负责多路分离套接字 , Accept新连接 , 并分发请求到处理链中 。
对于一些小容量应用场景 , 可以使用到单线程模型 。 但对于高负载 , 大并发的应用却不合适 , 主要原因如下:

  1. 当一个NIO线程同时处理成百上千的链路 , 性能上无法支撑 , 即使NIO线程的CPU负荷达到100% , 也无法完全处理消息
  2. 当NIO线程负载过重后 , 处理速度会变慢 , 会导致大量客户端连接超时 , 超时之后往往会重发 , 更加重了NIO线程的负载 。
  3. 可靠性低 , 一个线程意外死循环 , 会导致整个通信系统不可用
为了解决这些问题 , 出现了Reactor多线程模型 。
2.Reactor多线程模型:
常用的NIO框架-Netty文章插图
相比上一种模式 , 该模型在处理链部分采用了多线程(线程池) 。
在绝大多数场景下 , 该模型都能满足性能需求 。 但是 , 在一些特殊的应用场景下 , 如服务器会对客户端的握手消息进行安全认证 。 这类场景下 , 单独的一个Acceptor线程可能会存在性能不足的问题 。 为了解决这些问题 , 产生了第三种Reactor线程模型
3.Reactor主从模型
常用的NIO框架-Netty文章插图
该模型相比第二种模型 , 是将Reactor分成两部分 , mainReactor负责监听server socket , accept新连接;并将建立的socket分派给subReactor 。 subReactor负责多路分离已连接的socket , 读写网络数据 , 对业务处理功能 , 其扔给worker线程池完成 。 通常 , subReactor个数上可与CPU个数等同 。
2.3 Netty模型
2.2中说完了Reactor的三种模型 , 那么Netty是哪一种呢?其实Netty的线程模型是Reactor模型的变种 , 那就是去掉线程池的第三种形式的变种 , 这也是Netty NIO的默认模式 。 Netty中Reactor模式的参与者主要有下面一些组件:
  1. Selector
  2. EventLoopGroup/EventLoop
  3. ChannelPipeline
Selector即为NIO中提供的SelectableChannel多路复用器 , 充当着demultiplexer的角色 , 这里不再赘述;下面对另外两种功能和其在Netty之Reactor模式中扮演的角色进行介绍 。
3.EventLoopGroup/EventLoop当系统在运行过程中 , 如果频繁的进行线程上下文切换 , 会带来额外的性能损耗 。 多线程并发执行某个业务流程 , 业务开发者还需要时刻对线程安全保持警惕 , 哪些数据可能会被并发修改 , 如何保护?这不仅降低了开发效率 , 也会带来额外的性能损耗 。