目录
用三点来简单的介绍下Netty:
面试官:哦,还不错,那你在说说为什么要用Netty?
面试官:那你在通俗地说一下Netty可以做什么事情?
面试官:那,在说说Netty有几种线程模型吧?
这是最基本的单Reactor单线程模型
多线程单Reactor模型
多线程多Reactor模型
Netty相比于直接使用JDK自带的NIO相关的API来说更加易用。同时,它还具有以下特点:
1.统一的API,支持多种传输类型,如阻塞、非阻塞,以及epoll、poll等模型。
2.我们可以使用非常少的代码来实现,多线程Reactor模型以及主从多线程Reactor模型。
3.自带编解码器解决TCP粘包/拆包问题。
4.自带各种协议栈。
5.比直接使用Java库中的NIOAPI有更高的吞吐量、更低的延迟、更低的资源消耗和更少的内存复制。
6.安全性不错 ,有完整的SSL/TLS以及StartTLS支持。
7.社区活跃成熟稳定,经历了大型项目的使用和考验,而且很多开源项目都使用到了Netty,比如我们经常接触的Dubbo、RocketMQ等等。
我们之所以要用Netty,核心点还是在于解决服务器如何承载更多的用户同时访问的问题。
传统的BIO模型,由于阻塞的特性,使得在高并发场景中,很难获得更高的吞吐量。而后来基于NIO的多路复用模型虽然在阻塞方面进行了优化,但是它的API使用比较复杂,对于初学者来说使用不是很友好。而Netty是基于NIO的封装,提供了成熟且简单易用的API,降低了使用成本和学习成本。
本质上来说,Netty和NIO所扮演的角色是相同的,都是为了提升服务端的吞吐量,让用户获得更好的产品体验。
另外,Netty这个中间件经过很多年的验证,在目前主流的中间件如Zookeeper、Dubbo、RocketMQ中都有应用。
面试官:Netty核心组件了解吗?分别有什么作用?
高手:Netty由三层结构构成:网络通信层、事件调度器与服务编排层
在网络通信层有三个核心组件:Bootstrap、Server Boot Strap、Channel
事件调度器有两个核心组件:EventLoopGroup与EventLoop
在服务编排层有三个核心组件:ChannelPipeline、ChannelHandler、ChannelHandlerContext
高手Netty提供了三种Reactor模型的支持:
面试官:你说一下对于这三种线程Reactor模型的理解?
高手:Reactor模型有三个重要的组件:
1. Reactor:将I/O事件发派给对应的Handler
2.Acceptor:处理客户端连接请求
3.Handlers:执行非阻塞读/写
我们来看这张图:
其中Reactor线程,负责多路分离套接字,有新连接到来触发connect事件之后,交由Acceptor进行处理,有IO读写事件之后交给hanlder处理。
Acceptor主要任务就是构建handler,在获取到和client相关的SocketChannel之后,绑定到相应的hanlder上,对应的SocketChannel有读写事件之后,基于reactor分发,hanlder就可以处理了(所有的IO事件都绑定到selector上,有Reactor分发)
单线程Reactor这种实现方式有存在着缺点,从实例代码中可以看出,handler的执行是串行的,如果其中一个handler处理线程阻塞将导致其他的业务处理阻塞。由于handler和reactor在同一个线程中的执行,这也将导致无法接收新的请求。
为了解决这种问题,有人提出使用多线程的方式来处理业务,也就是在业务处理的地方加入线程池异步处理,将reactor和handler在不同的线程来执行,这就是多线程单Reactor模型。
在多线程单Reactor模型中,所有的I/O操作是由一个Reactor来完成,而Reactor运行在单个线程中,它需要处理包括Accept()/read()/write/connect操作,对于小容量的场景,影响不大。但是对于高负载、大并发或大数据量的应用场景时,容易成为瓶颈,主要原因如下:
Sub Reactor,Main Reactor通常监听客户端连接后会将通道的读写转发到Sub Reactor线程池中一个线程(负载均衡),负责数据的读写。在NIO中通常注册通道的读(OP_READ)、写事件(OP_WRITE)。