天天看点

mysql 技术内幕 pdf_【总结】MySQL技术内幕三:文件

MySQL和InnoDB有如下类型文件:

  • 参数文件
  • 日志文件
  • socket文件
  • pid文件
  • 表结构文件
  • 存储引擎文件

下面一一介绍各类型文件。

3.1、参数文件

参数文件名:my.cnf,我们通常更习惯于称之为“配置文件”,Linux默认在/etc/目录下。

MySQL中的参数可以分为两类: 动态(dynamic)参数和 静态(static)参数。

动态参数可以在MySQL实例运行中进行更改。SET命令就是用来更改动态参数的,语法如下:

mysql 技术内幕 pdf_【总结】MySQL技术内幕三:文件

其中global和session关键字,表明该参数的修改是基于当前会话,还是整个实例的生命周期。SET修改的参数不会写入参数文件,实例重启后会失效。如果需要重启生效,必须修改参数文件。

静态参数说明在整个实例生命周期内都不得进行更改。如果通过SET命令修改静态参数,会报read only的错误。如果需要更改的话,必须修改参数文件,并重启才能生效。

3.2、日志文件

日志文件记录了MySQL运行中的情况,常见的日志文件有:

□ 错误日志(error log):记录错误和警告信息,常用于故障分析。

□ 二进制日志(binary log):较为复杂,下文详细介绍。

□ 慢查询日志(slow query log):记录运行时间超过指定阀值的所有SQL语句,用于定位可能存在问题的SQL语句,从而进行SQL语句层面的优化。mysqldumpslow命令可用于分析该日志。

□ 查询日志(log):查询日志记录了所有对MySQL数据库请求的信息,无论这些请求是否得到了正确的执行。因查询日志写磁盘频繁,对性能有影响,因此生产环境中最好关闭,MySQL默认是关闭的。

这些日志文件有助于我们对数据库的运行状态进行诊断,如故障分析、性能优化等。

二进制日志

二进制日志(binary log),简称binlog,记录了对MySQL数据库执行更改的所有操作,但是不包括SELECT和SHOW这类操作。简单的理解就是,binlog记录了所有写操作。

通过如下命令可以查看binlog:

SHOW 
           

二进制日志主要有以下几种作用:

□ 恢复(recovery):某些数据的恢复需要二进制日志,例如,在一个数据库全备文件恢复后,用户可以通过二进制日志进行point-in-time的恢复。

□ 复制(replication):其原理与恢复类似,通过复制和执行二进制日志使一台远程的MySQL数据库(一般称为slave或standby)与一台MySQL数据库(一般称为master或primary)进行实时同步。

□ 审计(audit):用户可以通过二进制日志中的信息来进行审计,判断是否有对数据库进行注入的攻击。

二进制日志文件在默认没有启动,需要手动启动相应配置项。开启这个选项的对性能有所影响,但是影响十分有限。根据MySQL官方的测试表明,开启二进制日志会使性能下降1%。

二进制日志的配置参数有:

□ max_binlog_size:单个二进制日志文件的最大值,默认1G。如果超过该值,则产生新的二进制日志文件,后缀名+1,并记录到.index文件。

□ binlog_cache_size:二进制日志缓冲区大小,默认32K,是基于会话的。当使用事务时,所有未提交的二进制日志会被记录到这个缓冲区,等该事务提交时,直接将缓冲中的二进制日志写入二进制日志文件。该值设置过大会浪费内存,太小会导致缓冲中的日志写入一个临时文件中,影响性能。可通过SHOW GLOBAL STATUS命令查看binlog_cache_use、binlog_cache_disk_use的状态,来判断当前binlog_cache_size的设置是否合适。

□ sync_binlog:每写缓冲多少次就同步到磁盘。0表示由操作系统控制刷新,性能最好,但可能会丢数据。如果设为1,IO操作频繁,对性能有很大损耗。设为1时,还有另外一个问题。当使用InnoDB时,在一个事务发出COMMIT动作之前,将二进制日志立即写入磁盘。如果已写二进制日志,但是未提交事务,并且此时宕机了,那么在数据库恢复时,由于事务没有COMMIT,会被回滚掉。但是二进制日志不能被回滚,从而导致数据不一致。这个问题可以通过将参数innodb_support_xa设为1来解决。

□ binlog-do-db和binlog-ignore-db:分别表示需要写入或忽略写入哪些库的日志。默认为空,表示需要同步所有库的日志到二进制日志。

□ log-slave-update:如果数据库是slave角色,则它不会将从master取得并执行的二进制日志写入自己的二进制日志文件中去。如果需要写入,要设置该值。

□ binlog_format:参数十分重要,它影响了记录二进制日志的格式。详见下文。

binlog_format配置

binlog_format是动态参数,可基于会话设置,也可全局设置。该参数可设的值有STATEMENT、ROW和MIXED。

(1)STATEMENT格式和之前的MySQL版本一样,二进制日志文件记录的是日志的逻辑SQL语句。

(2)在ROW格式下,不再是记录简单的SQL语句,而是记录表的行更改情况。如果设置了binlog_format为ROW,可以将InnoDB的事务隔离基本设为READCOMMITTED,以获得更好的并发性。

(3)在MIXED格式下,MySQL默认采用STATEMENT格式进行二进制日志文件的记录,但是在一些情况下会使用ROW格式,可能的情况有:

a)表的存储引擎为NDB,这时对表的DML操作都会以ROW格式记录。

b)使用了UUID()、USER()、CURRENT_USER()、FOUND_ROWS()、ROW_COUNT()等不确定函数。

c)使用了INSERT DELAY语句。

d)使用了用户定义函数(UDF)。

e)使用了临时表(temporary table)。

存储引擎对二进制日志格式的支持情况:

mysql 技术内幕 pdf_【总结】MySQL技术内幕三:文件

通常ROW格式可以为数据库的恢复和复制带来更好的可靠性。但也会带来二进制文件大小的增加,有些语句下的ROW格式可能需要更大的容量。比如一条会修改多条记录的UPDATE操作。

在mysql中执行 SHOW BINARY LOGS 命令,即可查看二进制日志文件的列表。

mysqlbinlog 命令,可视化展示出二进制日志中的内容。也可以将内容读取出来,供其他MySQL实用程序使用。

3.3 套接字文件

在UNIX系统下本地连接MySQL可以采用UNIX域套接字方式,这种方式需要一个套接字(socket)文件。套接字文件可由参数socket控制,可通过 SHOW VARIABLES LIKE 'socket' 查看文件路径。默认位于数据库目录下,名为mysql.sock。

3.4 pid文件

当MySQL实例启动时,会将自己的进程ID写入一个文件中——该文件即为pid文件。该文件可由参数pid_file控制,可通过 SHOW VARIABLES LIKE 'pid_file' 查看文件路径,默认位于数据库目录下,文件名为 主机名.pid。

3.5 表结构定义文件

因为MySQL插件式存储引擎的体系结构的关系,MySQL数据的存储是根据表进行的,每个表都会有与之对应的文件。但不论表采用何种存储引擎,MySQL都有一个以frm为后缀名的文件,这个文件记录了该表的表结构定义。

详细了解frm文件格式可查看官方文档:https://dev.mysql.com/doc/internals/en/frm-file-format.html

3.6 InnoDB存储引擎文件

前面介绍的文件都是MySQL的文件,和存储引擎无关。除了这些文件外,每个表存储引擎还有其自己独有的文件。这里具体介绍与InnoDB存储引擎密切相关的文件,包括重做日志文件、表空间文件。

3.6.1 表空间文件

InnoDB采用将存储的数据按表空间(tablespace)进行存放的设计。在默认配置下会有一个初始大小为12MB,名为ibdata1的文件。该文件就是默认的表空间文件(tablespace file),用户可以通过参数innodb_data_file_path配置多个文件组成表空间(注意另外需要配置innodb_data_home_dir=指定home目录,配置为空就根目录,否则会报找不到文件目录的错误),例如:

mysql 技术内幕 pdf_【总结】MySQL技术内幕三:文件
mysql 技术内幕 pdf_【总结】MySQL技术内幕三:文件

若这两个文件位于不同的磁盘上,磁盘的负载可能被平均,因此可以提高数据库的整体性能。autoextend表示该文件可以自动增长。

如果设置参数innodb_file_per_table=ON(默认),会产生单独的.ibd独立表空间文件。这些单独的表空间文件仅存储该表的数据、索引和插入缓冲BITMAP等信息,其余信息还是存放在默认的表空间中。

InnoDB表存储引擎文件:

mysql 技术内幕 pdf_【总结】MySQL技术内幕三:文件

3.6.2 重做日志文件

在默认情况下,在InnoDB存储引擎的数据目录下会有两个名为ib_logfile0和ib_logfile1的文件。在MySQL官方手册中将其称为InnoDB存储引擎的日志文件,不过更准确的定义应该是重做日志文件(redo log file)。它们记录了对于InnoDB存储引擎的事务日志。

当数据库出现故障(如主机断电等),InnoDB会使用重做日志恢复到故障前的状态,以此来保证数据的完整性。

每个InnoDB存储引擎至少有1个重做日志文件组(group),每个文件组下至少有2个重做日志文件,如默认的ib_logfile0和ib_logfile1。为了得到更高的可靠性,用户可以设置多个的镜像日志组(mirrored log groups),将不同的文件组放在不同的磁盘上,以此提高重做日志的高可用性。在日志组中每个重做日志文件的大小一致,并以循环写入的方式运行。先写重做日志文件1,当写满这个文件时,会切换至重做日志文件2,再当重做日志文件2也被写满时,会再切换到重做日志文件1中。

下列参数会影响到重做日志:

□ innodb_log_file_size:指定每个重做日志文件的大小。大小需要适中,如果设置得很大,在恢复时可能需要很长的时间;也不能设置得太小了,否则可能导致一个事务的日志需要多次切换重做日志文件,太小还会导致频繁地发生async checkpoint,导致性能的抖动。

□ innodb_log_files_in_group:指定了日志文件组中重做日志文件的数量,默认为2。

□ innodb_mirrored_log_groups:指定了日志镜像文件组的数量,默认为1,表示只有一个日志文件组,没有镜像。若磁盘本身已经做了高可用的方案,如磁盘阵列,那么可以不开启重做日志镜像的功能。

□ innodb_log_group_home_dir:指定了日志文件组所在路径,默认为./,表示在MySQL数据库的数据目录下。

二进制日志与重做日志的区别:

1、二进制日志会记录所有与MySQL数据库有关的日志记录,包括InnoDB、MyISAM、Heap等其他存储引擎的日志。而InnoDB存储引擎的重做日志只记录有关该存储引擎本身的事务日志。

2、记录的内容不同,无论用户将二进制日志文件记录的格式设为STATEMENT还是ROW,又或者是MIXED,其记录的都是关于一个事务的具体操作内容,即该日志是逻辑日志。而InnoDB存储引擎的重做日志文件记录的是关于每个页(Page)的更改的物理情况。

3、写入的时间也不同,二进制日志文件仅在事务提交前进行提交,即只写磁盘一次,不论这时该事务多大。而在事务进行的过程中,却不断有重做日志条目(redo entry)被写入到重做日志文件中。

重做日志有几十种类型,它们有着基本的格式,重做日志条目的结构如下:

mysql 技术内幕 pdf_【总结】MySQL技术内幕三:文件

□ redo_log_type:占用1字节,表示重做日志的类型

□ space:表示表空间的ID,但采用压缩的方式,因此占用的空间可能小于4字节

□ page_no:表示页的偏移量,同样采用压缩的方式

□ redo_log_body:表示每个重做日志的数据部分,恢复时需要调用相应的函数进行解析

重做日志文件不是直接写文件,而是先写入一个重做日志缓冲中,然后按照一定的条件顺序地写入日志文件。其写入过程如下图:

mysql 技术内幕 pdf_【总结】MySQL技术内幕三:文件

从重做日志缓冲每次按一个扇区大小写入磁盘,因此可以保证写入必定成功,写入过程也不需要有doublewrite。

重做日志缓冲写入磁盘上的条件:

  • 主线程中每秒会将重做日志缓冲写入磁盘的重做日志文件中,不论事务是否已经提交。
  • 由参数innodb_flush_log_at_trx_commit控制是否触发写磁盘,表示在提交(commit)操作时,处理重做日志的方式。

参数innodb_flush_log_at_trx_commit的配置如下:

0:代表当提交事务时,并不将事务的重做日志写入磁盘上的日志文件,而是等待主线程每秒的刷新。

1:表示在执行commit时将重做日志缓冲同步写到磁盘,即伴有fsync的调用。为了保证事务的ACID中的持久性,必须设置为1。

2:表示将重做日志异步写到磁盘,即写到文件系统的缓存中。因此不能完全保证在执行commit时肯定会写入重做日志文件,只是有这个动作发生。

参考

  • 《MySQL技术内幕:InnoDB存储引擎(第2版)》
  • 源码:MariaDB 10.4.12