MySQL专题(四):行溢出是什么东西?表空间以及划分多个数据页的数据区的概念 数据库服务器使用RAID存储架构 深入理解redo log redo log block redo log buffer

前言:

本期内容会比较多,可能部分衔接不是非常的完整,如果有错误的地方,欢迎留言指出

1.行溢出是什么东西?存放磁盘的多行数据的数据页到底长什么样子?
2.表空间以及划分多个数据页的数据区的概念
3.MySQL数据库的日志顺序读写以及数据文件随机读写原理
4.Linux操作系统的存储系统软件层原理刨析以及IO调度优化原理
5.数据库服务器使用的RAID存储架构
6.MySQL数据库服务器上的RAID存储架构的电池充放电原理【以及使用了RAID的SDRAM缓存机制充放电的性能抖动问题】
7.回顾redo日志对于事务提交之后,数据绝对不会丢失的意义
8.写入redo log日志文件,不也是写入磁盘么,差距在哪里?
9.buffer pool执行完增删改之后,写入日志的redo log长什么样?
10.redo log改进版,MySQL内的另外一个数据结构《redo log block》
11.redo log buffer揭秘以及redo log buffer中的缓冲日志,到底什么时候可以写入磁盘?
12.undo log回滚日志底层原理

1.行溢出是什么东西?存放磁盘的多行数据的数据页到底是长啥样的?

首先存放磁盘多行数据的数据页之前在第二章的时候就已经上过图了,这里主要深入一下行溢出是怎么引出的,例如一个varchar(65535),或者是一个text字段,那么可能这个字段的数据可能不止16KB,此时可能会就发生行溢出,可能一个字段多个数据页存储,此时的这个数据页中存放部分字段的数据,还会存放一个大约20字节的指针,指向其他数据页,也就是相当于图中示例:【如图】

数据页行溢出

2.表空间以及划分多个数据页的数据区的概念【可能有点点绕】

2.1:首先回顾一下数据页在磁盘中长啥样子,便于更快速的理解表空间,数据页和数据区,包括数据组。

一个数据页拆分成了很多个部分:“文件头,数据页头,最小记录和最大记录,多个数据行,空闲空间,数据页目录,文件尾部”;【如图】
MySQL的数据页

2.2:什么是表空间?

在MySQL创建的表,实际上都会有一个表空间的概念,在磁盘上都会对应"标明.ibd"这样一个磁盘数据文件,在物理层面将,表空间就是对应一些磁盘上的数据文件,系统表空间可能对应的是多个磁盘文件,自己创建的表空间可能对应了一个"表名.ibd"文件,如图:
aaa.ibd文件
在表空间的磁盘文件中【.ibd】,会有很多很多的数据页,一个数据页16kb,所以一个表空间的磁盘文件中其实有很多的数据页,而表空间的其他各组数据区,每一组数据区的第一个数据区的头两个数据页,都是存放特殊信息,例如XDES数据页就是用来存放这一组数据区的一些相关属性,其实大白话就是描述这组数据区的东西。

2.3:那么什么又是数据区呢?extent

一个表空间中包含的数据页很多,不便于管理,所以在表空间中引入了一个数据区的概念:extent,这里要解释一下,不然越来越晕,一个数据区管理了多个数据页。就这么理解。每个数据区的第一个数据区的前3个数据页存放是一些特殊的信息,然后表空间的第一组数据区和第一个数据区的头三个数据页,都是存放特殊信息的,表空间的其他组数据区的第一个数据区的头两个数据页,也是存放特殊信息的。【有点绕,读多几遍就理解了】

2.4:什么又是数据组呢?

一个数据区对应连续的64个数据页,每个数据页是16KB,所以一个数据区是1mb,256个数据区划分为一组,也就是说256mb就是一组,一个数据组 = 256个数据区。
在磁盘上的各个表空间的数据文件中是通过数据区的概念,划分了很多很多的数据页,所以,当需要执行CRUD操作的时候,就是从磁盘上的表空间的数据文件中去加载一些数据页到buffer pool的的缓存页去使用;

最后进行小结一下:

平时创建的这些数据表都是有对应的表空间的,每个表空间就是对应了磁盘上的数据文件【表名.ibd文件】,在表空间中有很多组数据区,一组数据区是256个数据区,每个数据区包含了64个数据页,1个数据页16kb,64个就是1mb,表空间的第一组数据区和第一个数据区的头三个数据页,都是存放特殊信息的,表空间的其他组数据区的第一个数据区的头两个数据页,也是存放特殊信息的,所以在磁盘上的各个表空间的数据文件中是通过数据区的概念,划分了很多很多的数据页,所以,当需要执行CRUD操作的时候,就是从磁盘上的表空间的数据文件中去加载一些数据页到buffer pool的缓存页去使用。
【表空间图】
表空间图

3.MySQL数据库的日志顺序读写以及数据文件随机读写原理

前言: MySQL在实际工作时候的两种数据读写机制。一种是顺序读写,一种是随机读写(再次声明,这个随机并不是传统意义上的随机)

3.1:对表空间的磁盘文件中的数据进行的磁盘随机读写《某个数据页在磁盘文件中的随机一个位置》

MySQL在工作的时候,尤其实在执行增删改操作的时候,肯定是先从表空间的磁盘文件中读取数据页出来,这个过程就是典型的磁盘随机读写操作,对于磁盘随机读来说,主要关注的性能指标是IOPS和响应延迟,《IOPS:底层存储系统每秒可以执行多少次磁盘读写操作,第二个就是读写操作的响应延迟,也是对数据库性能有很大的影响,每个sql请求响应越快,性能越高》SSD固态硬盘要比机械硬盘的随机读写并发能力和响应延迟的性能要高很多,这个涉及到硬件设备了,不再进行深入分析和理解了。

3.2:redo log、binlog日志进行磁盘顺序读写

当在buffer pool的缓存页中更新了数据之后,必须要写一条redo log日志,这个redo log日志,实际上走的是磁盘顺序写,磁盘顺序写的性能是极高的,几乎可以和内存随机读写性能持平,并且在数据库中写入redo log日志还引入了os cache缓存,先写入os cache缓存,再写入磁盘,这个效率是控制在毫秒甚至微秒级别的,效率极高。

磁盘随机读写和顺序读写草图如下:
磁盘随机读写和顺序读写

4.Linux操作系统的存储系统软件层原理刨析以及IO调度优化原理

大家都晓得,实际上我们的MySQL服务最终都是跑再Linux上面的,Linux的存储系统分为VFS层,文件系统层,Page Cache缓存层,通用的Block层,IO调度层,Block设备驱动层,Block设备层。实际上当MySQL发起一次数据页的随机读写,或者是一次redo log日志文件的顺序读写的时候,实际上会把磁盘IO请求交给Liunx操作系统的VFS层。这里不深入,只是了解,就直接上图了,交给VFS后大概的执行过程就是:举例简单过一下:VFS这一层的作用,就是根据这个sql是对哪个目录中的文件执行的磁盘IO操作,将IO请求交给具体的文件系统,例如在Linux中,有的目录例如/XX1/XX2中的文件是由NFS文件系统管理的,有的目录例如:/XX3/xx4/中的文件其实是有EXT3文件系统关系的,这个时候VFS就需要根据你是对应哪个目录下的文件发起的读写IO请求,将请求转发给对应的文件系统。

在这里插入图片描述

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

前言问题:RAID存储架构,看起来有点高大上哇,实际上可以理解为一个管理MySQL磁盘的技术,场景:假设服务器中的磁盘就只有1块,万一磁盘容量不足,就需要再搞几块磁盘,机器中的多块磁盘不好管理,数据如何在多块磁盘上存放数据呢?

解决以上的问题:引入RAID技术,管理机器中的多块磁盘的一种磁盘阵列技术,这样就可以在一台服务器加多块磁盘,扩大磁盘空间【当往磁盘写数据的时候,通过RAID技术可以帮助选择一块磁盘写入,在读取数据的时候,也知道从哪块磁盘读取数据】,RAID还支持冗余备份技术,RAID磁盘冗余阵列技术中,是可以将写入同样一份数据,在两块磁盘上都写入,做数据冗余备份,当其中一块磁盘损坏,也是可以从另外一个磁盘读取,这一些都是RAID技术自动管理的,不要自己打理的。
在这里插入图片描述
图中有个缓存(SDRAM),这个可以相信成是一个充电宝,这样接下来就好理解一些了,

6.MySQL数据库服务器上的RAID存储架构的电池充放电原理【以及使用了RAID的SDRAM缓存机制充放电的性能抖动问题】

6.1:RAID卡是个什么东西?

大白话的方式理解就是一个充电宝,组成RAID阵列之后一般情况会有一个RAID卡,这个RAID卡是带有缓存的,是跟内存类似的SDRAM(基于内存存储),这里涉及到一个Linux内核调优小点子:将RAID的缓存模式设置为write back,这种写入磁盘阵列的机制,会先缓存到RAID卡的缓存中,后续慢慢刷入磁盘阵列中,提升数据库磁盘写入性能;

6.2:RAID卡的锂电池机制【充电宝机制】
服务器故障异常关闭,或者是突然被挖到电缆了,断电了,还没有刷到硬盘的缓存数据,不久丢失了?

RAID卡一般都配置自己独立的锂电池或者是电容,断电无法接通电源,RAID卡自己是基于锂电池来供电运行的,会加快速度将缓存的数据写入到阵列的磁盘中持久化。

6.3:RAID卡的锂电磁充放电自动切换级别

在RAID锂电池充放电的过程,RAID的缓存级别会从write back变成write through,也就是直接调整为写磁盘,不走RAID缓存了。此时有个缺点:一旦RAID锂电池充放电会导致RAID存储定期的性能出现几十倍的MySQL数据库的性能抖动,之前都是基于缓存的,现在直接要写盘了,几十倍的性能抖动也是正常的。

6.4:RAID锂电池充放电导致的MySQL数据库性能抖动的优化【三种解决方案】

最常用的就是:手动充放电,就是关闭RAID自动充放电,如何写一个脚本,脚本每隔一段时间自动再晚上凌晨或者是业务低峰的时期,脚本手动触发充放电,这样可以避免业务高峰期的时候RAID自动充放电引起的性能抖动(充放电的时候RAID自动充放电引起的新能抖动),充放电的时候不要关闭write back,也就是设置一下,锂电池电池充放电的时候,不要将缓存级别从write back修改为write through,和脚本配合使用。

7.回顾redo日志对于事务提交之后,数据绝对不会丢失的意义

先回顾这张写入redo log日志流程图
在这里插入图片描述

8:写入redo log日志文件,不也是写入磁盘么,差距在哪里?

此时就出现了一个问题,为什么buffer pool更新完缓存页不立即刷盘,而是写入redo log日志文件,同样都是刷盘,何必多此一举呢?

8.1:实际上,如果将修改过的缓存页都刷入磁盘,一个缓存页就是16KB,数据量比较大的时候,刷入磁盘比较耗时,而且可能就修改了一个字段,或者几个字节的数据。

8.2:并且缓存页刷入磁盘是随机写磁盘的,性能很差,因为一个缓存页对应的位置可能在磁盘文件中的一个随机位置,例如偏移量33的磁盘位置;

8.3:但是如果是写redo log,第一个好处就是一定是很小的,例如一行redo log可能就几十个字节,这个日志就只是包含了:表空间号,数据页号,磁盘文件偏移量,更新的值,而且还是顺序写的,还有os cache机制,写入磁盘飞快!

9:buffer pool执行完增删改之后,写入日志的redo log长什么样?

redo log日志记录格式:表空间号+偏移量+修改几个字节的值+具体的值;就长大概图中这个样子,日志类型(就是类型MLOG_1BYTE之类的),表空间号ID,数据页号,数据页中的偏移量,具体修改的数据
在这里插入图片描述

为什么突然又回顾了一边redo log?事出有因

10.redo log改进版,MySQL内的另外一个数据结构《redo log block》

10.1:redo log也不是单行单行写入日志文件的,是用一个redo log block来存放多个单行日志的。

一个redo log block是512个字节,redo log block的512个字节,分为3个部分,一个是12字节的header块头,一个是496字节的body块体,一个是4个字节的trailer块尾,12个字节的header头又分为了4个部分:1.包括4个字节的block no,就是块唯一编号;2.2个字节的data length,就是block中写入了多少个字节数据;3、2个字节的fitst record group。这是说每个事务都会有多个redo log,那么这个block的第一组redo log的偏移量就是这两个字节存储的。4.4个字节的checkponit on,redo log图解大概就是图中这个样子:如图
在这里插入图片描述
对于redo log而言,确实是不停的追加redo log磁盘文件中去的,但是其实每个redo log都是写入到文件中的一个redo log block中的,一个block最多放496字节自己的redo log日志。

10.2:一个个redo log block在日志文件中是如何存在的,一条条redo log又是如何写入日志文件的redo log block中去的?

redo log日志文件,平时往里面写数据,你大致可能认为是从第一行开始,从左往右写,可能会有很多行,举例:假设要写一个redo log了,首先是现在内存中将这个redo log给弄到一个redo log block数据结构中,等待内存中的一个redo log block的512字节都写满了,再一次性将这个redo log block写入disk磁盘文件。

11.redo log buffer揭秘以及redo log buffer中的缓冲日志,到底什么时候可以写入磁盘?

11.1:redo log到底是如何通过内存缓冲之后,再进入redo log磁盘文件的《redo log buffer》

redo log buffer其实就是在MySQL启动的时候就会跟操作系统申请一块连续内存空间,类似于buffer pool,buffer pool是申请之后划分了N多个空的缓存页和一些链表结构,便于从磁盘上的数据页加载到内存中,而redo log buffer也是类似的,申请出来一批连续的内存,这块内存中划分出来多个redo log block。

11.2:如何设置redo log buffer的大小?多少合适?

通过设置MySQL的innodb_log_buffer_size可以指定这个redo log buffer的大小,默认是16MB,其实默认的就够用,因为一个redo log block才512字节,每条redo log日志也才几十个字节,写满了一个redo log block就会继续写下一个redo log block,以此类推,直到所有的redo log block都写满,此时必然会强制刷入磁盘的。

11.3:事务的redo log是如何记录的呢?《注意事项知识点》

一个事务可能会有多个增删改操作,那么就会有多个redo log,这多个redo log就是一组redo log,每次一组redo log都是先暂存,然后都执行完后再将一组redo log写入到redo log buffer的block中去的《如果一组redo log太大,可能会存放在两个redo log block中》如果一组redo log 组比较小,也可能多个redo log 组在一个redo log block中。

11.4:redo log buffer中的缓冲日志,到底什么时候可以写入磁盘?《4个触发机制》

1.如果写入redo log block的日志已经占据了redo log buffer总容量的一般了,也就是操作了8MB的redo log在缓冲中,此时就会将缓冲中的redo log block输入redo log磁盘文件中。

2.一个事务提交的时候,比如将这个事务的redo log所在的redo log block都刷入到磁盘,这样才能保证修改过的数据绝对的不丢失,随时可以恢复事务做的修改,redo log也有对应的刷盘参数配置。

3.后台线程定时刷新,有一个后台线程每隔1秒就会将redo log buffer中的redo log block刷入到磁盘文件中去。

4.MySQL关闭的时候,所有的redo log block都会刷入到磁盘中去.

在这里插入图片描述
11.5:redo log日志可能会发生的问题:MySQL不停的产生redo log写入日志文件,那么就用一个日志文件写入全部的redo log?

默认的情况下,redo log都会写入一个目录的文件中,这个目录可以通过show variables like 'datadir’进行查看,可以通过innodb_log_group_home_dir参数来设置这个目录,然后redo log日志文件是有多个的,写满了就会写下一个redo log日志文件,通过innodb_log_file_size可以指定每隔redo log文件的大小,默认是48MB,通过innodb_log_files_in_group可以指定日志文件的数量,默认2个。所以默认的情况下,写满第一个redo log文件,写第二个,第二个写满了,覆盖第一个日志文件中原来的redo log,所以默认情况下,mysql保留了最近96MB的redo log,但是够存储上百万条redo log日志了,参数也可以做调整,具体得看实际的业务需求和数据量。

12.一条insert语句的undo log日志长啥样?

一条insert语句的undo log日志长啥样??就长的差不多这个熊样
一条insert语句的undo log日志长啥样?
图文解释:【如图】
在这里插入图片描述

课外小知识:MySQL报Too many connections故障(没有可用的连接)

查看MySQL当前连接数

SHOW VARIABLES LIKE ‘max_connections’;

Too many connections故障解决及背后原理:

1.先聊聊为什么会出现这样的问题?

为什么Linux的最大文件句柄限制为1024的时候,MySQL最大的连接数是214,这个计算结果是MySQL源码内部写死的一个计算公式。Linux默认是会限制每个进程对机器资源的使用,包括可以打开的文件句柄的限制,可以打开的子进程数的限制,网络缓存的限制,最大可以锁定的内存大小限制。
在这里插入图片描述

2.调整Linux最大句柄限制即可解决

2.1:修改Linux的最大文件句柄命令:执行命令:ulimit -HSn 65535
2.2:调整mysql配置文件:修改最大连接数,修改好之后,在MySQL的my.cnf中确保max_connections参数也调整好了,就可以重启服务器,这样的Linux最大文件句柄也生效了,MySQL最大连接数也会生效了

3.ulimit -a查看Linux的相关参数和限制

在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖喱ABC

无需打赏,共同进步学习!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值