【Netty开发指南】搭稳Netty开发的地基

Linux网络编程5种IO模型

根据UNIX网络编程对于IO模型的分类,UNIX提供了5种IO模型,分别是阻塞IO非阻塞IOIO复用信号驱动IO异步IO。这几种IO模型在《UNIX网络编程》中有详解,这里作者只简单介绍,帮助大家回忆一下这几种模型。
对于Linux来说,所有的操作都是基于文件的,也就是我们非常熟悉的fd,在缺省的情况下,基于文件的操作都是阻塞的。下面就通过系统调用recvfrom来回顾下这五种模型。模型的图示来源于《Netty权威指南》下面不再说明。

阻塞IO

系统调用recvfrom直到有数据到达并且从内核空间copy到用户空间才返回,这期间recvfrom调用者一直等待,这就是阻塞IO。
在这里插入图片描述

非阻塞IO

应用进程反复调用recvfrom询问操作系统内核数据是否准备好,相对于阻塞来说,你可以理解为非阻塞自主能力变强。从图中可以看出数据没有准备好的时候内核返回EWOULDBLOCK
在这里插入图片描述

IO复用

Linux给我们提供的IO复用相关的函数有selectpollepoll这几个函数的优缺点这里就不做详述了,想要再深入了解的同学可以看下我以前的这篇文章:epoll详解:从底层了解IO复用
在这里插入图片描述

信号驱动IO

应用进程建立一个SIGIO信号处理程序,当内核数据准备好的时候,会产生一个SIGIO信号,处理程序收到这个信号并通知进程调用recvfrom
在这里插入图片描述

异步IO

应用程序执行系统调用,告知内核某个操作,并让内核在整个操作完成后(包括将数据从内核复制到应用缓冲区)通知应用进程。这种模式与信号驱动模式的主要区别在于:信号驱动IO由内核通知我们何时可以开始IO操作。异步驱动IO由内核通知我们IO操作是否完成。
在这里插入图片描述

用漫画帮你分清同步异步阻塞非阻塞

说到同步异步阻塞非阻塞很多人分不清他们之间的区别,每次听到这几个词语的时候就头大。更别说他们的组合同步阻塞同步非阻塞异步阻塞异步非阻塞了。针对这几个大家非常容易混淆的词语,我画了一幅漫画帮助大家理解。欢迎大家来吐槽我的第一个漫画作品《洗衣服的故事》。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
你看到这四个词语的时候肯定以为是说的同一件事,描述的是同一个对象,这种理解是错误的。我们可以把 同步、异步 看做一组,阻塞和非阻塞 看成一组。这两者的主要区别就是:前者是"消息通知机制",后者是“等到消息通知时的状态”。
这样说你可能还是没有理解,结合上面的漫画情景中"消息通知机制"就是洗衣机,“等待消息通知时的状态"就是人。拿"异步非阻塞"举例,洗衣机洗完衣服会发出"滴滴"声通知人已经完成了"洗衣服"这个任务,这就是"消息通知机制”,这个过程中人不必傻等着洗衣机"洗衣服"这个任务的结果,可以干其他的事情“浇花”,听到洗衣机的"滴滴"声之后可以去"晾衣服"。这就是一种"等待消息通知时的状态"。

从BIO到AIO

BIO通信模型

BIO通信模型也叫一请求一应答模型。顾名思义,服务器没接收到一个请求就会生成一个线程来处理这个请求。
在这里插入图片描述
这种模式最大的问题是缺乏弹性伸缩能力。这种模式接收一个请求就开启一个线程取处理。众所周知,线程资源对于JVM虚拟机是极其宝贵的,线程数过度膨胀的时候,系统性能会急剧下降,并发很大的情况下很容易会导致资源耗尽而出现堆栈溢出,进而出现宕机或者僵死、服务器崩溃,无法对外服务。上面图示中Client5就是资源耗尽时服务器无法提供服务的场景,用户看到的将是异常或者超时。

伪异步IO模型

用过线程池的同学都知道线程池的好处是我们可以指定核心线程数最大线程数线程池队列大小并且可以设置拒绝策略。所以这种模式相比于阻塞IO来说线程的创建,服务的范围是可控的。无论多少个客户端并发,都不会导致服务器资源的耗尽和宕机。
在这里插入图片描述

NIO编程

NIO是Non-block I/O(非阻塞IO)的简称。使用IO复用编写的服务器和客户端就是NIO编程的很好的示例。我们设置了读写都是非阻塞之后,当没有可读或者可写的数据的时候,线程不同步等待,会直接返回。想要再深入了解的同学可以看下我以前的这篇文章:epoll详解:从底层了解IO复用

AIO编程

NIO 2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。
异步通道获取获取操作结果方式:
1.使用java.util.concurrent.Future类表示异步操作的结果;
2.在执行异步操作的时候传入一个java.nio.channels
操作完成后胡回调CompletionHandler接口的实现类。
NIO 2.0的异步套接字通道是真正的异步非阻塞I/O,对应于UNIX网络编程中的事件驱动I/O。

为什么选择Netty

不选择Java原生NIO编程的原因

以下内容引用自《Netty权威指南》:

  • NIO类库和API繁杂,使用麻烦,你需要熟练掌握SelectorServerSocketChannelSocketChannelByteBuffer等。
  • 需要其他额外的技能做铺垫,例如熟悉Java多线程编程。这是因为NIO编程涉及Reactor模式,你必须对多线程和网络编程十分熟悉,才能编写出高质量的NIO程序。
  • 可靠性能力补齐,工作量和难度都非常大。例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理问题,NIO编程的特点是功能开发相对容易,可靠性能力补齐的工作量和难度巨大。
  • JDK NIO的BUG,例如臭名昭著的epoll GUG,它会导致Selector空轮询,最终导致CPU 100%。官方声称在1.6版本中修复,但是在1.7版本中该问题依然存在,只不过GUG发生的概率降低了很多。

为什么选择Netty

Netty是业界最流行的NIO框架之一, 它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指的, 它已经得到成百上千的商用项目验证, 例如Hadoop的RPC框架Avro就使用了Netty作为底层通信框架, 其他还有业界主流的RPC框架, 也使用Netty来构建高性能的异步通信能力。
通过对Netty的分析,我们将它的优点总结如下。

  • API使用简单, 开发门槛低;
  • 功能强大,预置了多种编解码功能,支持多种主流协议;
  • 定制能力强, 可以通过ChannelHandler对通信框架进行灵活地扩展;
  • 性能高, 通过与其他业界主流的NIO框架对比,Netty的综合性能最优;
  • 成熟、稳定,Netty修复了已经发现的所有JDK NIO BUG, 业务开发人员不需要再为NIO的BUG而烦恼;
  • 社区活跃, 版本迭代周期短, 发现的BUG可以被及时修复,同时, 更多的新功能会加入;
  • 经历了大规模的商业应用考验, 质量得到验证。Netty在互联网、大数据、网络游戏、企业应用、电信软件等众多行业已经得到了成功商用,证明它已经完全能够满足不同行业的商业应用了。
    正是因为这些优点,Netty 逐渐成为了 Java NIO 编程的首选框架。

小结

通过以上内容帮助大家回忆一下Linux网络编程中的IO模型,搞清楚同步异步阻塞非阻塞的概念,了解了BIO到NIO的区别和联系。最后我们知道了众多的NIO框架中,为什么要选择Netty。这些知识也是我们后续进行网络编程和Netty开发的基础。

有收获的小伙伴 我一个 素质三连 吧!

猜你喜欢

转载自blog.csdn.net/lyztyycode/article/details/111564007