I/O是冯·诺依曼结构结构重要单元(运算器、控制器、存储器、输入设备、输出设备),也是一个使用频率最高的计算机资源,我们编程其实就是处理各种I/O的过程。
什么是I/O
I/O输入/输出(Input/Output),分为IO设备和IO接口两个部分。 在POSIX兼容的系统上,例如Linux系统 [1] ,I/O操作可以有多种方式,比如DIO(Direct I/O),AIO(Asynchronous I/O,异步I/O),Memory-Mapped I/O(内存映射I/O)等,不同的I/O方式有不同的实现方式和性能,在不同的应用中可以按情况选择不同的I/O方式。【百度百科】
I/O模型分类理论
提到IO分类,大家肯定会想到 同步阻塞 I/O、同步非阻塞 I/O、异步阻塞 I/O、异步非阻塞 I/O、多路复用I/O、BIO、NIO、AIO 这些IO模型有什么区别,为什么会有这些IO模型?下面列举不同IO类型及IO面向对象。
| 面向对象 |
支持IO类型 |
||||||
| Linux操作系统 |
同步阻塞 I/O、同步非阻塞 I/O、异步阻塞 I/O(多路复用I/O )、异步非阻塞 I/O |
||||||
| Linux系统内核 |
直接IO、缓存IO(标准IO) |
||||||
| 磁盘存储 |
线性结构、链式结构 |
||||||
| java程序 |
BIO、NIO、AIO |
||||||
-
I/O模型-系统内核
直接IO概念:
程序访问数据不经过内核缓存区,直接访问磁盘、网卡等其他设备的IO过程。
缓存IO概念:
程序访问数据,先将数据copy到系统内核,然后从系统内核copy到用户空间。
两种区别:
程序访问数据,数据是否进过系统内核,操作系统为了系统安全和缓存的需要,用户读取数据需要先读取到系统内核,然后从系统内核copy到用户空间,这种模式隔离用户空间和系统空间提高系统的安全,数据缓存到系统内核,不必每次读取数据都从磁盘读取提高程序的性能,但是在不需要反复数据读取处理的场景(比如kafka),缓存I/O会多一层读取内核操作,浪费cpu和内存资源。关于直接I/O Linux使用很多技术待I/O模型技术实现分解。
-
I/O模型-磁盘存储
线性结构概念:
程序存储数据时,申请一块连续的磁盘空间,然后将数据顺序写入磁盘,此种模式硬盘无需寻址,写入性能接近内存写入速度。
链式结构概念:
程序存储数据时候,申请一块非连续的磁盘空间,写入磁盘时候程序需要寻址速度慢。
两种区别:程序存储时候申请硬盘是连续磁盘空间,还是逻辑连续的磁盘空间,连续的磁盘空间程序写入性能好,但是硬盘空间利用率差,逻辑连续的硬盘资源反之。
-
I/O模型-操作系统
同步、异步个人理解:
同步 指进程触发IO操作后会阻塞用户进程,用户等待请求数据到达的过程。
异步 指进程触发IO操作后不会阻塞用户进程
两者区别 进程触发IO操作是否会阻塞用户进程,用户的cup此时是否释放,所以同步异步针对的是用户进程。
阻塞、非阻塞个人理解:
阻塞 指用户进程触发IO操作后,触发read()等待内核将数据copy到用户空间的过程(select 也是一种阻塞IO)。
非阻塞 指用户进程触发IO操作后,触发read(),系统内核会立刻返回成功,当read响应完成,系统内核会产生一个信号或者基于一个线程回调函数完成IO过程。
两者区别 触发read()操作后,系统内核是否会立刻返回状态还是等待, 所以阻塞非阻塞是针对操作系统内核。
同步阻塞I/O:
用户发起IO操作后,用户进程阻塞等待内核响应,此时系统内核发生上下文切换,等待内核将数据copy到用户空间,这个过程看似紧密有序,但是有用户线程和内核线程等待,所以同步阻塞I/O是一种低效I/O。
框架支持 java(BIO)、netty、mina
图 1. 同步阻塞 I/O 模型流程
同步非阻塞I/O:
用户发起IO操作后,用户进程阻塞等待内核响应,此时系统内核立刻返回成功,当read()响应完成,系统内核会产生一个信号或者基于一个线程回调函数完成IO过程。
框架支持 目前没有见过支持同步非阻塞I/O模型产品
Linux同步非阻塞I/O模型:当用户发起IO请求,用户进程阻塞,此时read()响应错误代码,内核响应未就绪,程序需要多次请求确认内核就绪,严格意义上讲此时内核是阻塞的,在等待内核响应有一定的时间间隔,所以同步非阻塞I/O也是一种低效I/O。
图 2. Linux 同步阻塞 I/O 模型流程
异步阻塞I/O:当用户发起IO请求,此时用户进程不被阻塞,此时内核配置的I/O是非阻塞的I/O,操作系统会阻塞select来监视内核是否就绪,如果内核就绪就通知应用处理。此I/O模型也叫多路复用I/O模型,只是缓解内核阻塞,但是高性能的I/O操作仍然会有性能问题。
框架支持: java(NIO)、netty、mina
总结:此I/O模型是Linux最成熟稳定的I/O模型,Linux做大量的技术优化(比如:select、poll、epoll),许多高性能框架都是基于此I/O模型,比如 netty,mina等。
图 3. Linux 异步阻塞 I/O 模型流程
异步非阻塞I/O:当用户发起IO请求,此时用户进程不被阻塞,此时内核配置的I/O是非阻塞的I/O,当内核就绪后回调通知用户线程完成I/O处理流程。
框架支持:java(AIO)、netty(AIO)
图 4. Linux 异步非阻塞 I/O 模型流程
I/O模型与硬件
I/O读写流程:
I/O读流程:用户空间读请求-->Linux内核空间-->在pageCache查询缓存-->未查询到os内核在内存映射的目标数据(缺页)-->获取逻辑地址(获取page对应块地址)-->块地址获取磁盘物理地址-->通过SASI指令操作硬盘读取物理地址内容-->数据返回到系统内核(此过程通过DMA技术直接copy到内存,不需要cup参与)-->数据通过内核返回到用户空间
I/O写流程:用户空间写请求-->将文件写入pageCache-->获取逻辑地址(获取page对应块地址)-->块地址获取磁盘物理地址-->通过SASI指令操作硬盘读取物理地址内容-->pageCache在合适的时机将脏页刷新到磁盘
图 5. Linux 一次写入I/O宏观流程图(包含硬件部分)
I/O读写流程总结: 系统在读写的时候参与方可能有 cup、内存、硬盘、网卡、显卡等等外接设备,分析过程发现三个特点。
- 这个读写过程都有经过操作系统内核
- 读写过程都经过用户空间
- 通过DMA技术对第三方外设进一步抽象,让CPU无需关注外设copy数据到系统内核过程。
I/O模型与Linux
待完善
图 6. Linux 协议流程图
I/O模型代码实战
待完善各种I/O模型java代码实现
I/O模型性能对比总结
待完善各种I/O模型java代码实现,然后列表对其起性能
名词解释:
硬件名词解释:
DMA技术:它允许某些电脑内部的硬件子系统(外设),可以独立地直接读写系统内存,而不需中央处理器介入处理,同等情况下降低cup负担。
PIC总线:cpu访问其他pic设备的通道。
SAS控制器:一种新型的磁盘链接技术。
MCU微控单元:一种微型计算机简称单片机。
MMU内存管理单元:分页内存管理单元,功能包括虚拟地址到物理地址的转换(即虚拟内存管理)、内存保护、中央处理器高速缓存的控制。
LBA逻辑地址块:存储设备物理地址与逻辑地址映射关系
Linux名词解释:
Linux内核存储单元:
脏页:被修改过的页
扇区:磁盘存储的最小单位
磁盘块:文件系统读写数据的最小单位
页:内存存储的最小单位,他是位于内存和文件系统之间的缓存区域,操作系统通过地址映射将文件系统映射为页的级别。
pageCache:页高速缓冲存储器,简称页高缓。page cache的大小为一页,通常为4K。在linux读写文件时,它用于缓存文件的逻辑内容,从而加快对磁盘上映像和数据的访问。
机型硬盘容量:硬盘容量大小=磁头数×柱面数×扇区数×每扇区字节数
参考文档:
5.1: Linux文件系统简介
5.2: Linux IO协议栈框图
- Linux地址空间(一、二、三)
- Linux内核漫游记(一)
- IBM Linux I/O类型简介
- DMA技术简介
网卡:三
硬盘:四