从文件read/write一个字节的过程和所发生的磁盘IO

IO时(不管是磁盘IO还是网络IO)的过程整体上看有两个操作(write过程与read过程相反):

1 将数据从外设读入内核态内存,如从网卡读入到内存Ring Buffer。此过程为DMA read,不需要CPU参与,完成后通过中断通知CPU。我们通常说IO操作耗时,就是这步耗时。

2 从内核态内存复制到用户态内存(通常就是应用程序进程的内存)。此过程为CPU read,需要CPU参与。之所以要有这一步而不是将外设数据直接复制到用户态内存,是因为OS出于安全考虑不允许用户态应用程序直接访问IO设备。

但深入追究的话该过程实际上相当复杂,概要图如下:

详见下文。

读过程概要:

note:

OS支持多种文件系统,一个磁盘上可以有多个分区,每个分区可以格式化成一种文件系统,不同分区格式化成的文件系统可以不一致;OD提供了虚拟文件系统(VFS)以屏蔽对不同文件系统的访问,页缓存(PageCache)位于VFS和实际的FS之间。

磁盘自身数据读取以扇区(通常为512B)为单位、文件系统以块block(通常为4KB)为单位管理数据、PageCache以页Page为单位(通常为4KB)管理数据。可见:

一次磁盘IO的数据有多少?虽然用户只需要一个字节,但实际上至少一页(即8扇区)的数据会被从磁盘读取到内存PageCache(即使只需要一个字节);

是否一定会有磁盘IO?PageCache在内存中暂存这些Page,若下一次访问时PageCache中存在需要的数据则直接从内存取而不需要读磁盘,因此,由于PageCache的存在,读取文件一个字节并不一定会导致磁盘IO。

从上述过程看,若写数据时写入到了PageCache,则此时用户的写磁盘操作从效果上看是异步的。

详情参阅文章 read 文件一个字节实际会发生多大的磁盘IO

写过程概要:

 

note:

写的过程与读类似,先后经历 用户态写、系统调用写、VFS系统写、写PageCache、实际FS写、磁盘驱动写 等过程。

有多种写的方法,如同步写、异步写等,区别在于写方法是否等数据真正写入磁盘才返回。对于异步写,数据写入PageCache(此时该PageCache称为脏页)写方法就立即返回。

脏页数据由内核Worker线程周期性地扫描,将符合条件(脏页数据的 比例达到阈值、总量达到阈值、存在时间达到阈值 至少一个,阈值可配置)的脏页数据持久化到磁盘,这才是真正的“写”。持久化的时机:

数据会在如下三个时机下被真正发起写磁盘IO请求:
第一种情况,如果write系统调用时,如果发现PageCache中脏页占比太多,超过了dirty_ratio或dirty_bytes,write就必须等待了。
第二种情况,write写到PageCache就已经返回了。worker内核线程异步运行的时候,再次判断脏页占比,如果超过了dirty_background_ratio或dirty_background_bytes,也发起写回请求。
第三种情况,这时同样write调用已经返回了。worker内核线程异步运行的时候,虽然系统内脏页一直没有超过dirty_background_ratio或dirty_background_bytes,但是脏页在内存中呆的时间超过dirty_expire_centisecs了,也会发起会写
View Code

由于PageCache位于内存,而异步写时会优先考虑往PageCache写,故异步写的效率很高;但也由于PageCache在内存,发生断电等异常情况时数据可能还没来得及持久化,故数据可能丢失。

 

详情参阅文章 write 文件一个字节实际会发生多大的磁盘IO

原文地址:https://www.cnblogs.com/z-sm/p/15163921.html