MySQL 顺序读写,随机读写,linux底层读写原理

顺序,随机

1
2
3
4
5
6
7
8
9
CREATE TABLE `person_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`birthday` date NOT NULL,
`phone_number` char(11) NOT NULL,
`country` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_name_birthday_phone_number` (`name`,`birthday`,`phone_number`)
) ENGINE=InnoDB

主键索引:id
联合索引:idx_name_birthday_phone_number

假设已存在数据
在这里插入图片描述

我们在进行范围查找的时候,如

1
SELECT * FROM person_info WHERE name > 'Ashburn' AND name < 'Ashburn3'

(1)、由于索引idx_name_birthday_phone_number对应的B+树中的 记录首先会按照name列的值进行排序,所以值在Ashburn~Ashbur3之间 的记录在磁盘中的存储是相连的,集中分布在一个或几个数据⻚中, 我们可以很快的把这些连着的记录从磁盘中读出来,这种读取方式我 们也可以称为顺序I/O

(2)、根据第1步中获取到的记录的id字段的值可能并不相连,而在聚簇索引中记录是根据id(也就是主键)的顺序排列的,所以根据这些并不连续的id值到聚簇索引中访问完整的用户记录可能分布在不同的数据⻚中,这样读取完整的用户记录可能要访问更多的数据⻚,这种读取方式我们也可以称为随机I/O

一般情况下,顺序I/O比随机I/O的性能高很多,所以步骤1的执行可能很快,而步骤2就慢一些。

附加参考:
硬碟与储存设备 — 鸟哥的Linux 私房菜
MySQL顺序读写和随机读写磁盘_随机读写与顺序读写的深入理解

在这里插入图片描述
一起认识下关于磁盘的读写原理和顺序读写,随机读写。

首先磁盘是如何存储数据的?
信息存储在硬盘里,把它拆开也看不见里面有任何东西,只有些盘片。假设,你用显微镜把盘片放大,会看见盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化;凸起的地方代表数字1(磁化为1),凹的地方代表数字0。因此硬盘可以以二进制来存储表示文字、图片等信息。

机械盘和固态盘的区别

  • 机械盘:数据是存储的扇区的,读写是依靠磁头的摆动寻址的。顺序读写主要时间花费在了传输时间,随机读写需要多次寻道和旋转延迟。
  • 固态盘:是由控制单元和固态存储单元(DRAM或FLASH芯片)组成,存储单元负责存储数据,控制单元负责读取、写入数据。

由于固态硬盘没有普通硬盘的机械结构,也不存在机械硬盘的寻道问题。

文件的操作方式

  • 顺序读写:文件指针只能从头移动到尾。
  • 随机读写:文件指针可以随意移动,根据需要。

MYSQL的日志顺序读写,数据文件随机读写以及linux底层原理

对于redo log,binlog这种日志进行的磁盘顺序读写

在这里插入图片描述

  • 在写redo log日志的时候,其实是不停的在一个日志文件末尾追加日志的,这就是磁盘顺序写。
  • 磁盘顺序写的性能其实是很高的,某种程度上来说,几乎可以跟内存随机读写的性能差不多,尤其是在数据库里其实也用了os cache机制,就是redo log顺序写磁盘之前,先进入os cache,就是操作系统管理的内存缓存里。

对于表空间磁盘文件里的数据页进行的磁盘随机读写

在这里插入图片描述

  • 磁盘随机读的性能是比较差的,所以不可能每次更新数据都进行磁盘随机读,必须是读取一个数据页之后放到buffer pool的缓存里去,下次要更新的时候直接更新到buffer pool里的缓存页。
  • 对于磁盘随机读来说,主要关注的性能指标是IOPS和响应延迟
  • IOPS指标实际上对数据库的crud操作的QPS影响非常大的,因为他在某种程度上几乎决定了你每次能执行多少个SQL语句,底层存储的IOPS越高,你的数据库的并发能力就越高。
  • 一般对于核心业务的数据库的生产环境机器规划,我们都是推荐使用SSD固态硬盘,而不是机械硬盘,因为SSD固态硬盘的随机读写并发能力和响应延迟要比机械硬盘好得多,可以大幅度提升数据库的QPS和性能。

Linux操作系统的存储系统

  • 不管是mysql执行磁盘随机读写,还是磁盘顺序读写,其实在底层的linux层面,原理基本上是一样的。
  • linux系统分为VFS层(Virtual File System),文件系统层,Page Cache缓存层,通用Block层,IO调度层,Block设备驱动层,Block设备层

在这里插入图片描述

  1. 当mysql发起一次数据页的随机读写,或者redo log日志的顺序读写的时候,实际上会把磁盘IO请求交给Linux操作系统的VFS层:这一次根据你对哪个目录中的文件执行的磁盘IO操作,把IO请求交给具体的文件系统。
  2. 接着文件系统会先在Page Cache这个基于内存的缓存里找你要的数据在不在里面,如果有就基于内存缓存执行读写,如果没有就往下一层走。
  3. 请求交给通用的Block层,这一层会把你对文件的IO请求转换为Block IO请求。IO请求转换为Block IO请求之后,会把这个Block IO请求交给IO调度层,
  4. IO调度层默认使用的是CFQ公平调度算法(该算法的特点是按照I/O请求的地址进行排序,而不是按照先来后到的顺序来进行响应),不过一般建议用deadline IO调度算法(任何一个IO操作都不能一直不停的等待,在指定时间范围内,都必须让他去执行。)
  5. 最后IO完成调度之后,就会决定哪个IO请求先执行,哪个IO请求后执行,此时可以执行的IO请求就会交给Block设备驱动层,然后最后经过驱动把IO请求发送给真正的存储硬件,也就是Block设备层
  6. 然后硬件设备完成了IO读写操作之后,最后就把响应经过上面的层级反向依次返回。

数据库服务器使用的RAID存储架构

关于 RAID 鸟哥有详细的阐述:14.2 软体磁碟阵列(Software RAID) — 鸟哥的Linux 私房菜

  • mysql数据库就是一个软件,底层就是磁盘来存储数据,基于内存来提升数据读写性能。

  • mysql运行过程中,他需要使用CPU,内存,磁盘和网卡这些硬件,但是不能直接使用,都是通过调用操作系统提供的接口,依托于操作系统来使用和运行的,然后linux操作系统负责操作底层的硬件。
    在这里插入图片描述

  • 一般来说,很多数据库部署在机器上的时候,存储都是搭建的RAID存储架构;在存储层面往往回在机器上搞多块磁盘,然后引入RAID这个技术,RAID:管理机器里的多块磁盘的一种磁盘阵列技术。
    在这里插入图片描述

  • 当我们往磁盘里写数据的时候,通过RAID技术可以通过我们选择一块磁盘写入,在读取数据的时候,我们也知道从哪块磁盘去读取。RAID还可以实现数据冗余机制。

  • RAID磁盘冗余阵列技术里,可以把你写入的同样一份数据,在两块磁盘上都写入,这样让两块磁盘上的数据一样,作为冗余备份,然后当你一块磁盘坏掉的时候,可以从另一块磁盘读取冗余数据出来,这一切都是RAID技术自动帮你管理的。
    在这里插入图片描述

RAID存储架构的电池充放电原理

  • 服务器使用多块磁盘组成的RAID阵列的时候,一般会有一个RAID卡,这个RAID卡是带有一个缓存的,这个缓存不是直接用我们的服务器的主内存的那种模式,他是一种类似于内存的SDRAM

  • 我们可以吧RAID的缓存模式设置为write back,这样的话,所有写入到磁盘阵列的数据,先会缓存在RAID卡的缓存中,后续慢慢再写入磁盘阵列里去,这种机制可以大幅度提升我们的数据库磁盘的写性能。
    在这里插入图片描述

  • 如果突然断电了,或者服务器自己故障了,那么这个RAID卡的缓存里的数据会突然丢失,为了解决这个问题,RAID卡一般都配置有自己独立的锂电池或者电容,如果服务器突然掉电了,RAID卡自己是基于锂电池来供电运行的,然后他赶紧把缓存里的数据写入到阵列中的磁盘上去。
    在这里插入图片描述

  • 锂电池是存在性能衰减问题的,所以一般来说锂电池都是要配置定时充放电的,也就是说每隔30~90天,就会自动对锂电池充放电一次。锂电池在充放电过程中,RAID的缓存级别会从write back变成write through,我们通过RAID写数据的时候,IO就直接写磁盘了,如果写内存的话,性能是0.1ms这个级别,如果是直接写磁盘,性能就退化到毫秒级了。

  • 这个时候一旦RAID锂电池子自动充放电,往往会导致你的数据库服务器的RAID存储定期的性能出现几十倍的抖动,间接导致你的数据库每隔一段时间就会出现性能几十倍的抖动。

RAID锂电池充放电导致MYSQL数据库性能抖动的优化

  • RAID 0:没有冗余备份,磁盘坏了就会丢失一部分数据
  • RAID 1:两块磁盘为镜像关系,你写的所有数据,在两块磁盘上面都有,形成了数据冗余。一块磁盘坏了,另一块磁盘上面还有数据;一块磁盘如果压力很大,可以让读请求路由到另外一块磁盘上去,分担压力。
  • RAID 10:RAID 0 + RAID 1
    在这里插入图片描述
  • 对于RAID 10架构,它必然内部是有一个锂电池,然后这个锂电池默认一段时间进行一次充放电,所以每次充放电的时候,导致RAID写入时不经过缓存,性能会急剧下降,所以我们发现线上数据库每隔一段时间会有一次剧烈的性能抖动,数据库性能下降了10倍。
  • 可以用linux命令查看RAID硬件设备的日志。

解决RAID锂电池充放电导致的存储性能抖动的解决方案

(1)、给RAID卡把锂电池换成电容,佃农是不用频繁充放电,不会导致充放电的性能抖动。单身很容易老化,而且更换困难,一般不用这个

(2)、关闭RAID自动充放电;写一个脚本,脚本每隔一段时间自动在晚上凌晨的业务低峰时期,脚本手动触发充放电,这样可以避免业务高峰期的时候RAID自动充放电引起性能抖动。

(3)、充放电时不要关闭write back,可以和第二个策略配合起来使用。