[230529] 文件 IO 简明概述

[230529] 文件 I/O 简明概述

写在前面:本文是文件 I/O 简明概述部分文章的学习笔记,非常感谢北邮的研究生学长整理输出的文章,为我的学习提供了便利,获益匪浅。感谢!

一 Page Cache

1. Page Cache

1.1 什么是 Page Cache

Page Cache 是 Linux 内核管理的内存区域,通过 mmap 或 buffered I/O 将文件读取到内存空间实际上是读取到内核的 Page Cache 中。

1.2 查看系统的 Page Cache
$cat /proc/meminfo
1.3 page 与 Page Cache

page 是内存分配的基本单位,Page Cache 由多个 page 构成。page 在操作系统中通常为 4KB 大小(32bits/64bits),而 Page Cache 的大小为 4KB 的整数倍。

Linux 系统上可供用户访问的有两种类型:

  • File-backed pages:文件备份页,即 Page Cache 中的 page,对应磁盘上的若干数据块;对于这些页,最大的问题是脏页回盘。(Page Cache 是由内核管理的,为什么说可供用户访问?难道是指类似 mmap 的访问吗)
  • Anonymous pages:匿名页不对应磁盘上的任何磁盘数据块,他们是进程的运行空间。

swap 机制:

  • 内存在计算机中是珍稀资源。当内存不足时,需要进行内存空间的回收,即把内存上的数据写回磁盘,把磁盘中需要的数据交换出来。这就是 swap 机制。

File-backed pages 和 Anonymous pages 在 swap 机制下的性能:

  • File-backed pages 的内存回收代价较低。Page Cache 通常是磁盘中连续的块,所以它进行的是顺序 I/O。并且,如果 Page Cache 不是脏页的话,可以不用回写到磁盘。
  • Anonymous pages 的内存回收代价较高。因为匿名页中的数据总是要经常做持久化处理的,并且进行的是随机 I/O。为了防止数据丢失,匿名页在 swap 时必须持久化到磁盘。
1.4 swap 与缺页中断

swap 存在的本质原因是虚拟内存机制,所有进程都认为自己独占物理内存空间,所有进程内存空间的总和是大于实际物理内存空间的,多出的部分存在于磁盘上。所以当进程访问到不在物理内存上的 pages 时,我们说此时发生了缺页中断。如果此时物理内存空间不足,就需要操作系统进行 swap

1.5 Page Cache 与 buffer cache

Page Cache 是文件系统中文件的缓存,buffer cache 是磁盘中数据的块缓存。因为磁盘上的大多数据是以文件系统的形式组织的,所以 Page Cache 和 buffer cache 中的数据可能有重合。这样的情况下,我们会在 buffer cache 中只储存指向 Page Cache 的指针,减少内存浪费。

1.6 Page Cache 与预读

由于空间局部性原理,在从磁盘中读数据时会预先读取目标数据后面的数据到内存中。但预读机制存在预读失效的风险,Linux 通过改善 LRU 算法,设置 active list 和 inactive list 来改善这个问题。

2 Page Cache 与文件持久化的一致性&可靠性

一致性问题:内存中的数据与持久化设备上的数据不一致。有缓存就会有一致性问题。

文件的结构:文件由元数据和数据组成。元数据是指与文件属性有关的信息,例如文件修改时间、文件大小等。

Linux 通过两种方式来实现文件一致性:

  • write through(写穿):由用户利用系统调用将 Page Cache 写回持久化设备
  • write back(写回):由内核线程周期性执行,把所有脏页写回到持久化设备

主要的系统调用:

系统调用描述
fsync(intfd)fsync(fd):将 fd 代表的文件的脏数据和脏元数据全部刷新至磁盘中。
fdatasync(int fd)fdatasync(fd):将 fd 代表的文件的脏数据刷新至磁盘,同时对必要的元数据刷新至磁盘中,这里所说的必要的概念是指:对接下来访问文件有关键作用的信息,如文件大小,而文件修改时间等不属于必要信息
sync()sync():则是对系统中所有的脏的文件数据元数据刷新至磁盘中

write through 与 write back 在文件持久化可靠性上的不同:

  • write through:以牺牲系统 I/O 吞吐量为代价,确保一旦上层应用修改了数据,数据一定会回盘
  • write back:当系统宕机时不保证全部脏页写回磁盘,但如果是程序终止,比如被 kill -9 了,会保证脏页回盘。

3 Page Cache 的优劣势

3.1 Page Cache 的优势
  1. 加快数据访问
  2. 减少 I/O 次数,提高系统磁盘 I/O 吞吐量(磁盘 I/O 吞吐量:每秒内)
3.2 Page Cache 的劣势
  1. 占用额外的物理内存,当物理内存比较紧俏的时候会导致频繁的 swap 操作
  2. 没有为上层用户提供很好的管理 API,用户即使想优化 Page Cache 也很难进行
  3. 在某些应用场景下比 Direct I/O 多一次磁盘读和一次磁盘写。

二 DMA 与零拷贝技术

1 数据的四次拷贝与四次上下文切换

当用户调用 read 从磁盘中读取文件和并用 write 写到网络上时,会发生四次数据拷贝和四次上下文切换。

  1. 调用 read,从用户态切换到内核态,把数据从磁盘拷贝到内核缓冲区中的 Page Cache 上,然后再把数据从内核缓冲区的 Page Cache 拷贝到用户缓冲区,最后 read 返回,从内核态切换回用户态。
  2. 调用 write,从用户态切换到内核态,把数据从用户缓冲区拷贝到内核缓冲区中的 socket 缓冲区上,然后再把数据从 socket 缓冲区拷贝到网卡,最后 write 返回,从内核态切换回用户态

2 DMA 技术中的四次数据拷贝

DMA 技术是通过 DMAC(DMA Controller)实现的。由 CPU 来控制 DMAC 协助 CPU 完成设备之间的数据拷贝,比如:

  1. 把数据从磁盘拷贝到内核缓冲区的 Page Cache 中
  2. 把数据从内核的 socket 缓冲区拷贝到网卡

但是,设备内部的数据拷贝仍然需要 CPU 完成。

3 零拷贝技术

零拷贝技术是指,CPU 不用再负责把数据从内存某处拷贝到另一特定区域,而不是不需要数据拷贝(换言之,还是需要利用 DMA 技术来完成从磁盘到内存的数据拷贝的)。

零拷贝技术有以下几种实现方式:

  • sendfile:不需要把数据从内核空间的 Page Cache 拷贝到用户空间,不需要把数据从用户空间拷贝到 socket 缓冲区;如果 DMAC 支持 SG-DMA 技术,还可以在内核空间的 Page Cache 和 socket 缓冲区之间直接传递文件描述符,而不进行数据拷贝。
  • mmap:
  • direct I/O:磁盘和用户空间直接进行数据拷贝,不经过内核空间的 Page Cache。
  • splice:略
3.1 sendfile

sendfile 用一次系统调用代替了 read 和 write 两次系统调用,因此不需要把数据从内核空间的 Page Cache 中拷贝到用户空间,再从用户空间拷贝到内核空间的 socket 缓冲区。如果 DMAC 支持 SG-DMA 技术,还可以在内核空间的 Page Cache 和 socket 缓冲区中传递文件描述符,不需要把数据从 Page Cache 拷贝到 socket 缓冲区。

sendfile 的典型应用场景是消息队列。

忽然觉得,了解过程才是最重要的,硬背几次数据拷贝几次上下文切换太无聊了。

3.2 mmap

通过使用内存映射,把内核空间中的 Page Cache 对应的物理地址一一映射到进程虚拟地址空间中的文件映射区,减少了一次从内核空间 Page Cache 到用户空间的数据拷贝。

3.3 Direct I/O

Direct I/O 是什么:

  • read 操作:不经过 Page Cache,把数据从磁盘直接读取到用户空间
  • write 操作:不经过 Page Cache,把数据从用户空间直接写回磁盘

Direct I/O 的优点:

  1. 略过了系统缓存的结构,降低了系统级别程序对应用程序访问数据的影响
  2. 用户空间与磁盘直接进行数据交互,提高了性能

Direct I/O 的缺点:

  1. 第一点没太看懂
  2. 需要数据时若数据不在用户空间中,需要去磁盘取,加载比较缓慢
  3. 在用户空间引入直接 I/O,需要用户对其进行管理,增加了系统的复杂性

Direct I/O 的应用:

  • 自缓存应用程序会使用 Direct I/O(自缓存应用程序是指,在用户空间内自己实现了缓存机制的程序,而不使用操作系统提供的缓存结构,比如数据库管理系统就是最典型的自缓存应用程序)
  • Linux 中的异步 I/O 会使用 Direct I/O

4 典型案例

4.1 Kakfa

Kakfa 作为消息队列,在两个场景下涉及到了磁盘 I/O 操作:

  • 当 Producer 向 Kakfa 发送消息时,利用 mmap 将日志消息进行持久化
  • 当 Consumer 向 Kakfa 拉取消息时,利用 sendfile 将日志消息发送出去

注意:利用 mmap 将收到的数据进行持久化,利用 sendfile 将数据发送出去,是常用的组合。

4.2 MySQL

很复杂,移步MySQL 的零拷贝技术

5 疑问

TCP 的发送缓冲区和接收缓冲区是在哪里?用户程序中的 write buffer(用户空间)、socket 缓冲区还是网卡呢?

每个 TCP socket 连接在内核空间的 socket 缓冲区中都有一个发送缓冲区和接收缓冲区。

三 MMAP

1 mmap 基础概念

mmap(memory map)是指内存映射,把磁盘中的数据映射到进程的虚拟地址空间,使用的是逻辑地址。

2 mmap 的 I/O 模型

使用 mmap 也可以实现零拷贝技术,具体的流程如下:

  1. 用户调用 mmap,将磁盘的数据拷贝到内核空间中的 Page Cache,无需将内核空间 Page Cache 中的数据拷贝到用户空间,只需要完成进程虚拟地址到内核空间物理地址的一一对应
  2. 用户调用 write,由 CPU 负责将内核空间 Page Cache 中的数据拷贝到 socket 缓冲区,再从 socket 缓冲区拷贝到网卡

3 mmap 的优势

  1. 简化用户编程
    • mmap 实现的是基于缺页的懒加载,也就是说,只有当用户程序真正使用到对应的数据时,发现缺页中断,才会真正地把磁盘中的数据加载到物理内存
    • mmap 机制下由操作系统保证文件一致性,也就是说,当出现脏页时,由操作系统负责脏页的落盘
  2. 提高读写效率:不需要将数据从内核空间的 Page Cache 拷贝到用户空间,并且可以通过指针的偏移对文件进行读写
  3. 避免了只读情况下的 swap 操作:如果对 mmap 的文件没有写操作,当物理内存不足且发生缺页中断时,不需要把 mmap 的内存页写回到磁盘上;但如果是其它内存数据,如果出现脏页,就必须 swap 到磁盘。
  4. 节约内存:将文件数据拷贝到内核空间的 Page Cache,可由多个进程共享此 Page Cache,无需重复拷贝。

4 mmap 的使用场景

  1. 多线程共享同一份文件
  2. 多进程之间通过共享内存实现进程间通信,并且可以依赖于操作系统的同步原语(后半句话什么意思?我觉得是使用 mmap 时操作系统会保证同步吧)

四 文件分区

1 文件分区是什么

文件分区包括两件事:

  1. 把大文件分成多个小文件储存
  2. 把不同类型的文件存储到不同的磁盘上

2 文件分区的意义

  1. 减少文件锁粒度,提高并发 I/O 潜力:小文件比大文件的文件锁粒度更小,降低锁冲突的可能性。
  2. 简化索引实现:一个大文件的索引树会有很多节点,查询效率较低;如果把一个大文件分成几个小文件,每个小文件对应一个索引文件,查询效率较高。
  3. 分磁盘存储文件提高磁盘 I/O 效率:实现并行化 I/O,不同文件的 I/O 模式可以不同(顺序/随机),更可靠的持久化保证

九 如何实现顺序读写

1 为什么顺序读写更快

顺序读写更快有两个原因:

  1. 顺序读写下磁盘指针移动的长度更小
  2. 顺序读写下可以实现 Page Cache 的预读机制,提高了缓存命中率(基于局部性原理)

2 Java 上利用锁实现顺序读写

我不会 java…

3 扩展:锁

操作系统提供的 write 系统调用不保证原子性。文件系统提供两个操作的原子性,即当 open 系统调用以 flag 为 O_CREAT 或 O_APPEND 打开文件时:

  • O_CREAT:文件不存在就创建
  • O_APPEND:每次写文件时把文件游标移动到文件最后追加写

但是,即使保证原子操作,也无法保证并发安全性,因为原子性只是并发安全的一个条件。

解释:

这是因为在多线程并发执行的情况下,原子性并不能确保所有线程看到的数据都是一致的。例如,在读写操作时,如果两个线程同时读取同一个变量,由于原子性并不能保证这两个线程看到的变量值是一致的,因此可能会导致数据不一致的问题。

要保证并发安全,需要同时考虑原子性、数据一致性和互斥性等因素。即需要保证所有线程看到的数据都是一致的,并且不会发生数据冲突。

我们通常使用锁来保证并发安全,如 Linux 有提供两种类型的文件锁:

  • flock:对整个文件上锁
  • fcntl:既可以对整个文件上锁,也能只锁文件的某一部分
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值