高性能IO底层原理

高性能IO底层原理,第1张

文章目录
    • 高性能IO底层原理
        • IO读写的基础原理
        • 内核缓冲区与进程缓冲区
        • 典型的系统调用流程
        • 五种主要的IO模型
          • IO多路复用模型的特点

高性能IO底层原理 IO读写的基础原理

​ 用户程序进行IO的读写,依赖于底层的IO读写。都会用到read&write两大系统调用,不通 *** 作系统中,IO读写系统调用的名称可能不完全相同,功能基本一致。在用户程序中,无论是Socket的IO还是文件IO *** 作都属于上层应用开发。

​ read系统调用:并不是直接从物理设备把数据读取到内存中,是把数据从内核缓冲区复制到进程缓冲区

​ write系统调用:也不是直接把数据写入到物理设备,是把数据从进程缓冲区复制到内核缓冲区

即上层应用无论是调用 *** 作系统的read还是调用 *** 作系统的write,都会涉及到缓冲区。
上层应用的IO *** 作,实际上不是物理设备级别的读写,而是缓存的复制。
read&write两大系统调用,都不负责数据在内核缓冲区和磁盘之间的交换。底层的读写交换是由 *** 作系统内核来完成的。

内核缓冲区与进程缓冲区

​ 缓冲区的目的是为了减少频繁与设备之间的物理交换。设备的直接读写,涉及 *** 作系统的中断。
当发生系统中断时,需要保存之前的进程数据和状态等信息,而结束中断之后,还需要恢复之前的进程数据和状态等信息。为了减少这种底层系统的时间损耗,性能损耗,就出行了内存缓冲区。

​ 有了内存缓冲区后,上层应用使用read系统调用时,仅仅是把数据从内核缓冲区复制到上层应用的缓冲区(进程缓冲区);上层应用使用write系统调用时,只需要把数据从进程缓冲区复制到内核缓冲区。底层 *** 作会对内核缓冲区进行监控,等待缓冲区达到一定数量时,再进行IO设备的中断处理,集中执行物理设备的实际IO *** 作,这种机制提示了系统的性能。以至于什么时候中断(读中断,写中断),由 *** 作系统的内核决定,用户程序不需要关心。

​ 从数量上来说,Linux系统中, *** 作系统内核只有一个内核缓冲区。
每个用户程序(进程),有自己的缓冲区,叫做进程缓冲区。
所以用户程序的IO读写程序,在大多数情况下,没有进行实际的IO *** 作,而是在进程缓冲区和内核缓冲区直接之间进行的数据交换。

典型的系统调用流程

​ 图示 系统调用read&write流程

​ 例如read系统调用的输入流程

  • 等待数据就绪

  • 从内核向进程复制数据。

    如果read是一个socket。那么具体流程为:

    • 等待数据从网络中到达网卡,当等待的分组到达时,数据会被复制到内核中的某个缓冲区。

      (这个 *** 作有 *** 作系统完成,用户程序无感知)

    • 把数据从内核缓冲区复制到应用进程缓冲区

​ 从客户端和服务器端的角度来理解,即一次socket的请求和响应如下

  • 客户端请求: linux通过网卡读取到客户端的请求数据,将数据读取到内核缓冲区
  • 服务器端获取请求数据:通过read系统调用,从linux内核缓冲区读取数据,再送入Java进程缓冲区
  • 服务器端业务处理:Java进程在自己的用户空间处理客户端的请求
  • 服务器端返回数据:Java进程处理完成,构建好响应数据。通过write系统调用。将这些数据从用户缓存区写入内核缓冲区
  • 发送至客户端:linux内核通过网络IO,将内核缓冲区中的数据写入网卡,网卡通过底层的通信协议,会将数据发送给目标客户端。
五种主要的IO模型
  • 同步阻塞IO (Blocking IO)

    ​ 阻塞IO,指需要内核IO *** 作彻底完成后,才返回到用户空间执行用户的 *** 作。

    阻塞指的是用户空间程序的执行状态,传统的IO模型都是同步阻塞IO。

    Java中默认创建的socket都是阻塞的。

  • 同步非阻塞IO (Non-blocking IO)

    ​ 非阻塞IO,指的是用户程序不需要等待内核IO *** 作彻底完成,可以立即返回执行用户 *** 作,即处于非阻塞的状态。

    ​ 非阻塞IO要求socket被设置为NONBLOCK

    ​ 用户程序需要不断的进行IO系统调用,轮询数据是否已经准备好,制度完成IO系统调用为止。

    • 优点:每次发起的IO系统调用,在内核等待数据过程中可以立即返回,用户线程不会阻塞,实时性比较好。
    • 缺点:不断地轮询内核,占用大量的CPU时间,效率低下。

    阻塞和非阻塞

    ​ 阻塞是指用户空间(调用线程)一直等待,非阻塞指用户空间(调用线程)拿到内核返回的状态值就返回自己的空间。

  • IO多路复用(IO Multiplexing)

    ​ 避免同步非阻塞IO模型中轮询等待的问题,可以采用IO多路复用模型。

    ​ 在IO多路复用中,引入了一种新的系统调用,查询IO的就绪状态。在Linux系统中,对应的 *** 作系统调用为select/epoll系统调用。通过该系统调用,一个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓冲区可读/可写),内存能过将就绪的状态返回给应用程序。随后,应用程序根据就绪的状态,进行对应IO系统调用。

    ​ 在IO多路复用模型中通过select/epoll系统调用,单个应用程序的进程,可以不断的轮询成百上千个的socket连接,当某个或者某些socket网络连接有IO就绪的状态,就返回对应的可执行的读写 *** 作。

    例如发起一个多路复用IO的read读 *** 作系统调用

    • 选择器注册

      先将read *** 作的目标socket网络连接,提前注册到select/epoll选择器中(Java中对应Selector类)

    • 就绪状态的轮询

      通过选择器的查询方法,查询所有注册过的socket连接的就绪状态。当其中任何一个socket连接数据准备好了,内核缓冲区有数据(就绪)了,内核就会将该socket连接维护为就绪状态。
      通过查询的系统调用,内核会返回一个就绪的socket列表。

      当用户程序执行select方法,整个线程就会阻塞掉

    • 用户线程发起read调用

      用户线程获取到就绪状态的socket列表后,依靠socket连接发起read系统调用,用户线程阻塞。内核开始复制数据,将数据从内存缓冲区复制到用户缓冲区。

    • 复制完成

      复制完成后,内核返回结果,用户线程接触阻塞状态。用户线程获取到了数据,继续向下执行。

    IO多路复用模型的特点
    • *** 作系统的内核必须能够提供多路分离的系统调用select/epoll。

    • 多路复用也需要轮询,负责select/epoll查询调用的线程,需要不断的进行select/epoll轮询,进而

      获取到就绪的socket连接。

    • 优点: 与一个线程维护一个连接的阻塞IO模式相比,优势在于一个选择器查询的线程可以同时处理成千上万个连接(Connection)。系统不必创建,维护大量线程。减小系统开销。

    • 缺点: 本质上,select/epoll 系统调用也是阻塞式的,属于同步IO。需要等待读写事件就绪后,由系统调用本身进行读写。

  • 异步IO (Asynchronous IO)

    彻底解决线程的阻塞,需要引入异步IO模型。

    异步IO,指的是用户空间与内核空间的调用方式反过来,用户空间的线程编程被动接受者,而内核空间成为主动调用者。

    类似于Java中比较典型的回调模式,用户空间的线程向内核空间注册了各种IO时间的回调函数,由内核去主动调用。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/756354.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-30
下一篇 2022-04-30

发表评论

登录后才能评论

评论列表(0条)

保存