(1)Linux操作系统的存储系统
    简单说下,Linux操作系统利用自己的一套存储系统去管理cpu,内存,磁盘,网卡等硬件去执行文件编辑,读写等操作;
    Linux操作系统的存储系统分为 VFS层文件系统层Page Cache缓存层通用block层IO调度层Block设备驱动层Block设备层
    3907500_1583145173.jpg
    (2)MySQL的数据页具体执行过程:
    VFS层:当MySQL数据页发起一次数据页的随机读写,或者是一次redo log日志文件的顺序读写的时候,实际上会把磁盘IO请求交给Linux操作系统的VFS层,这一层就是你要对目录中的哪一个文件执行的磁盘IO操作,把IO请求交给具体的文件系统;
    例如,在Linux中,目录 /xx1/xx2 里的文件其实是由 NFS 文件系统管理的,有的目录如 /xx3/xx4 里的文件是由 Ext3文件系统管理的,那么这个时候VFS层需要你对哪个目录下的文件发起IO请求,把请求交给对应的文件系统。就是根据路径定位文件属于哪个文件系统的,把操作这个文件的IO请求交给这个文件系统。
    文件系统层,page cache:文件系统层会在Page Cache这个基于内存的缓存里查找你要的数据在不在,如果有就基于内存缓存来执行读写,如果没有就继续交给下一层处理。
    Block层,IO调度层:基于内存的Page Cache里没有这个数据,在这一层会把你的文件的IO请求转换为Block IO请求,接着会把这个Block IO请求交给IO调度层,在这一层里默认使用CFQ公平调度算法,就是数据库发起多个SQL语句同时执行IO,有的SQL语句只需更新磁盘上一个block里的数据就可以了,但是有的SQL需要IO读取磁盘上的大量数据。如果根据CFQ公平调度算法就会导致它先执行第二个SQL语句的读取大量数据的IO操作,第一个仅仅少量的IO操作就一直等待得不到执行。
    所以一般建议MySQL的生产环境,需要调整为deadline IO调度算法,让每个IO操作在一定时间都得到执行。

    Block设备驱动层,Block设备层:最后IO完成调度之后,就会决定哪个IO请求先执行,哪个IO请求后执行,此时可以执行的IO请求就会交给Block设备驱动层,最后经过驱动把IO请求发送给真正的存储硬件,也就是Block设备层。

    1. 硬件设备完成了IO读写操作之后,要不然是写,要不然是读,最后就把响应交给上面的层级反向依次返回,最终MySQL可以得到本次IO读写操作的结果。<br />![68722600_1583145188.jpg](https://cdn.nlark.com/yuque/0/2021/jpeg/232825/1630649513476-bb4f5587-5860-45ae-a5c3-6abda7e9ed87.jpeg#clientId=u004f98bf-2e60-4&from=ui&height=340&id=u77b577a6&margin=%5Bobject%20Object%5D&name=68722600_1583145188.jpg&originHeight=680&originWidth=664&originalType=binary&ratio=1&size=175958&status=done&style=stroke&taskId=u24097ecd-c1fe-4a92-8976-e265bb6b832&width=332)

    虚拟文件系统(Virtual File System):
    VFS 对高层进程和应用程序隐藏了 Linux 支持的所有文件系统的区别,以及文件系统是存储在本地设备,还是需要通过网络访问远程设备。 设备和其他特殊文件和 VFS 层相关联。
    为了能够使应用程序能够在不同类型的本地或者远程设备上的文件系统进行交互,因为在 Linux 当中文件系统千奇百种,比较常见的有 EXT3、EXT4,还有基于内存的 ramfs、tmpfs 和基于网络的 nfs,和基于用户态的 fuse,当然 fuse 应该不能完全的文件系统,只能算是一个能把文件系统实现放到用户态的模块,满足了内核文件系统的接口,他们都是文件系统的一种实现。
    对于这些文件系统,Linux 做了一层抽象就是 VFS虚拟文件系统。

    (1)文件系统缓存
    处理数据必须先从磁盘读到缓存,然后修改,然后刷会磁盘。缓存的刷新涉及到两个参数:vm.dirty_background_ratio、vm.dirty_ratio。还有刷新写回时,使用到 bio 结构,bio的组成是由磁盘上相邻的block组成的,所以这里进行了优化。
    (2)block layer
    该层就涉及到 IO调度算法,IO调度算法在mysql服务器是一个很重要的调优手段。系统中所有进程申请的IO操作,全部在这里进行排队,等待调度,然后写回磁盘。
    调度算法有四种: 1> Anticipatory: 适用于个人PC,单磁盘系统; Anticipatory:预期的
    2> CFQ(Complete Fair Queuing):默认的IO调度算法,完全公平的排队调度算法。
    每一个进程的IO请求会安排进一个专门的IO队列,然后按照进程组来公平的调度IO,也就是每一个进程组之间按照公平的方式来调度IO。显然他适合多用户的系统,但是极为不适合作为数据库系统的IO调度算法,因为显而易见,数据库系统中,数据库进程肯定是IO最多的一个进程组,然后它却只能获得和其它进程一样多的IO调度机会。所以显然这是极为不合理的。数据库系统绝对不要使用该调度算法。
    3> Deadline: 按照截止期限来循环在各个IO队列中进行调度,所以它提供了一个近实时的IO系统,并且磁盘throughput也很好,也不会造成starvation.一般mysql系统建议采用该调度算法。
    4> NOOP: 简单的FIFO队列进行调度,No operation的意思是,它没有进行额外的将临近的IO进行合并的操作,所以它对CPU的使用极少。该调度算法特别适合于SSD。因为SSD在对待顺序IO和随机IO没有什么区别。所以它不需要对临近的IO进行合并。避免了合并操作对CPU的使用。

    所以一般而言,对于mysql的系统,如果是SSD,那么应该使用NOOP调度算法,如果是磁盘,就应该使用Deadline调度算法。

    查看当前系统支持的IO调度算法 dmesg | grep -i scheduler
    查看当前系统的I/O调度方法: cat /sys/block/sda/queue/scheduler
    临地更改I/O调度方法: echo noop > /sys/block/sda/queue/scheduler

    想永久的更改I/O调度方法: 修改内核引导参数,加入elevator=调度程序名
    [root@localhost ~]# grubby —update-kernel=ALL —args=”elevator=deadline”
    [root@localhost ~]# reboot
    [root@localhost ~]# cat /sys/block/sda/queue/scheduler
    noop [deadline] cfq

    https://www.cnblogs.com/andy6/p/9577381.html

    /proc/sys/vm/dirty_ratio
    文件系统写缓冲区的大小,单位是百分比,表示系统内存的百分比,表示当写缓冲使用到系统内存多少的时候,开始向磁盘写出数据。增大之会使用更多系统内存用于磁盘写缓冲,也可以极大提高系统的写性能。但是,当需要持续、恒定的写入时,应该降低其数值。
    /proc/sys/vm/dirty_background_ratio
    控制 pdflush 进程在何时刷新磁盘。单位是百分比,表示系统内存的百分比,意思是当写缓冲使用到系统内存多少的时候, pdflush 开始向磁盘写出数据。增大之会使用更多系统内存用于磁盘写缓冲,也可以极大提高系统的写性能。但是,当需要持续、恒定的写入场合时,应该降低其数值。