内存数据库系统在磁盘上维护备份,以提供持久性并防止易失性。有些数据库只在内存中存储数据,没有任何持久性保证。
数据库在认定操作完成之前,必须先将其结果写入一个顺序日志文件。为了避免在启动过程中或奔溃后重放完整的日志内容,内存数据库维护了一个备份副本。该备份副本使用一个基于磁盘且已排序的数据结构。并且对该结构的修改通常是异步(与客户端请求解耦)且分批处理的。这样可以减少I/O操作数量。在恢复过程中,数据库可以从备份和日志还原数据库内容
日志数据通常用于批量备份,在处理该批日志数据之后,备份将持有截止到这一特定时间点的数据库快照。因此可以丢弃之前的日志内容。这个过程称为生成检查点(checkpointing). 它会更新磁盘上点数据库快照使其更接近最新的日志条目,从而缩短恢复时间,且备份过程不会阻塞客户端请求。
使用页缓存在内存里,序列化格式和数据布局也会使磁盘数据库产生额外的开销,而不会达到与内存数据库相同的优化程序。
pagecache
Page Cache的机制如上图所示,具体来说,当应用程序读文件时,系统先检查读取的文件页是否在缓存中;如果在,直接读出即可;如果不在,就将其从磁盘中读入缓存,再读出。此时如果内存有足够的内存空间,该页可以在page cache中驻留,其他进程再访问该部分数据时,就不需要访问磁盘了。
同样,在写文件之前,系统先检查对应的页是否已经在缓存中;如果在,就直接将数据写入page cache,使其成为脏页(drity page)等待刷盘;如果不在,就在缓存中新增一个页面并写入数据(这一页面也是脏页)。真正的磁盘I/O会由操作系统调用fsync等方法来实现,这一调用可以是异步的,保证磁盘I/O不影响文件读写的效率。
dirty_background_ratio
// 触发文件系统异步刷脏的脏页占总可用内存的最高百分比,当脏页占总可用内存的比例超过该值,后台回写进程被触发进行异步刷脏。
dirty_ratio
// 触发文件系统同步刷脏的脏页占总可用内存的最高百分比,当脏页占总可用内存的比例超过该值,生成新的写文件操作的进程会先执行刷脏。
dirty_background_bytes & dirty_bytes
// 上述两种刷脏条件还可通过设置最高字节数而非比例触发。如果设置bytes版本,则ratio版本将变为0,反之亦然。
dirty_expire_centisecs
// 这个参数指定了脏页多长时间后会被周期性刷脏。下次周期性刷脏时,脏页存活时间超过该值的页面都将被刷入磁盘。
dirty_writeback_centisecs
// 这个参数指定了多长时间唤醒一次刷脏进程,检查缓存并刷下所有可以刷脏的页面。该参数设为零内核会暂停周期性刷脏。
http://mysql.taobao.org/monthly/2020/09/01/
https://lwn.net/ml/linux-fsdevel/20191210162454.8608-1-axboe@kernel.dk/
https://web.cs.iastate.edu/~prabhu/Tutorial/title.html
http://www.howardhuang.us/teaching/cs232/24-Cache-writes-and-examples.pdf
https://man7.org/tlpi/code/online/dist/filebuff/direct_read.c.html
https://linux.die.net/man/2/open