背景
一个同学向我问起:一个 MySQL 的数据页默认为 16k,而 OS 内存页默认为 4k,他们的配置不一定会导致冲突吗?
分析过程
- MySQL 的 B+ Tree 的页大小,和操作系统虚拟内容的页大小是不同概念。
- MySQL 在读取一个节点数据时的步骤;
- 访问发现数据页未加载,发起一次文件读 IO;
- 操作系统将一个 B+ Tree 数据页(默认16k)加载到 MySQL 进程的内存中;一个 B+Tree 的数据页在文件上是连续的,所以加载一次数据页只需要一次文件IO。(参考 MySQL 技术内幕-InnoDB存储引擎 P120)
- Linux 的内存页 4k (指的是虚拟内存) 参考:draveness.me/whys-the-de… 《深入理解计算机系统》第9章 虚拟内存
- 内存是 OS 操作内存的最小单位,一般用于处理缺页中断。
问题:OS 在处理一个 MySQL 数据页(16k),会触发 4 次文件 IO 吗?
答案是:有可能会。逻辑如下:
- MySQL 进程从文件加载了 MySQL 数据页(假设命名为:a16)
- 由于物理内存不足,OS 的虚拟内存系统将 a16 淘汰到缓存文件中(交换区)
- MySQL 其后需要 a16 的第一段数据(a16-1:一个内存页 4kb),OS 触发缺页中断,因此去缓存文件中加载此页(一次文件IO)。同理,加载其余3个,会相继有3次 OS 的缺页中断,即一个 4 次文件 IO。
值得注意:
- 以上逻辑是有可能的,但前提是物理内存比较少。而且加载 OS 在虚拟内存的情况下,会使用局部性优化,上面的情况一般出现得比较少。
- 那是不是 MySQL 页大小总是设置为 4kb 才是最优?
- 答案:并不是,MySQL 加载一个数据页就是一个磁盘 IO,保持 4kb 数据页大小会导致文件 IO 增多,同样会降低查询效率。
结论:
- 保持 OS 的物理内存充足有利于存储系统的性能(实际上阿里云很多主机会直接关闭交换区)
- MySQL 的数据页大小是一个配置项,需要根据实际业务特点去配置。例如一行数据的大小为 1k,一个数据页只能保存 4 个数据,业务上又有批量查询的需求。那么这样的数据页大小过小是不合适的
- 内存的局部性原理能够有效避免文件经常被加载的问题(也就是预热数据)