三、揭开Netty的神秘面纱
目标:网络应用开发框架。
实现:异步、事件驱动。
特性:高性能、可维护、极速开发。
用途:服务端、客户端开发。
四、为何舍近求远、不直接使用JDK的NIO
Netty做的更多:
支持常用应用层协议;
解决了传输问题:沾包、半包;
支持流量整形;
完善的断连、Idle等异常处理机制。
Netty做的更好:
规避了JDK NIO部分bug: linux2.4 epoll bug之异常唤醒空转导致的CPU满载,Netty检测到空转次数到达阈值则重置Selector。
JDK12才解决的IP_TOS(IP包的优先级和QoS选项)使用时抛出的异常:Netty直接绕过,不支持该选项。
API更友好更强大:
JDK NIO的一些API不够友好,功能薄弱,Byte Buffer(只有一个索引,读写手动flip,基于数组不方便扩容) -> Netty‘s ByteBuf(读写两个索引,自动扩容);
除了NIO范畴,也做了一些其他增强:ThreadLoacal -> Netty’s FastThreadLoacal(高并发性能更好);
隔离了变化、屏蔽了细节:隔离了底层JDK从NIO到AIO以及后续升级,用户无感知。屏蔽了JDK NIO的实现细节。
开发者直接使用NIO的可能性:
Netty大概有18584行代码,已解决问题4347个,为解决问题400个,JKD NIO本身大约有5000个bug,这就意味着自己直接使用NIO开发一套成熟稳定的网络模块,付出的工作量大概也是这个级别。
Netty已经维护十五年,其沉淀积累极其宝贵。
五、为何孤注一掷:独选Netty
为何不选Apache Mina:Netty是Mina的重构版,提高了扩展性且解决了已知问题。
为何不选Sun的Grizzly:用户少、文档少、更新少。
为何不选Apple的SwiftNIO、ACE等:仅支持Apple系语言。
为何不选Cindy:生命周期太短。
为何不选Tomcat、Jetty、Undertow:它们有自己的网络通信层实现,但是并未独立出模块,其功能也主要针对Servlet容器,不具备通用开发框架的要素。
结论:Java网络编程,只选Netty。
六、Netty的前程往事
归属组织:
JBoss:4.0之前
Netty:4.0之后
版本演进:
2004-6:Netty2发布,号称Java社区第一个基于事件驱动的网络框架。
2008-10:Netty3发布。
2013-7:Netty4发布。
2013-12:Netty5Alphal。
2015-11:废弃Netty5。复杂度太高、没有显著的性能优势、版本太多维护不过来。不要在项目中用任何非稳定依赖。
与Apache Mina的关系?
同一作者开发,都还在维护:
2004年6月Netty2发布,后火。
2005年5月Mina发布,先火。
Mina受Apache管理,Netty受作者自己管理,作者的才能发挥更充分,所以作者推荐Netty。
七、Netty的现状与趋势
社区现状:
github指标反应很火很活跃。
22个贡献者,两个核心成员(Trustin Lee和Norman Maurer)。
分支:
4.1master,活跃。
4.0维护状态。
典型用例:
全文检索:ES;
开发框架:gRPC、Dubbo、Spring5;
分布式协调:Zookeeper;
工具:async-http-client;
特性持续更新:
流行协议:dns、haproxy、http、http2、memcache、maqq、redis、smtp、socks、stomp、xml;
紧跟JDK新功能的步伐;
易于使用、人性化:IP地址黑白名单、流量整形;
八、Netty怎么切换三种IO模式
三种IO模式:
BIO(jdk1.4之前):类似食堂排队打饭,在窗口等待,打好才走。
NIO(jdk1.4之后,2002年):类似餐厅点菜-被叫,等待被叫,好了自己取餐。
AIO(jdk1.7,2011年):类似包厢,点菜后在包厢干其他事,服务员送餐。
阻塞与非阻塞:
菜没做好,是否死等 -> 数据没就绪,要不要等待?
阻塞:数据未就绪,线程一直等待,直到数据来;缓冲区满时,写线程也会等待,直到缓冲区有空位;
非阻塞:线程遇到数未就绪或缓冲区满,直接返回。
同步与异步:
菜做好了,谁来端 -> 数据就绪了谁来完成对数据的操作。
同步:数据就绪后,客户端线程自己去读取。
异步:数据就绪后,服务端线程读取好,再回调客户端线程。
Netty对BIO的支持被声明为已废弃?
——因为,在连接数高的情况下:阻塞会导致大量线程等待 -> 资源占用严重、响应效率降低。
Netty为何删除了已实现对AIO的支持?
——Windows对AIO有成熟的实现,但很少作为服务器使用。
Linux服务器份额大,但是其AIO实现不成熟,且目前Linux的AIO与NIO相比,性能提升不明显。
为什么Netty在NIO的支持上分成了Common、Linux、macOS/BSD三种实现?Common实现的NIO在Linux上使用的也是epoll,为何还要单独实现一套Linux的epoll?
Netty实现了更好的epoll机制:
Netty暴露了更多的可控参数:JDK NIO默认水平触发,Netty则默认边缘触发更高效,也可水平触发。
Netty的实现GC更少,性能更佳。
BIO实现更简单,能保证连接数少的场景下性能也和高,但NIO能让系统更具扩展性。
九、Netty如何切换IO模式
EventLoopGroup:内部是一个无限循环,达到实时而永久监听时间的目的。
服务端:修改boss、worker之EventLoopGroup,serverSocketChannel的类型;但socketChannel不需要切换,原因是socketChannel对象由serverSocketChannel创建,其类型由serverSocketChannel决定。
切换原理:泛型 + 反射 + 对象工厂。
十、Netty如何支持三种Reactor?
饭店演变:
迎宾(接入)、点菜(请求)、做菜(业务处理)、上菜(响应)、送客(断开)
一个人(服务端线程)包揽所有 --> 单线程Reactor。
招几个伙计:所有人各自迎宾、点菜、做菜、上菜、送客 --> 多线程Reactor。
招几个伙计:精细分工 --> 主-从多线程Reactor。
三种默认是:
BIO:Thread-Per-Connection
NIO:Reactor
AIO:Proactor
Reactor处理流程:注册感兴趣的事件 -> 监听扫描是否有感兴趣的时间发生 -> 处理时间
不分工的线程池能免去线程初始化的消耗、能防止线程被耗尽,但不能解决阻塞等待问题。
Reactor三种模式:
处理流程:accept -> read -> decode -> compute -> encode -> send,其中read、send必然阻塞
单线程Reactor:单线程处理全流程;Netty中只初始化一个EventLoopGroup且将线程池容量设为1。
多线程Reactor:Reactor负责accept、read、send,其余流程交给线程池处理;Netty中只初始化一个EventLoopGroup线程池容量默认根据核数计算,或容量设为N。(N > 1)
主-从多线程Reactor:MainReactor专门负责accept,SubReactor负责read、send,其余流程交给线程池;Netty中只初始化两个EventLoopGroup,都不设容量,线程池容量都自动计算。
十一、解析Netty对Reactor模式支持的常见疑问
如何支持主-从Reactor模式的:
十二、Netty对TCP/IP的沾包和半包处理
什么是沾包和半包问题?
沾包:发送方一次写入数据 < 套接字缓冲区大小,或接收方读取套接字缓冲区不够及时。
半包:发送方一次写入数据 > 套接字缓冲区大小,或发送的数据大于协议的MTU,被迫拆包。
为什么会出现沾包和半包问题?
解决沾包和半包问题的几种常用方法?
Netty对三种常用封帧方式的支持?
源码解析Netty对沾包和半包问题的处理?
原文:https://www.cnblogs.com/JaxYoun/p/12896457.html