1. sync 和 fsync
sync只是将所有修改过的块的缓存排入写队列,然后就返回,它并不等待实际I/O操作结束。相当于是异步的。
fsync只引用单个文件,它等待I/O结束,然后返回。相当于同步操作。
当将数据写到文件上时,通常该数据先由内核复制到缓存中,如果该缓存尚未写满,则并不将其排入输出队列,而是等待其写满或者当内核需要重用该缓存以便存放其他磁盘块数据时,再将该缓存排入输出队列,然后待其到达队首时,才进行实际的I/O操作。这种输出方式被称之为延迟写(delayed write)。
2. WAL
在计算机科学中,预写式日志(Write-ahead logging,缩写 WAL)是关系数据库系统中用于提供原子性和持久性(ACID属性中的两个)的一系列技术。在使用WAL的系统中,所有的修改在提交之前都要先写入log文件中。
log文件中通常包括redo和undo信息。这样做的目的可以通过一个例子来说明。假设一个程序在执行某些操作的过程中机器掉电了。在重新启动时,程序可能需要知道当时执行的操作是成功了还是部分成功或者是失败了。如果使用了WAL,程序就可以检查log文件,并对突然掉电时计划执行的操作内容跟实际上执行的操作内容进行比较。在这个比较的基础上,程序就可以决定是撤销已做的操作还是继续完成已做的操作,或者是保持原样。
WAL允许用in-place方式更新数据库。另一种用来实现原子更新的方法是shadow paging,它并不是in-place方式。用in-place方式做更新的主要优点是减少索引和块列表的修改。ARIES是WAL系列技术常用的算法。在文件系统中,WAL通常称为journaling
3. 缓存
由于下一级的硬件跟不上上一级的读写速度,缓存这东西应运而生。硬盘有缓存,操作系统有缓存,标准库也有缓存,用户还可能自己设缓存,总之是各种的缓存。命中缓存时,可以大大提高读的速度,只有当缓存穿透才会到下层去请求数据。写操作也由于缓存的存在而变成了批量操作,吞吐得以提高。
然而写的时候遇到突然断电的情况,数据还在缓存层没刷下去,就尴尬了...会丢数据!如果要保证可靠写这里我们需要采取些法子,手动将缓存刷进磁盘里。
4. flush/fsync/WAL
flush是刷C标准库的IO缓存。fsync是系统调用,页缓存会被刷到磁盘上。
写IO有好多种方式,最笨的调用C的IO库,然后还有操作系统的read/write,或者mmap又或者使用direct-io,甚至是写祼设备。关于这些写下去相关知识也不少。
WAL是常识性的东西,先出日志,重放日志就可以得到快照,即使快照坏掉了,重放日志也可以恢复出正常的快照。而且做同步一般都是基于日志来做的。