社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
在服务器工作阶段,会出现大量得输入输出数据,这些数据不会被立即写入磁盘中。
linux系统中分为用户空间和内核空间,用户空间中有一个缓存区,用来暂时存放输入输出数据,等缓存区被放满了,再写入磁盘中,由于磁盘得读写速度和次数有限,这样做是为了提高读写效率和减少磁盘IO的读写次数。
那么,什么情况下缓存区的数据会被写入磁盘呢,有以下几种:
1、换行符号‘n’,因为缓存区是行缓存,加换行符号相当于告诉系统行缓存满了,可以写入磁盘了;
2、fflush()函数刷新数据;
3、scanf(),该函数内部会调用write写入操作;
4、setbuf(),当遇到紧急数据需要立即写入磁盘的时候,该函数可以直接关掉用户空间的缓存区;
5、等到缓存区满了,会自动写入磁盘;
除了用户空间,内核空间也有缓存区,而且内核缓存的大小没有明确规定,一般都是由物理内存决定的,所以还是挺大的;因为CPU的处理速度远远大于磁盘IO的速度,所以内核缓存的存在就是将内核每一次读取的数据存放在内核缓存中,当需要的时候直接从内核缓存中拿出来用,不够的时候再去打扰磁盘它老人家。
而且,每一次内核从磁盘读取数据,一次读取都是4096个字节,当其他地方需要的数据在这4K的数据内,就直接使用,暂停不会再从磁盘读取。
当需要写入的时候,只有当内核缓存中被写满了,才会被系统写入磁盘中;但是内核缓存是很大的,现实中我们不可能等到缓存满了再写入磁盘,这样会长时间导致内核缓存和磁盘的数据长期不同步。
为此,系统中设定了一个超时时间,知道超过了这个时间,即使内核缓存没有满,也会被写入磁盘中,这个超超时时间具体的系统版本是不一样的,可以在/proc/sys/vm/dirty_expire_centisecs中查看,单位是百分之一秒。
内核缓存有一个特性,就是掉电不保持,一旦掉电,缓存中所有的数据都会消失,这对于一些处理紧急重要的数据是具有极大的风险的,即使有了超时时间的限定,但是在这么一个时间内,还是存在着掉电丢失的可能性。
因此linux系统中可以手动将数据即时写入磁盘的两种操作:
第一种,跳过内核缓存,直接读写磁盘
open(filename,O_DIRECT),O_DIRECT该参数设置可将文件数据处于跳过内核缓存状态,不过只有在linux2.4版本或以上才有。
而且在采用这种方法的时候,write()函数中缓存区的大小在一开始定义的时候一定要是512个字节的倍数,因此申请缓存的malloc()是行不通的,因为不知道具体申请了多少内存,这时候就要用到posix_memalign()函数了。
一般而言,这种跳过内核缓存的方法是不建议的,每当有数据进行就直接操作磁盘IO,一来大大增加了磁盘IO的读写次数,二来放弃了内核缓存中的优化策略。
第二种,缓存同步,即内核缓存中的数据与磁盘中的数据时刻保持着同步
缓存同步需要知道三个函数
sync():将内核缓存中的数据写入磁盘之前的队列中,不等待磁盘操作结束就返回了。
fsync():将内核缓存中的数据立即写入磁盘中,并等待磁盘操作结束后返回,不过其只是更新磁盘中的数据部分,不更新文件属性,文件属性等到内核缓存满了自动刷新磁盘,可以提高效率。
fdatasync();跟fsync功能类似,不同的是其不仅更改数据部分,同步还更新文件属性。
除了以上三个函数,还有常见的open()中第二个参数如果选用O_SYNC,那么也会跟fsync()效果一样。
当然了,以上两种方法,不借用内核缓存,采用直接输入磁盘的话,占用运行时间肯定是要更长的。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!