3.为什么还需要Netty呢?
那既然已经有了NIO包了,我们可以自己手动编写服务框架了,为什么还需要封装一个Netty框架呢?有什么好处呢?
好处当然是有很多了!我们从一开始实现的demo说起。
3.1 设计模式的优化
我们的demo确实已经能够工作了,但是还是有比较明显的问题。第4步(轮询已经就绪的通道)和第5步(对事件作相应处理)是在同一个线程中的,当事件处理比较耗时甚至阻塞时,整个流程就会阻塞了。
我们使用的实际上就是 “单Reactor单线程” 设计模式。
这种模型在Reactor中负责监听端口、接收请求,如果是连接事件交给acceptor处理,如果是读写事件和业务处理就交给handler处理,但始终只有一个线程执行所有的事情。
为了提高性能,我们理所当然相当可以把事件处理交给线程池,那就可以演进为 “单Reactor多线程” 设计模式。
这种模型和第一种模型的主要区别是把业务处理从之前的单一线程脱离出来,换成线程池处理。Reactor线程只处理连接事件、读写事件,所有业务处理都交给线程池,充分利用多核机器的资源,提高性能。
但是这仍然不够!
我们可以发现,一个Reactor线程承担了所有的网络事件,例如监听和响应,高并发场景下单线程存在性能问题。
为了充分利用多核能力,可以构建两个 Reactor,主 Reactor 单独监听server socket,accept新连接,然后将建立的 SocketChannel 注册给指定的从 Reactor,从Reactor再执行事件的读写、分发,把业务处理就扔给worker线程池完成。这就演进为 ”主从Reactor模式“ 设计模式。
所以,如果有人直接帮我们 封装好这样的设计模式 ,是不是太好了?
没错,Netty就是这样的“活雷锋”!
Netty就使用了主从Reactor模式封装了Java NIO包的使用,大大提高了性能。
3.2 其他优点 (以后的核心知识点)
除了封装了高性能的设计模式外,Netty还有许多其他优点:
- 稳定性。 Netty 更加可靠稳定,修复和完善了 JDK NIO 较多已知问题,包括 select 空转导致 CPU 消耗 100%、keep-alive 检测等问题。
- 性能优化。对象池复用技术。Netty 通过复用对象,避免频繁创建和销毁带来的开销。零拷贝技术。 除了操作系统级别的零拷贝技术外,Netty 提供了面向用户态的零拷贝技术,在 I/O 读写时直接使用 DirectBuffer,避免了数据在堆内存和堆外内存之间的拷贝。
- 便捷性。 Netty 提供了很多常用的工具,例如行解码器、长度域解码器等。如果我们使用JDK NIO包,那么这些常用工具都需要自己进行实现。
正是因为 Netty 做到了高性能、高稳定性、高易用性,完美弥补了 Java NIO 的不足,所以在我们在网络编程时,首选Netty,而不是自己直接使用Java NIO。