1.题外话
一点题外话,最近开始写博客,零零散散写了几篇不成体系的文章。觉得这种方式还是不太好,因而打算开始对某一个点详细的写一写。一方面也是系统的回顾知识,另一方面或许能有新的收获。
2.概述
官方对Netty的定义是:“Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端”。
Netty本身是基于Java的NIO进行编写的,直接使用NIO的API晦涩难懂,需要自己处理如诸如缓冲区读写复位,半包读写,粘包之类的等等问题,开发难度较大。而Netty把这些麻烦的事情都给我们提供了良好的解决方案,我们更多的只需要专注于业务逻辑即可。
- 那为啥非要用NIO,就用过去简单易懂的BIO不香吗?
有一组数据可能说明了一切。在一百并发,每个并发发送一百个消息,测试平均延时及错误率上,BIO达到了160ms,错误率为4%左右。而NIO和基于NIO的Netty框架错误率为0,平均延时分别为57ms和15ms。可以看出无论是耗时还是可靠性都是有着明显的差异的。这也难怪大多数Java语言开发的大数据框架底层都在用Netty。
3.Linux网络模型
要理解Netty,首先得知道Lunix的5种网络模型。
为了方便理解,我们把系统比作一座图书馆(必定Linux万物皆文件),把调用资源的应用程序比作借书的人,把处理这些任务的线程比作图书馆工作人员。
- 阻塞I/O模型
这是一种最为常见的I/O模型。
借阅人享受着VIP待遇,有一个专门的工作人员为他服务。“把《银瓶梅》给我找出来”,一个工作人员走进这个庞大的图书管大厦,将需求报告给图书管理员,然后去了等待区抽烟,“希望这书标题被啃掉了,免得那么快找到搞得我烟都没抽完”。就这样,时间过去了半天,管理员总算拿回了那本缺了封面泛黄的书,工作人员拿着书恭敬的交给了借阅人,借阅人于是拿着书高兴的回家了。
没错,每个工作人员只服务于一个请求。这意味着有多少借阅者,就需要多少个工作人员为其服务。当工作人员多的行走都成问题时,VIP服务就成了^·0服务。
当然,不要以为阻塞I/O一无是处,在并发量并不大的情况下,这种I/O模型性能足以支撑需求。完全没必要因为几个用户大动干戈的将每个线程分配特定角色。
借用一张图来说明阻塞I/O模型:
- 非阻塞I/O模型
同样的,借阅人借阅图书。这次工作人员并不会无休止的等待图书管理员将书找到才返回结果,而是会在告知需求后立即询问结果,就好像认为有一些书目早已准备好随时准备调阅。如果结果为没准备好那么会立即给借阅者返回错误,随后这个工作人员就可以接待其他的借阅者了。当然,借阅人知道这个规矩,因而会重复的进行询问,直到书被找到,这时工作人员才拿着书交给借阅者。
在这种模型下,线程并不因为结果未满足而陷入等待,而是可以被释放去做其他的事情,只是定期回来询问结果是否已满足,而每一次轮询的调用可能由不同线程在处理
这里仍然有个问题,进程反复的调用仍然会导致大量无用的工作在执行,会消耗系统资源。
非阻塞I/O模型图如下:
- I/O复用模型
这次有点不一样了,图书馆新增了一个前台,借阅者来了只需告知前台需求,然后就去了休息室休息。等有结果的时候前台会通知你的。这里最大的好处就是多个请求只用一个线程就能完成处理。
前台将需求转交给工作人员处理,处理完的结果会被送到前台,前台通过轮询看哪些客户的请求已经有了结果,然后通知相应的人前来认领。
这里面有两种方式,对应了poll和epoll调用机制,如果是轮询等待区的所有客户看哪些人的请求得到了结果,那么就是poll,如果只是轮询返回的结果,然后通知相应的人,这就是epoll。两种方式优劣十分明显,前者会随着连接数的增多性能线性下降,并且有最大数量限制,而epoll则不存在这些问题,性能提升明显。
Java的NIO就是用的多路复用模型中的epoll机制。
I/O复用模型图如下:
- 信号驱动I/O模型
这个模型和上面一个有点类似,区别在于没有前台了,而是在首次提交需求时为其提供一个凭证(信号),借阅者得到凭证后可以去做自己的事了。当数据准备好(书找到了),那么会通知凭证持有者书找到了(返回对应信号),此时凭证持有者就可以再次发起请求获取相应的数据了。
这个好处也是非常明显的,不再有多路复用的轮询带来的性能消耗,通过信号驱动更为直接的实现了数据交互。当然实现难度也相对更大一些。
信号驱动I/O模型图如下:
- 异步I/O模型
前面几种模型,无论是否阻塞,数据从准备好到拷贝到用户空间这个过程,一定是阻塞的。也就是说无论如果数据总是要我自己取的。
而异步I/O则不同,连数据准备好后拷贝到用户空间这个过程也给自动的做了,最后只是单纯的通知结果已完成而已。就像借阅者提交请求之后就去做别的事了,完全不用考虑再回图书馆取书的事情,而图书馆会将一切处理好,把书送到用户家中。然后通知借阅者书已送到,在家就能看了。
异步I/O模型图如下:
4.结束语
- 以上就是有关Linux网络模型的基本讲解。欢迎各位大佬指正,更希望能和各位大佬共同交流。
- 下一篇我会用原生Java代码分别展示一个BIO和NIO的网络编程案例,敬请期待。
转载:https://blog.csdn.net/Grain_Rain_tx/article/details/106170554
查看评论