• IO的演进


    一、I/O是什么?

    Linux里对数据流的操作叫I/O操作(Input and Output)。而Linux世界里一切都抽象成文件,文件实际就是一串二进制流。不管是管道、Socket、标准输入、标准输出等,在Linux看来都是文件,都是流,流的对象通过文件描述符标识,对文件描述符的读写操作,就等于对流的读写操作,就是我们说的I/O操作。随着互联网的发展,对I/O的要求越来越高,每个时期都有新的技术对I/O进行优化,这就是今天我们要聊的I/O的演进,看看以前的工程师是如何思考并处理问题,以后的I/O之路又会走向何方。

    总的说I/O分为:磁盘I/O,网络I/O,内存I/O三种。因为内存很快,不会有问题,所以通常说的I/O指的是前两者。

    二、著名的“C10K问题”

    以前服务器并发的吞吐量很低,只能处理几十、几百并发。在2000年左右,互联网发展迅速,各类应用层出不穷,即时通信、实时互动等对网络通信需求越来越高,迫使技术更新,由此提出C10K问题,即单服务器处理1万个并发连接问题。在解决C10K问题的道路上,Linux内核I/O操作出现5次更新,对应5种I/O通信模型。

    三、Linux内核的5种I/O通信模型

    在此之前需要先了解阻塞、非阻塞,异步、同步的概念。在大部份场景下,同步意味着阻塞,异步意味着非阻塞,所以很多人搞混了。实际情况它们是有区别的,同步、异步关注的是消息通信机制,阻塞、非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。两两组合,实际上有同步阻塞、同步非阻塞、异步阻塞、异步非阻塞四种情况。

    I/O的操作抽像的说分两步:等待数据,拷贝数据。主要问题是出在等待数据,要提高I/O的效率,就需要尽可能降低等待的时间。接下来我们看看每种模型是如何降低等待时间的。

    1.阻塞I/O模型

    在这里插入图片描述

    比喻一个人在钓鱼,当没鱼上钩时,就坐在岸边一直等
    特点在I/O执行的两个阶段(等待数据和拷贝数据)都被阻塞
    典型应用阻塞Socket,JavaBIO
    优点1.进程阻塞挂起不消耗CPU资源,及时响应每个操作
    2.实现难度低,开发应用容易
    3.适合并发量小的网络应用开发
    缺点1.不适合并发量大的应用,因为每个请求I/O会阻塞进程
    2.需要为每个请求分配一个处理进程以及时响应(或线程),系统开销大
    2.非阻塞I/O模型

    在这里插入图片描述

    比喻边钓鱼边玩手机,隔会再看看有没有鱼上钩,有的话就迅速拉杆
    特点用户进程需要不断地主动询问内核,数据准备好了没有
    典型应用Socket设置为NON_BLOCK
    优点实现难度低,开发应用相对阻塞I/O模型较难
    缺点1.进程轮询(重复)调用,消耗CPU的资源
    2.适合并发量较小且不需要及时响应的网络应用开发
    3.多路复用I/O模型

    在这里插入图片描述

    比喻放了一堆鱼竿,在岸边一直守着这堆鱼竿,没鱼上钩就玩手机
    特点对于每一个Socket,一般都要设置成非阻塞,但是整个用户的进程其实是一直被阻塞的,只不过进程是被select函数阻塞,而不是被Socket I/O阻塞
    典型应用Java NIO,Nginx(epoll,poll,select)
    优点1.专一进程解决多个进程I/O的阻塞问题,性能好,Reactor模式
    2.适合高并发服务应用开发,一个进程(或线程)响应多个请求
    缺点实现和开发应用难度较大

    I/O多路复用中的 “多路” 是指同时监听多个打开的文件描述符,“复用” 是指复用一个进程(或线程)去监听这些打开的文件描述符。

    最早期是select,存在监听的文件描述符有数量限制,内核态到用户态的描述符拷贝等问题,后面poll是对select优化,突破了描述符有数量的限制,但它还是存在内核到态用户态的拷贝等问题。后面出现的epoll的实现机制与select/poll机制完全不同,所以他们的缺点在epoll上不复存在。

    特点selectpollepoll
    监听描述符个数有上限无上限无上限
    描述符从内核态到用户态的拷贝及从用户态到内核态的拷贝需要需要不需要
    调用后轮询检测事件是否发生需要需要不需要
    调用前是否需要重置监听的描述符状态(函数参数)需要需要不需要
    4.信号驱动I/O模型

    在这里插入图片描述

    比喻鱼竿上系了个铃铛,当铃铛响,就知道鱼上钩,然后可以专心玩手机
    特点并不符合异步I/O要求,只能算是伪异步,并且实际中并不常用
    典型应用应用场景较少
    优点应用较少,不做详细总结
    缺点实现和开发应用难度大
    5.异步I/O模型

    在这里插入图片描述

    比喻有个机器人帮你钓鱼,钓到鱼就告诉你,你只要在旁边专心玩手机
    特点真正实现了异步I/O,是五种I/O模型中唯一的异步模型
    典型应用Java7 AIO,高性能服务器应用
    优点1.不阻塞,数据一步到位,采用Proactor模式
    2.非常适合高性能、高并发应用
    缺点1.需要操作系统底层支持,Linux2.5内核首现,Linux2.6产品的内核标准特性
    2.实现和开发应用难度大
    6.各I/O模型总结

    在这里插入图片描述
    从上图可以看出,阻塞程度:阻塞I/O>非阻塞I/O>多路复用I/O>信号驱动I/O>异步I/O,越往后,阻塞越少,效率是由低到高的。

    四、java的BIO,NIO,AIO

    在操作系统提供5种I/O模型的前提下,java的网络编程也对应用实现了BIO、NIO、AIO,它们的出现的顺序跟操作系统的IO模型演进是一致的,因为就是依赖操作系统实现的。

    1.BIO

    同步阻塞式IO,简单理解:一个线程处理一个连接,发起和处理IO请求都是同步的。对应系统的I/O模型为:阻塞I/O模型

    2.NIO

    同步非阻塞IO,简单理解:一个线程处理多个连接,发起IO请求是非阻塞的但处理IO请求是同步的。对应用系统的I/O模型为:多路复用I/O模型

    3.AIO

    异步非阻塞IO,简单理解:一个有效请求一个线程,发起和处理IO请求都是异步的。对应用系统的I/O模型为:异步I/O模型

    五、I/O对应的设计模式

    设计模式代表了最佳的实践,在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作。

    1.Reactor模式
    2.Proactor模式

    六、未来IO的可能方向

    在现有Linux架构下收发报文必须采用硬中断来做通讯,每次硬中断大约消耗100微秒;数据在内核态用户态之间拷贝带来大量CPU消耗;多次系统调用的开销;到网卡经过的路径太长。随着并发要求不段提高,可以看到系统内核一直在改为,在原来的分层与封装的设计思想之上,又增加了直接访问内核的手段。I/O优化的未来,可能是去内核态的方式。跳过内核直接驱动网卡,自己实现数据的拆包与封包,充分理用硬件资源,从通用型服务器变成专用型服务器。现在DPDK(www.dpdk.org)已经基本实现这一想法。

    参考:《Netty 4核心原理与手写RPC框架实战》谭勇德 著

  • 相关阅读:
    Initialize the kubernetes basic environment configuration on CentOS 8.2
    C# 开发的程序怎么默认以管理员身份运行
    YOLOv8+swin_transfomerv2
    基于PyQt5GUI的人脸识别系统设计与实现
    pyinstaller打包python脚本为exe可执行文件实例:错误排查小脚本
    Hudi第二章:集成Spark(二)
    大数据分析案例-基于RFM模型对电商客户价值分析(聚类)
    品牌进行女性营销时应该如何避免翻车?媒介盒子分享
    Ceph提供nfs服务
    权值初始化的常用方法
  • 原文地址:https://blog.csdn.net/caidongxuan/article/details/126949339