转载自https://www.jianshu.com/p/444646e02ef7
簇
对于磁盘的驱动来说,存在一个最小的操作单位。这个单位被称为“簇”(sector)。
块
虚拟文件系统(VFS)抽象了磁盘设备,是以块为单位,块的大小是簇的整倍数。对于操作系统在驱动程序之上的层次来说,访问磁盘数据的最小单位是“块”。即,即使你只想读取1个Byte,磁盘也至少要读取1个块;要写入1个Byte,磁盘也至少要写入一个块。
Page Cache
在虚拟文件系统层之上,是内存。这一层被称为Page Cache。这个层次是用页面(Page)来组织的。一般来讲一个页面是4KB,一个页面对应若干个“块”。
Page Cache对于磁盘IO的性能表现极度重要。比如,当通过write API写入数据到磁盘时,数据先会被写入到Page Cache。此时,这个Page被称为“dirty page”。dirty page会最终被写入到磁盘上,这个过程为称之为“写回”(writeback)。写回往往不会立刻发生。写回可能由于调用者直接使用类似于fsync这样的API,也有可能因为操作系统根据某种策略和算法决定自动写回。写回发生之前,如果机器挂了,就有可能丢失数据。这也是为什么有持久性要求的程序都需要用fsync来保证数据落地的原因。
当读取数据时,操作系统会先尝试从Page Cache里找,如果找到了就会直接返回给应用程序。如果找不到,就会触发“页错误”(Page Fault),迫使操作系统去读取磁盘数据,在Page Cache里进行缓存,然后将数据返回给上层应用程序。
应用程序
Page Cache的上层是应用程序,就是我们平时写的程序了。
在处理IO数据时,应用程序总是需要在用户态分配一段内存空间作为buffer,然后将Page Cache中的数据copy出来进行处理。处理完成后,将数据写回(copy回)到Page Cache。
如果你留意这个图,就会发现,这里会多额外两次数据的copy(并且是CPU copy)。但是有两种方法可以避免这两次copy,分别是mmap和sendfile(发送网络数据时,实现零拷贝)。
Direct IO
上面介绍的是用了Page Cache的IO一般被称为Buffered IO,与Buffered IO相对的,是Direct IO。即应用程序直接读写块设备,不再经过Page Cache。
AIO
操作系统没有完全实现AIO,一般上层(nodejs,Java NIO)都会选择用线程池+BIO来模拟文件AIO。