当前位置: 首页 > article >正文

Linux之文件IO前世今生

在 Linux之文件系统前世今生(一) VFS中,我们提到了文件的读写,并给出了简要的读写示意图,本文将分析文件I/O的细节。
在这里插入图片描述

一、Buffered I/O(缓存I/O)& Directed I/O(直接I/O)

1.1、Page Cache

我们读写一个文件时,会从磁盘加载文件到内存中,以便我们快速读写文件;我们把内存中用于缓存文件的这块区域记为 Page CachePage Cache 位于内核态(所以也叫OS cache)。

  • page 是内存管理分配的基本单位, Page Cache 由多个 page 构成;
  • page 在操作系统中通常为 4KB 大小,而 Page Cache 的大小则为 4KB 的整数倍;
  • 更多 page 细节参见 Linux之内存管理前世今生(一)。

1.2、预读

根据程序的局部性原理,加载文件时除了加载文件指定位置内容,同时会加载该位置后续一部分连续内容到内存中,这个机制就是预读。所以 Page Cache 中额外包含了程序后续可能读写的内容。

1.2.1、Page Cache + 预读优势

  • 加速数据访问

    由于内存访问比磁盘访问快的多,且预读了后续数据;

  • 提高系统磁盘I/O吞吐量

    通过一次 I/O 将多个 page 装入 Page Cache 能够减少磁盘 I/O 次数, 进而提高系统磁盘 I/O 吞吐量;

1.3、Write back(写回)& Write Through(写穿)

由于我们在内核态引入的Page Cache机制,所以我们对文件的读写都是基于Page Cache,但文件最终还是需要持久化到磁盘中去的。Linux 提供两种策略将Page Cache脏页(dirty page) 刷回磁盘:

  • Write back(写回)
    • 内核线程周期性地将脏页刷回磁盘,Linux 默认采用此策略 ;
    • 该策略存在数据丢失的风险(比如遇到系统宕机、断电),理论上操作系统不宕机,数据就保证会刷回磁盘,即使用户程序崩溃;
  • Write Through(写穿)
    • 向用户层提供特定接口,应用程序可主动调用接口来直接刷新数据到磁盘
    • 以牺牲系统 I/O 吞吐量作为代价,向上层应用确保一旦写入,数据就已经落盘,不会丢失;

1.3.1、Page Cache刷盘涉及的系统调用

Write back(写回)& Write Through(写穿)这两种写策略均依赖系统调用,分为如下3种:

  • sync()

    将所有修改过的缓冲区排入写队列,然后就返回了,它并不等实际的写磁盘的操作结束。所以它的返回并不能保证数据的安全性。通常会有一个update系统守护进程每隔30s调用一次sync。

  • fsync(fd)
    • fd 代表的文件的脏数据和文件属性全部刷新至磁盘中;
    • 确保一直到写磁盘操作结束才会返回。数据库一般使用 fsync
  • fdatasync(fd)
    • fd 代表的文件的脏数据刷新至磁盘,fdatasync的功能与fsync类似,但是仅仅在必要的情况下才会同步文件属性,因此可以减少一次IO写操作;
    • 举例来说,文件的尺寸(st_size)如果变化,是需要立即同步的,否则OS一旦崩溃,即使文件的数据部分已同步,由于文件属性没有同步,依然读不到修改的内容。而最后访问时间(atime)/修改时间(mtime)是不需要每次都同步的,只要应用程序对这两个时间戳没有苛刻的要求,基本无伤大雅。

1.3.2、Write back 刷盘时机

  • Page Cache 脏页数量超过设定阈值;
  • Page Cache 脏页缓存超过设定缓存时间;
  • 应用程序主动刷盘,即调用 sync()fdatasync(fd)fsync(fd) 三者任一;
  • 物理内存分配告警;

1.4、Buffered I/O(缓存I/O)& Directed I/O(直接I/O)

  • 前面我们在内核态引入了Page Cache用于加速文件I/O的操作就是 Buffered I/O(缓存I/O)

在这里插入图片描述

  • 相反,如果在内核态关闭Page Cache的使用(通过参数O_DIRECT),文件I/O直接与磁盘交互,我们称为Directed I/O(直接I/O)

在这里插入图片描述

问题来了:Page Cache 这么好,什么场景需要关闭?

  • Page Cache 位于内核态,对用户态提供的API灵活性差,用户态的应用程序无法对Page Cache 进行个性化定制,比如什么时间刷盘,刷哪些数据……
  • Page Cache 容量受限,大文件读写时,很快会把Page Cache消耗完,导致之前缓存的常用的、热点数据被移出内存,下次访问热点数据时产生磁盘I/O,从而降低系统性能;即Page Cache 缓存的是小文件的热点数据。
  • 举例:Mysql 中 InnoDB :
    • Buffer Pool 关闭了Page Cache,即不在内核态缓存数据,直接在用户态缓存数据;
    • redo log buffer 通过参数innodb_flush_log_at_trx_commit(取值为0,1,2)设置为2来开启 Page Cache。

二、Blocking I/O(阻塞I/O)& Non Blocking I/O(非阻塞I/O)

  • 前面我们从 Page Cache 的维度,将 I/O分为 缓存I/O 和 直接I/O;
  • 接下来,我们从进程阻塞阶段的维度,将 I/O 分为 阻塞I/O 和 非阻塞I/O;

2.1、阻塞定义

阻塞 的主体是进程当进程进入阻塞状态,是不占用CPU资源的

2.2、阻塞时机

正在执行的进程,由于期待的某些事件未发生,如请求系统资源失败、等待某种操作的完成、新数据尚未到达或无新工作做等,则由系统自动执行阻塞原语(Block),使当前进程由运行状态变为阻塞状态。可见,进程的阻塞是进程自身的一种主动行为,所以只有处于运行态(获得CPU)的进程,才可能将其转为阻塞状态。

2.3、阻塞I/O

由前面定义,I/O时期待的事件未发生,产生阻塞,那到底期待啥呢?

等待内核将数据准备好,换言之,等待 Page Cache 中有程序请求的数据。

以文件读取为例:当一个read操作发生时,它会经历两个阶段:

第一阶段:等待数据准备 (Waiting for the data to be ready)。

第二阶段:将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)。

2.3.1、阻塞I/O vs 非阻塞I/O

当应用程序发起read时,且Page Cache 中没有程序请求的数据时,内核会加载磁盘数据,若加载数据同时,

  • read调用立即返回告诉程序,数据没有准备好,这就是非阻塞I/O

    非阻塞 I/O 在I/O执行的第二个阶段仍然被阻塞了。

  • 相反,内核闷声干活,直到数据加载完,并且数据从内核拷贝到应用程序中,才返回,这就是阻塞I/O

    阻塞 I/O 在I/O执行的两个阶段都被阻塞了。

在这里插入图片描述

在这里插入图片描述

三、同步 I/O(synchronous I/O)& 异步 I/O(asynchronous I/O)

POSIX(Portable Operating System Interface, 可移植操作系统接口)关于同步I/O和异步I/O的定义如下:

A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;

An asynchronous I/O operation does not cause the requesting process to be blocked;

在这里插入图片描述

说人话就是,同步I/O会阻塞进程,异步I/O不会阻塞进程
我们之前提到的 阻塞I/O 和 非阻塞I/O 都是同步I/O

  • 阻塞I/O 两个阶段都阻塞;
  • 非阻塞I/O 第二个阶段阻塞;

四、小节

  • Page Cache 的维度,将 I/O分为 缓存I/O 和 直接I/O;
  • 进程阻塞阶段的维度,将 I/O 分为 阻塞I/O 和 非阻塞I/O;
  • 进程阻塞的维度,将 I/O 分为 同步I/O 和 异步I/O。

文件 I/O 至此基本介绍完毕,后续会介绍网络 I/O。


http://www.kler.cn/a/538074.html

相关文章:

  • 使用Pytorch训练一个图像分类器
  • 数据结构——图
  • 移植BOA服务器到GEC2440开发板
  • 如何在Vscode中接入Deepseek
  • 数据结构-基础
  • 【通俗易懂说模型】反向传播(附多元回归与Softmax函数)
  • C++基础 |右值引用、移动语义与完美转发
  • 模型 冗余系统(系统科学)
  • 数据结构及排序算法
  • Java反射机制:解锁Java编程的奥秘
  • netcore openTelemetry+prometheus+grafana
  • MIT 6.5940(一)
  • 用JavaScript实现异步锁
  • aio-pika 快速上手(Python 异步 RabbitMQ 客户端)
  • 模型 反脆弱
  • 前端开发中的主题切换:如何实现灵活的主题变化?
  • 半导体制造工艺讲解
  • sqli-lab靶场学习(五)——Less15-17(post方法盲注、修改密码)
  • 从DeepSeek上线亚马逊云科技,看大模型争霸背后的隐形战场
  • 青少年编程与数学 02-008 Pyhon语言编程基础 23课题、数据库操作
  • 蓝桥杯之c++入门(六)【string(practice)】
  • NFT Insider #168:The Sandbox 推出新春{金蛇礼服}套装;胖企鹅合作 LINE Minini
  • java基础3(黑马)
  • 2014 年中央、国家机关公务员录用考试 《申论》(市地以下)真题详解
  • 人工智能:从概念到未来
  • lvglllllllllll