IT笔记与心得

操作系统io小结

2021-03-01  本文已影响0人  会跳的八爪鱼

io分为内存io,磁盘io与网络io,一般认为是后两种

1. io设备

io设备

  • 块设备:块设备是以块为单位读写的设备,像磁盘等
  • 字符设备:以字符为单位读写的设备,像键盘,鼠标,打印机等

设备控制器:每个设备都有设备控制器。设备控制器中含有数据和状态寄存器。负责接收cpu的命令,通过控制线发送中断,接收cpu命令,并在设备和内存中拷贝数据
设备驱动程序:接收上层软件(例如下图的io命令调用所经历的过程)发来的抽象I/O要求,如read、write等命令。再把它转化为具体设备要求,发送给设备控制器,启动设备去执行。工作包括检查用户I/O请求的合法性,了解I/O设备的工作状态,传递与I/O设备操作有关的参数,设置设备的工作。
中断处理程序:驱动程序接收到设备中断信号后,会去中断向量表查询对应的中断处理程序并执行。属于驱动程序的一部分

2. 直接io与缓存io

操作系统为了减少io次数,提高缓存利用率,保护内核空间,在内核空间中设计了页缓存

write操作时也会先将数据写入到页缓存中,减少了io。
页缓存中的数据怎么写回到磁盘:1.定期同步到磁盘2.调用sync系统命令3.页缓存空间不够。

3.IO控制方式io控制方式详解

首先说一下cpu读取io设备的经历的过程。


io命令调用所需要经历的过程
  • User是用户应用程序;
  • GLIBC是c的库函数,作为应用程序的运行时库;
  • SCI(system-call interface)是系统调用接口,例如read,write,这层抽象允许用户程序的I/O操作转换为内核的接口调用;
  • VFS提供了一个抽象层,将API接口与不同存储设备的具体接口实现进行了分离,使得底层的文件系统类型、设备类型对上层应用程序透明;设备无关层还会保留逻辑设备对应物理设备的映射表,例如 /dev/hd[a-t]:IDE设备,dev/sd[a-z]:SCSI设备
  • 具体设备的硬件操作系统,例如硬盘操作系统ext3等;
  • 设备驱动程序,也属于内核,操纵硬件设备进行io工作;
  • 具体设备;每个设备都有对应的设备控制器设备控制器中含有数据和状态寄存器。负责接收cpu的命令,通过控制线发送中断,并在设备和内存中拷贝数据I/O软件的层次结构

读取数据的过程:
--->用户调用c或者java库函数读取文件
--->接着库函数会转换为sci层的系统调用指令read
--->设备无关性系统(例如vfs)根据逻辑设备选择对应的设备文件系统,然后接着调用对应的设备驱动程序
---->设备驱动程序发送指令到设备控制器,设备控制器完成数据读取后
程序控制方式
早期的计算机没有中断机制,所以cpu发送读取指令,要同时把状态寄存器中的忙/闲标志busy置为1,然后便不断地循环测试busy。
当busy=1时,表示输入机尚未输完一个字(符),处理机应继续对该标志进行测试。
直至busy=0,表明输入机已将输入数据送入控制器的数据寄存器中。于是处理机将数据寄存器中的数据取出,送入内存指定单元中,这样便完成了一个字/符的I/O。
中断控制方式
CPU向设备控制器发送I/O命令后,立即返回继续执行原来的任务。设备控制器于是按照该命令的要求去控制相应的输入设备读数据。
一旦数据进入数据寄存器(在设备控制器中),设备控制器便通过控制线向CPU发送一中断信号,由CPU检查输入过程是否出错。
若无错,便向控制器发送取走数据的信号,然后cpu再通过数据线将数据写入内存指定单元中。在I/O设备输入每个数据的过程中,由于无需CPU干预,因而可使CPU与I/O设备并行工作。仅当输完一个数据时,才需CPU花费极短的时间去处理
DMA控制方式
由于中断方式每传送一个字符或一个字,都要发生一次中断。而且每次中断都需要CPU去处理,因此设计了DMA控制器(DMA采用窃取或挪用总线控制权,在设备和主存之间开辟直接数据交换通道,成批地交换数据,而不必让 CPU 干预)
DMA控制器由三部分组成:主机与DMA控制器的接口;DMA控制器与块设备的接口;I/O控制逻辑。DMA中包含四种寄存器:
1)命令/状态寄存器(CR,command register)。用于接收从CPU发来的I/O命令,或有关控制信息,或设备的状态。

2)内存地址寄存器(MAR,memory address register)。在输入时,它存放把数据从设备传送到内存的起始目标地址;在输出时,它存放由内存
到设备的内存源地址。
3)数据寄存器(DR,data register).用于暂存从设备到内存,或从内存到设备的数据。
4)数据计数器(DC,data counter).存放本次CPU要读或写的字(节)数。

DMA读取数据流程
-->cpu发送读取指令给DMA,并将存放数据内存地址和计数器发送到MAR和DC中,然后就可以执行其他工作了。
-->DMA控制器从磁盘中读入一个字节的数据并送入数据寄存器(DR)后,接着将该字节传送到MAR所指示的内存单元中,接着对MAR的内容加1,DC内容减1。若减1后DC的内容不为0,表示传送未完,接着传送。
-->当DMA完成任务后,发送中断指令告诉cpu。cpu再将数据传送到应用程序(注意这里是将数据拷贝到内核空间中)。

4. socket

在讲解io模型时,首先需要了解io传输的大致过程:

socket是两个主机之间进行数据交互的接口,是对tcp/ip层的抽象,它通过五元组(协议, 客户端IP, 客户端Port, 服务器端IP, 服务器端Port)来确定。它在内核缓冲区中。根据上面io设备的传输流程可知。
①数据到达网卡后,采用DMA方式将数据传入到指定的socket缓存区(缓冲区是一个网络连接的假设,在linux中以文件的方式存在,如下图网络io数据传输流程)。
②数据socket缓存区到达用户空间中。在网络io模型中,内核准备好其实就是socket缓存区有数据。

发送数据到网络的流程
socket
发送数据到网络的流程如上图,skb是内核中的socket缓冲区(在linux中也是进程打开文件表中的一项,例如下下图中的fd)。
需要说明的是网卡接收到数据后通过硬件中断发送信号,cpu调用中断处理程序将数据写入到ring buffer(缓冲队列中),接着发送软中断信号,结束运行。cpu接收到软中断信号后会将数据从ring buffer拷贝到skb中。
中断需要快速执行,不能浪费cpu太多的时间。所以将中断分为上下两部分,上部分是硬中断,下部分是软中断。硬中断立刻执行立刻结束,然后发送软中断任务到队列中,然后cpu执行软中断队列中的软中断任务。

网络io数据传输过程
  • socket分为两种状态,主动socket和被动socket(通过调用listener方法),客户端创建的socket是主动socket,服务器端为了实现监听某个端口创建的是被动socket(也叫监听socket)。当有多个客户端连接到socket上时,socket会根据连接的ip+端口和本机ip+端口创建新的数据socket用于传输数据。类似于ftp的控制连接和数据连接。每个数据socket对应一个连接。
  • 为什么每个连接都新建数据socket,因为如果只用监听socket,当一个客户端传输数据时,其他的客户端不能再传输,因为监听同一个端口只是同一个socket。
  • 其他:socket中还有发送缓冲区和接收缓冲区,发送缓冲区会在适当的时候发送到网络,因为涉及了滑动窗口协议和流量控制。
4. io模型

note:本文中的io模型是针对linux下的网络io模型,因为阻塞非阻塞,同步异步不同场景的说法可能不同

上面说了网络io操作通常分为两个阶段,对于应用进程来说将网卡数据拷贝到内核不用考虑,只需要下面两步:1.内核中数据准备完毕(等待有数据到来)2.将数据和内核拷贝到用户空间


阻塞io
  • reactor模型就使用了io多路复用思想。优点:适合多并发连接。而select,poll,epoll(看下文)就是Reactor模型在进行线程轮询时使用的方法。
  • note:socket监听是否有客户端连接并不是多路复用的范围。轮询数据就绪才是。

BIO/NIO/AIO适用场景

  • BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
  • NIO(多路复用)方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
  • AIO方式适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
5. select,epoll

前言:如果服务端有大量的连接,那么就会生成大量的socket,但是如果只有一部分socket活跃,这时如果使用阻塞io/非阻塞io需要构造大量线程读取socket,会造成巨大的浪费。所以可以使用io多路复用技术。使用单独的线程轮询这些socket。

Reactor模型

Reactor模型是对io多路复用的一种体现。他有三种模型,单Ractor单线程模型,单Reactor多线程模型,多Reactor多线程模型。这种模型主要分为以下几个部分 Reactor线程模型 (zhihu.com)

  • Reactor 当任务就绪时负责任务分发
  • Acceptor 负责连接到建立
  • Handler 负责网络读写与任务运行
    多Reactor多线程模型
    上面这张图就是第三种模型,mainReactor负责监听连接建立,subReactor负责接收acceptor注册的读写事件,然后subReactor通过revcfrom函数轮询client建立连接时生成socket缓冲区(这个时候就需要使用select,poll,epoll模型从而知道是哪些socket缓冲区已经有数据了),subReactor得到就绪事件之后,就会将任务发送到线程池任务队列中,等待线程池中的空闲线程完成就绪事件读取并运行任务。(注意:这个过程是同步也是同步阻塞模型。当然也可以让监听线程先返回数据,业务线程异步执行达到异步的效果,servlet3就是使用的这种同步非阻塞模型
io多路复用模型的应用

javaNIO就是对多路复用的一种使用,而tomcat从8.5之后也支持了NIO的方式,就是通过使用java的NIO技术来完成的。它一共包含LimitLatch、Acceptor、Poller、SocketProcessor、Excutor5个部分。


tomcat模型
  • LimitLatch是连接控制器,它负责维护连接数的计算,nio模式下默认是10000,达到这个阈值后,就会拒绝连接请求。
  • Acceptor负责接收连接,默认是1个线程来执行,将请求的事件注册到事件列表。
  • Poller来负责轮询,Poller线程数量是cpu的核数Math.min(2,Runtime.getRuntime().availableProcessors())。由Poller将就绪的事件生成SocketProcessor同时交给Excutor去执行。
  • Excutor线程池的大小就是我们在Connector节点配置的maxThreads的值。在Excutor的线程中,会完成从socket中读取http request,解析成HttpServletRequest对象,分派到相应的servlet并完成逻辑,然后将response通过socket发回client。

这种结构就是Reactor模型中多Reactor多线程模型。而servlet3实在NIO的基础上完成了完成了异步处理逻辑。(即先返回数据,然后在打入到队列中等待handler异步执行。)
nginx,redis也是使用io复用技术。

参考:文件系统及io模型
io模型
监听socket和连接socket
socket缓冲区
keep-alive
select,epoll详解
epoll模型
redis io多路复用
IO控制方式

上一篇下一篇

猜你喜欢

热点阅读