0

mysql-磁盘上存储结构

2024.09.11 | cuithink | 698次围观

Innodb存储引擎的逻辑存储结构是将所有的数据都逻辑的放在了一个空间中,这个空间中的文件就是实际存在的物理文件(ibd文件)。默认情况下,一个表占用一个表空间,表空间可以看做是Innodb存储引擎逻辑结构的最高层,所有的数据都放在表空间中。

表空间分为系统表空间,临时表空间,通用表空间,undo表空间和独立表空间。

系统表空间

系统表空间可以对应文件系统上一个或多个实际的文件,默认情况下, InnoDB 会在数据目录下创建一个名为ibdata1,大小为 12M 的文件,这个文件就是对应的系统表空间在文件系统上的表示。这个文件是可以自扩展的,当不够用的时候它会自己增加文件大小。需要注意的一点是,在一个 MySQL 服务器中,系统表空间只有一份。

可以通过innodb_data_file_path变量设置

独立表空间

在 MySQL5.6.6 以及之后的版本中, InnoDB 并不会默认的把各个表的数据存储到系统表空间中,而是为每一个表建立一个独立表空间,也就是说我们创建了多少个表,就有多少个独立表空间。使用独立表空间来存储表数据的话,会在该表所属数据库对应的子目录下创建一个表示该独立表空间的文件,文件名和表名相同,只不过添加了一个.ibd 的扩展名而已。

可以通过变量innodb_file_per_table变量设置

通用表空间

通用表空间是使用create tablespace语法创建的共享表空间,主要有以下功能:

1、跟系统表空间类似,通用表空间是能够存储多个表的数据的共享表空间

2、与独立表空间相比,通用表空间具有潜在的内存优势:通用表空间多个表共享一个表空间,所以消耗更少的内存用于表空间元数据,独立表空间需要更多的内存用于表空间元数据

3、数据文件可以放置在与mysql目录相关或独立的目录中

4、通用表空间支持所有的行格式以及相关的特性

5、create table语句可以使用tablespace选项在通用表空间,独立表空间,或者系统表空间创建表

6、create table语句可以使用tablespace选项在通用表空间,独立表空间,或者系统表空间移动表

Undo 表空间

在初始化mysql实例的时候,会创建两个默认的undo表空间,用于事务异常时进行数据回滚,默认的undo表空间文件名称是undo_001和undo_002。如果默认的表空间不足以支撑需求,那么可以增加、删除和移动undo表空间

临时表空间

临时表空间分为会话临时表空间和全局临时表空间

会话临时表空间

会话临时表空间用于存储用户创建的临时表或由优化器创建的内部临时表。

当一个会话首次请求创建磁盘上的临时表时,服务器会从临时表空间池中分配临时表空间给会话,分配给会话的临时表空间将用于会话创建的所有磁盘上的临时表。

当会话断开连接时,其临时表空间被截断并释放会池中。

一个会话最多分配两个临时表空间,一个用于用户创建的临时表,另一个用于优化器创建的内部临时表

服务器启动时将创建一个包含10个临时表空间的池,池的大小永远不会缩小,表空间会根据需要自动添加到池中,当服务器正常关闭或者初始化终止时,临时表空间将被移除。

全局临时表空间

全局临时表空间用于存储对用户创建的临时表所做更改的回滚段。

全局临时表空间在正常关闭或初始化终止时被移除,并在服务器启动时重新创建

全局临时表空间在创建时接受一个动态生成的空间ID

如果无法创建全局临时表空间,服务器将拒绝启动,如果服务器意外停止,全局临时表空间不会被移除

重新启动mysql服务器会自动移除并重新创建全局临时表空间,回收全局临时表空间数据文件占用的磁盘空间

Doublewrite Buffer Files

我们常见的服务器一般是linux系统,linux文件系统页的默认大小是4KB,而mysql的页大小默认是16KB,mysql程序一般是运行在linux操作系统上的,所以当跟操作系统进行交互的时候,mysql中一页数据刷到磁盘,就要写4个文件系统里的页,如下图所示:

注意,这个刷页的操作并不是原子操作,比如我们操作第二个页的时候,服务器断电了,那么就会有问题,出现页数据损坏的情况,此时是无法通过redolog来进行修复的,因为redolog中记录的是对页的物理操作,而不是页面的全量记录,当发生部分页写入的时候,出现的是未修改的数据,此时redolog是无能为力的。

Doublewrite Buffer的出现就是为了解决上面的这种,给Innodb提供了数据页的可靠性,虽然名字带了Buffer,但是实际上是由内存+磁盘的结构:

内存结构:Doublewrite Buffer内存结构由128个页组成,大小是2MB

磁盘结构:Doublewrite Buffer磁盘结构由128个页(2个区组成,每个区1MB),大小是2MB

Doublewrite Buffer的原理是,再把数据页写到数据文件之前,InnoDB先把它们写到一个叫「doublewrite buffer(双写缓冲区)」的共享表空间内,在写doublewrite buffer完成后,InnoDB才会把页写到数据文件适当的位置。

如果在写页的过程中发生意外崩溃,InnoDB会在doublewrite buffer中找到完好的page副本用于恢复。

DoubleWrite Buffer原理图如下所示:

1、页数据先通过memcpy函数拷贝到内存中的DoubleWrite Buffer中

2、DoubleWrite Buffer的内存里的数据页会fsync刷到DoubleWrite Buffer的磁盘上,分两次写入,每次写1MB

3、 如果操作系统在将页写入磁盘的过程中发生了崩溃,在恢复过程中,InnoDB存储引擎可以从共享表空间中的Double write中找到该页的一个副本,将其复制到表空间文件,再应用redo日志

那么如何利用Doublewrite Buffer来进行数据恢复呢?主要由三种情况:1、脏数据写磁盘成功,这种情况是最常见的,这种情况不需要Doublewrite Buffer,2、表空间写失败,如果写表空间失败,那么这些数据不会写到数据文件中,数据库认为这次刷盘没有发生过,mysql此时会载入原始数据,不做任何修改,3、脏数据刷数据文件失败,此时写表空间成功了,但是写数据文件失败,在恢复的时候,mysql会比较整个页面,如果不对的话,直接从Doublewrite Buffer中找到该页的副本,并将其复制到数据文件中,然后再进行redolog的操作。

Redo Log

redolog记录数据库的变更,数据库崩溃后,会从redolog中获取事务信息,进行系统恢复,在5.x版本中,redolog在磁盘上表现为ib_logfile0和ib_logfile1.在mysql8版本之后以#ib_redo_N来记录


粤ICP备16076548号
发表评论