Netty 是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。
Netty是对Java自带的NIO的封装。虽然Java自带了网络应用程序的API,但是存在一系列问题,主要体现如下:
使用复杂:NIO 的类库和 API 繁杂,使用麻烦。你需要熟练掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer 等。
掌握难度大:需要具备其他的额外技能做铺垫。例如熟悉 Java 多线程编程,因为 NIO 编程涉及到 Reactor 模式,你必须对多线程和网路编程非常熟悉,才能编写出高质量的 NIO 程序。
健壮性差:可靠性能力补齐,开发工作量和难度都非常大。例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理等等。 NIO 编程的特点是功能开发相对容易,但是可靠性能力补齐工作量和难度都非常大。
内部BUG:JDK NIO 的 Bug。例如臭名昭著的 Epoll Bug,它会导致 Selector 空轮询,最终导致 CPU 100%。 官方声称在 JDK 1.6 版本的 update 18 修复了该问题,但是直到 JDK 1.7 版本该问题仍旧存在,只不过该 Bug 发生概率降低了一些而已,它并没有被根本解决。
Netty主要特点如下:
设计优雅:适用于各种传输类型的统一 API 阻塞和非阻塞 Socket;基于灵活且可扩展的事件模型,可以清晰地分离关注点;高度可定制的线程模型 - 单线程,一个或多个线程池;真正的无连接数据报套接字支持。
使用方便:详细记录的 Javadoc,用户指南和示例;没有其他依赖项,JDK 5(Netty 3.x)或 6(Netty 4.x)就足够了。
高性能:吞吐量更高,延迟更低;减少资源消耗;最小化不必要的内存复制。
安全:完整的 SSL/TLS 和 StartTLS 支持。
社区活跃,不断更新,社区活跃,版本迭代周期短,发现的 Bug 可以被及时修复,同时,更多的新功能会被加入。
典型使用场景:
互联网行业:Dubbo的RPC通信框架使用Dubbo协议进行节点间的数据传输,Dubbo协议底层使用netty做基础通信控件;
游戏行业:netty+socketio 做IM(及时通信);
物联网行业:netty做数据网关。
Netty的高性能体现在什么地方:
1 io模型:负责数据的接入和发送
2 线程处理模型:负责数据的处理
Io模型:
阻塞IO:
传统的 I/O 是面向字节流或字符流的,以流式的方式顺序地从一个 Stream 中读取一个或多个字节, 因此也就不能随意改变读取指针的位置
IO复用模型:
(其中select是阻塞型的、数据复制是阻塞的,但是数据的读和写是并行的)
Netty的非阻塞IO是基于IO复用模型来实现的,Netty 的 IO 线程 NioEventLoop 由于聚合了多路复用器 Selector,可以同时并发处理成百上千个客户端连接。一个线程在空闲时,可以做IO的读取操作,它不需要时时刻刻监听数据的输入,只有在select的时候才做数据的接入工作。空闲时候可以做IO的读取和写入。
在 NIO 中,抛弃了传统的 I/O 流,而是引入了 Channel 和 Buffer 的概念。在 NIO 中,只能从 Channel 中读取数据到 Buffer 中或将数据从 Buffer 中写入到 Channel
线程处理模型:
事件驱动模型:发生事件,主线程把事件放入事件队列,在另外线程不断循环消费事件列表中的事件,调用事件对应的处理逻辑处理事件。事件驱动方式也被称为消息通知方式,其实是设计模式中观察者模式的思路。
Reactor线程模型:
对多路复用IO的输入进行监听,收到请求后dispatch到不同的处理线程(handler),它主要包含如下2个部分:
Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人。
Handlers:处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。
根据reactor的数量和handler的数量,reactor线程模型主要分为如下3个变种:
单reactor单线程;
单reactor多线程;
主从reactor多线程;
Netty的线程模式就是主从reactor多线程模型,如下图所示:
其中mainReactor和subReactor就是2个线程池,其中subReactor和workgroup公用一个线程池。