问题引入
舍友最近在找实习,简历上有CMU15-445经典数据库项目。在面试时被问到:
-
操作系统已经有页面置换算法,为什么Buffer Pool中还需要自己实现呢?
-
操作系统中的页面置换,对自己实现的页面置换有什么影响?
个人理解
MySQL在默认配置下,读取一行数据,要先打开磁盘中对应的数据页,这时因为局部性,会直接复制一份磁盘文件的整页数据到Page Cache中。
然后,这一页还会被读到用户空间的Buffer Pool中;Buffer Pool中数据的修改,对Page Cache没有影响。
当Buffer Pool淘汰了数据页,会把脏页的内容刷进Page Cache。之后fsync()才会把Page Cache的内容刷到磁盘中。
这里Page Cache和Buffer Pool的内容有重叠,浪费内存了。所以MySQL提供了O_DIRECT方式,可以绕过Page Cache,节省内存。
回到最初的问题,数据库文件太大,Buffer Pool只按需缓存其中一部分内容到内存。而Buffer Pool是用户内存空间的一部分,又受到OS页面置换的管理。
Buffer Pool的置换算法管理的是哪些磁盘页被调入虚拟内存;OS的置换算法管理的是Buffer Pool的虚拟内存中,哪些部分使用实际物理内存,剩余部分被swap到磁盘中。
回答第2个问题:OS的置换只是超出了实际物理内存空间才会进行,平时对Buffer Pool应当没有影响。所以Buffer Pool的大小应该合理设置,如果太大,超出的部分会经常被OS给置换,影响效率;而太小,就达不到缓存的效果了,因为要不停自我置换。
那可不可以Buffer Pool不实现磁盘页置换,把数据文件全都装进来?反正虚拟内存空间很大嘛,需要的时候OS会帮我们调。
我想这样不太好,因为Buffer Pool中应该会使用哈希表,保存数据页号到Buffer Pool中地址的映射,如果不置换,这个哈希表越来越大,查起来就很慢了。
还有个原因我觉得是,自定义的置换算法比较灵活,可以根据数据库的特性去调整,并随着版本更新去不断优化调整。而OS是通用的置换,不够灵活。
到这里还有一个想法:是否可以用O_DIRECT方式的mmap把整个数据库文件映射到内存里,这样完全由OS进行页面置换管理?我去查了下为什么没人这么干,搜到一篇回答,可以看参考资料中的最后一篇。
大意说的是mmap不够灵活,即使使用了mmap,代码量也不会减少很多。Buffer Pool实际上是mmap的重新实现。
参考资料
mysql刷盘机制详解_liuzhilong_62的博客-CSDN博客
揭开 Buffer Pool 的面纱 | 小林coding
细看InnoDB数据落盘 图解 MYSQL 专家hatemysql - zengkefu - 博客园
关于Linux中的mmap和page cache的问题? - 知乎
Why is mmap considered bad while designing a database system? - Quora