随笔分类
论述 NIO与 Netty间的点点滴滴
说起 Netty,我们脑海里第一印象便是 异步非阻塞的高性能 NIO框架,那 Netty究竟对 NIO进行了哪些改造,为什么 Netty始终是网络通信里的王者?
可以先从 NIO开始讲起,都说 Java程序员是生活在甜蜜罐里,实际上我们去使用的关于网络流编程相关的类都是经过封装的,Socket、FileDescription实际上都是抽象的东西,底层都是对 os层面的封装,比如说 Socket本身就是抽象的,SocketImpl是其具体实现,而我们常说的 Socket在 os中对应的便是一个个的文件描述符,对应的便是 FileDescription
而原生封装的 Socket使用起来仍然很复杂,so,对其进行了封装,进而衍生出 Channel,其是对 Socket的装饰增强,简单来说,其承载着 Socket;而 Channel本身是个接口,而基于接口我们可以通过多继承的方式实现接口功能的扩展,进而衍生出 InterruptibleChannel、SelectableChannel、NetworkChannel,分别实现了赋予 Channel可被中断处理、可多路复用、可进行网络之能力,似乎功能实现起来还不错,已经能够简化我们的通信 coding了
但这还不够,还是存在许多冗余代码,部分类的 API使用起来不够人性化 (如 ByteBuffer),so,陆续就有了基于 NIO实现的一些框架
Netty便是在这时脱颖而出,其解决了什么问题,带来的好处是什么,想必我们已经是熟悉无比
不过笔者认为,除了在系统性能上进行的优化外,Netty中进行代码的设计更是赏心悦目,其对传统的 NIO进行了逻辑上的抽取,如抽取出了一个 EventLoop,使得代码逻辑上显得更加清晰明了;而且我们能通过书写少量的代码实现双端之间的通信,这是 NIO所做不到的,但注意的是,代码量少了,并不意味着 底层要去干的事少了,实际上 Netty为我们兜着呢,这块在 启动流程上体现得淋漓尽致;
且,Netty通过 handler、ctx、pipeline的设计,使得上层业务对数据或某事件进行响应时,如同一道道的工序,看起来就很舒服 ~
且,Netty还去解决了 Linux下 epoll无限轮询的 bug,这是 NIO并没有去解决的痛点,即 Netty为我们进行了兜底
其次,我们知道 NIO离不开 直接内存,或许我们在使用时并没有直接去使用直接内存,比如我们创建的 ByteBuffer使用的是基于 堆内存进行创建的,但是,当我们数据通过网卡发送到对端时,使用的是系统服务,即其对应着便是直接内存的使用,即涉及用户态数据和内核态数据的一次拷贝,若是能直接去使用直接内存,这就够减少一次内存拷贝
so,基于直接内存的创建和销毁上的开销,Netty便使用了 池化技术 (对象池和内存池),这便优化了系统性能,因为由 Netty去管理内存的话,便可以实现一系列的基于内存的详细申请策略
但,我们需明知一点,直接内存使用起来虽然方便 (不用再去担心由于 GC到导致的对象地址发生改变的问题),但是也会涉及到内存资源泄漏的风险,so,DirectByteBuffer实现了弱引用,最终由其 cleaner实现内存的回收,这便解决了内存资源泄漏!
行吧,有关 Netty的先扯这么些,Netty学习就先告一段落了...