什么是经典的三种I/O模式

我们在学Netty的时候讲的最多的就是Reactor的三种模式,因为他的这个模式用的最广泛,涉及的I/O知识点很基础也很常用。

  • 我们去吃饭的时候:

1:家乐园排队打饭,排队在窗口,打好才走。

2:点单,拿一个号码牌等待被叫,好了自己去端走。

3:辣可可包厢模式,点单后菜直接端上桌。

  • 类比:

饭店->服务器

饭菜->数据

饭菜好了->数据就绪

端菜、送菜->读取数据

模式 特点 JDK版本
排队打饭模式 BIO(阻塞) JDK1.4之前
点单被叫模式 NIO(非阻塞) JDK1.4
包厢消费模式 AIO(异步) JDK1.7
  • 阻塞与非阻塞区别:

    菜没好,要不要死等 -> 数据就绪之前要不要等待。

    阻塞:没有数据传过来时,读会阻塞直到有数据;缓冲区满时,写操作也会阻塞。非阻塞:遇到这些情况都是直接返回。

  • 同步与异步区别:

    菜好了,谁端 -> 数据就绪后,数据操作谁来完成?

    数据就绪后需要自己去读就是同步,数据就绪后直接读好再回调给程序是异步。

总结

所以BIO是阻塞同步方式;NIO是非阻塞同步方式;AIO是非阻塞异步方式。

疑问

Netty为什么仅仅支持NIO模式呢?为什么不用AIO模式呢?(Netty删掉了AIO的实现)

1:Windows实现AIO很成熟,但Win很少用来做服务器。

2:Linux常用来做服务器,但AIO实现不够成熟。

3:Linux下的AIO相比较NIO的性能提升不够明显。

Reactor线程模型

生活场景 饭店规模变化
1:一个人包揽所有 迎宾、点菜、做饭、上菜、送客等。
2:多招几个伙计 大家一起做上面的事情。
3:进一步分工 选一个或多个人专门做迎宾。

Netty中的Reactor线程模型有三种,分别如下:

  1. Reactor单线程模型;
  2. Reactor多线程模型;
  3. 主从Reactor多线程模型;

–传统单线程模型–

单线程模型简单,一个线程就一路走到底,优点是开发简单;缺点是如果某一个环节慢了,整个线程资源就拖垮了,甚至应用也会处理相当慢。

这个模型中最主要的就是每一步都是阻塞的,也就是BIO模型。有朋友会说改造成多线程不就解决了吗,多线程也只是用更多的线程做同样的事情而已,对应的每一步还是阻塞的。

70

Reactor单线程模型

注:Netty将这些读写、编解码等操作包装成事件,想想NIO的非堵塞的原理和包装成事件有何必然关联性。

有同学会问,这个绿色的圈怎么理解,其实如上所说的,netty把所有的请求操作内部操作都认定为事件,绿色是一个客户端连接事件,这个连接事件也是这三种模型的关键优化点。

70-20210907141509987

上面的单线程Reactor模式因为服务端只有一个线程处理IO和业务逻辑,服务端性能肯定受到限制。虽然用了NIO的非阻塞方式,但一个线程如果挂了,这个应用基本也就挂了。因此就有了多线程版本。

Reactor多线程模型

如下图所示,Reactor还是一个线程,负责监听IO事件以及分发,业务逻辑处理部分使用了一个线程池来进行处理(解码、计算、编码),这样就解决了服务端单线程处理请求而带来的性能瓶颈。就如生活场景中说的第二点,找多个人一起干同样的事。

但是这样还是有问题,这样会把性能的瓶颈转移到IO处理上。因为IO事件的监听和分发采用的还是单个线程,在并发量比较高的情况下,这个也是比较影响性能的。这是否还有继续优化的空间呢?

70-20210907141512872

主从多线程模式

我们知道Reactor主要是负责IO事件的监听和分发。单个Reactor单个线程这种模式在并发量比较高的情况下,会存在性能瓶颈。我们可以想象一下生活场景,开饭店最重要的是什么?我觉得是迎宾,找几个漂亮的小姑娘在门口,把客人先招揽进来,咱们做菜慢一点又有什么关系呢?流量都没进来,你的应用再强大饭菜做的再香也没有任何体现的价值。

再次提到这个绿色的连接事件,第一和第二两种模型为啥会进化成主从模式,你想一想,客户端连接上来都会立即传输数据吗?都会立即发送数据交互请求吗?不一定吧。

用生活场景说:用户到饭店门口了,如果我们都在店里面忙不过来,没有人招呼外面的客人会怎么样?客人就会走吧。连接也一样,如果线程都在里面忙碌或者卡住了,那么客户端连接就会超时。

再结合起来看看,我们第一步就先要保证和客户端连接稳定,而且客户端连接这个操作是不耗啥资源的,很快就完成了,先和客人建立了联系,客人就不会走。大家想想是不是这个道理。

所以对于服务器而言最重要的是什么呢?是“接收连接”这个事情。主从模式更好的模式提高了性能利用率,他把acceptor单独注册到mainReactor里面去做接收连接事件。

70-20210907142437684

最后

我们所以的Netty服务端开发都是用了主从Reactor模式开编写,虽然说他不是最优的,比如我的业务就是只要几个连接就能完成事情,比如一个线程像一个VIP服务一样,也不会占用更多资源;或者这个项目就目前属于维护型项目,就不用什么改动了,就算改了也没有明显的效率提升反而增加了上线测试风险。但是考虑未来更多的可能性,都是建议使用第三种方式。

分析问题要从场景来分析,并非BIO就弱于NIO。

上一篇 下一篇