目录

  • 十、MySQL日志
  • 1、错误日志
  • 2、二进制日志
  • 2.1 介绍
  • 2.2 格式
  • 2.3 查看
  • 2.4 删除
  • 3、查询日志
  • 1.4 慢查询日志
  • 1.5 事务日志 redo log
  • 1.刷盘时机
  • 2.日志文件组
  • 3.小结
  • 1.6 回滚日志 undo log
  • 1.7 总结


十、MySQL日志

在MySQL中,有4种不同的日志:

  • 错误日志
  • 二进制日志(BINLOG日志)
  • 查询日志
  • 慢查询日志

1、错误日志

错误日志是 MySQL 中最重要的日志之一,它记录了当 mysqld 启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。

该日志是默认开启的,默认存放目录 /var/log/,默认的日志文件名为 mysqld.log 。

查看日志位置:

show variables like '%log_error%';

Mysql收集日志 mysql 日志在哪_数据

2、二进制日志

2.1 介绍

二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但不包括数据查询(SELECT、SHOW)语句。

binlog 是逻辑日志,记录内容是语句的原始逻辑,类似于“给 ID=2 这一行的 c 字段加 1”,属于MySQL Server 层。

不管用什么存储引擎,只要发生了表数据更新,都会产生 binlog 日志。

binlog会记录所有涉及更新数据的逻辑操作,并且是顺序写。

作用

  • 灾难时的数据恢复
  • MySQL的主从复制

以说MySQL数据库的数据备份、主备、主主、主从都离不开binlog,需要依靠binlog来同步数据,保证数据一致性。

Mysql收集日志 mysql 日志在哪_日志_02

在MySQL8版本中,默认二进制日志是开启着的,涉及到的参数如下:

show variables like '%log_bin%';

Mysql收集日志 mysql 日志在哪_MYSQL_03

Mysql收集日志 mysql 日志在哪_日志_04

参数说明

  • log_bin_basename:当前数据库服务器的binlog日志的基础名称(前缀),具体的binlog文
    件名需要再该basename的基础上加上编号(编号从000001开始)。
  • log_bin_index:binlog的索引文件,里面记录了当前服务器关联的binlog文件有哪些。

2.2 格式

MySQL服务器中提供了多种格式来记录二进制日志,具体格式及特点如下:

日志格式

含义

STATEMENT

基于SQL语句的日志记录,记录的是SQL语句,对数据进行修改的SQL都会记录在日志文件中。

ROW

基于行的日志记录,记录的是每一行的数据变更。(默认)

MIXED

混合了STATEMENT和ROW两种格式,默认采用STATEMENT,在某些特殊情况下会自动切换为ROW进行记录。

show variables like '%binlog_format%';

Mysql收集日志 mysql 日志在哪_日志_05

如果我们需要配置二进制日志的格式,只需要在 /etc/my.cnf 中配置 binlog_format 参数即可。

2.3 查看

由于日志是以二进制方式存储的,不能直接读取,需要通过二进制日志查询工具 mysqlbinlog 来查看,具体语法:

mysqlbinlog [ 参数选项 ] logfilename 
mysqlbinlog -d learn 

参数选项: 
    -d 指定数据库名称,只列出指定的数据库相关操作。 
    -o 忽略掉日志中的前n行命令。 
    -v 将行事件(数据变更)重构为SQL语句 
    -vv 将行事件(数据变更)重构为SQL语句,并输出注释信息
    
    
 -- eg:
 mysqlbinlog -d db_name binlog.000001;
 mysqlbinlog -o 100 db_name binlog.000002;

2.4 删除

对于比较繁忙的业务系统,每天生成的binlog数据巨大,如果长时间不清除,将会占用大量磁盘空间。可以通过以下几种方式清理日志:

指令

含义

reset master

删除全部 binlog 日志,删除之后,日志编号,将从 binlog.000001重新开始

purge master logs to ‘binlog.*’

删除 * 编号之前的所有日志

purge master logs before ‘yyyy-mm-dd hh24:mi:ss’

删除日志为 “yyyy-mm-dd hh24:mi:ss” 之前产生的所有日志

也可以在mysql的配置文件中配置二进制日志的过期时间,设置了之后,二进制日志过期会自动删除。

查询过期时间:

show variables like '%binlog_expire_logs_seconds%';

Mysql收集日志 mysql 日志在哪_Mysql收集日志_06

3、查询日志

查询日志中记录了客户端的所有操作语句,而二进制日志不包含查询数据的SQL语句。默认情况下,查询日志是未开启的。

show variables like '%general_log%';

Mysql收集日志 mysql 日志在哪_MySQL_07

如果需要开启查询日志,可以修改MySQL的配置文件 /etc/my.cnf 文件,添加如下内容:

#该选项用来开启查询日志 , 可选值 : 0 或者 1 ; 0 代表关闭, 1 代表开启 
general_log=1 

#设置日志的文件名 , 如果没有指定, 默认的文件名为 host_name.log 
general_log_file=mysql_query.log

开启了查询日志之后,在MySQL的数据存放目录,也就是 /var/lib/mysql/ 目录下就会出现mysql_query.log 文件。之后所有的客户端的增删改查操作都会记录在该日志文件之中,长时间运行后,该日志文件将会非常大。

1.4 慢查询日志

慢查询日志记录了所有执行时间超过参数 long_query_time 设置值并且扫描记录数不小于min_examined_row_limit 的所有的SQL语句的日志,默认未开启。long_query_time 默认为10 秒,最小为 0, 精度可以到微秒。

如果需要开启慢查询日志,需要在MySQL的配置文件 /etc/my.cnf 中配置如下参数:

#慢查询日志 
slow_query_log=1 

#执行时间参数 
long_query_time=2

默认情况下,不会记录管理语句,也不会记录不使用索引进行查找的查询。可以使用log_slow_admin_statements和 log_queries_not_using_indexes更改此行为 log_queries_not_using_indexes,如下所示。

#记录执行较慢的管理语句 
log_slow_admin_statements =1 

#记录执行较慢的未使用索引的语句 
log_queries_not_using_indexes = 1

1.5 事务日志 redo log

redo log(重做日志)是InnoDB存储引擎独有的,它让MySQL拥有了崩溃恢复能力。

比如在开启事务修改数据时,提交事务之后,还没有将修改的数据写入到磁盘中去, 此时MySQL实例挂了或宕机了,重启时,InnoDB存储引擎会使用redo log恢复数据,保证数据的持久性与完整性。

Mysql收集日志 mysql 日志在哪_MYSQL_08

MySQL 中数据是以页为单位,你查询一条记录,会从硬盘把一页的数据加载出来,加载出来的数据叫数据页,会放入到 Buffer Pool 中。

后续的查询都是先从 Buffer Pool 中找,没有命中再去硬盘加载,减少硬盘 IO 开销,提升性能。

更新表数据的时候,也是如此,发现 Buffer Pool 里存在要更新的数据,就直接在 Buffer Pool 里更新。

然后会把“在某个数据页上做了什么修改”记录到重做日志缓存(redo log buffer)里,接着刷盘到 redo log 文件里。

Mysql收集日志 mysql 日志在哪_Mysql收集日志_09

理想情况,事务一提交就会进行刷盘操作,但实际上,刷盘的时机是根据策略来进行的。

每条 redo 记录由“表空间号+数据页号+偏移量+修改数据长度+具体修改的数据”组成.

1.刷盘时机

InnoDB 存储引擎为 redo log 的刷盘策略提供了 innodb_flush_log_at_trx_commit 参数,它支持三种策略:

  • 0:设置为 0 的时候,表示每次事务提交时不进行刷盘操作
  • 1:设置为 1 的时候,表示每次事务提交时都将进行刷盘操作(默认值)
  • 2:设置为 2 的时候,表示每次事务提交时都只把 redo log buffer 内容写入 page cache

innodb_flush_log_at_trx_commit 参数默认为 1 ,也就是说当事务提交时会调用 fsync 对 redo log 进行刷盘

另外,InnoDB 存储引擎有一个后台线程,每隔1 秒,就会把 redo log buffer 中的内容写到文件系统缓存(page cache),然后调用 fsync 刷盘。

也就是说,一个没有提交事务的 redo log 记录,也可能会刷盘。

这是为什么呢?

因为在事务执行过程 redo log 记录是会写入redo log buffer 中,这些 redo log 记录会被后台线程刷盘。

Mysql收集日志 mysql 日志在哪_MySQL_10

除了后台线程每秒1次的轮询操作,还有一种情况,当 redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘。

2.日志文件组

硬盘上存储的 redo log 日志文件不只一个,而是以一个日志文件组的形式出现的,每个的redo日志文件大小都是一样的。

比如可以配置为一组4个文件,每个文件的大小是 1GB,整个 redo log 日志文件组可以记录4G的内容。

它采用的是环形数组形式,从头开始写,写到末尾又回到头循环写,如下图所示。

Mysql收集日志 mysql 日志在哪_MYSQL_11

Mysql收集日志 mysql 日志在哪_日志_12

在个日志文件组中还有两个重要的属性,分别是 write pos、checkpoint

  • write pos 是当前记录的位置,一边写一边后移
  • checkpoint 是当前要擦除的位置,也是往后推移

每次刷盘 redo log 记录到日志文件组中,write pos 位置就会后移更新。

每次 MySQL 加载日志文件组恢复数据时,会清空加载过的 redo log 记录,并把 checkpoint 后移更新。

write poscheckpoint 之间的还空着的部分可以用来写入新的 redo log 记录。

Mysql收集日志 mysql 日志在哪_Mysql收集日志_13

如果 write pos 追上 checkpoint ,表示日志文件组满了,这时候不能再写入新的 redo log 记录,MySQL 得停下来,清空一些记录,把 checkpoint 推进一下。

Mysql收集日志 mysql 日志在哪_数据_14

3.小结

问题: 只要每次把修改后的数据页直接刷盘不就好了,还有 redo log 什么事?

它们不都是刷盘么?差别在哪里?它们不都是刷盘么?差别在哪里?

1 Byte = 8bit
1 KB = 1024 Byte
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB

实际上,数据页大小是16KB,刷盘比较耗时,可能就修改了数据页里的几 Byte 数据,有必要把完整的数据页刷盘吗?

而且数据页刷盘是随机写,因为一个数据页对应的位置可能在硬盘文件的随机位置,所以性能是很差。

如果是写 redo log,一行记录可能就占几十 Byte,只包含表空间号、数据页号、磁盘文件偏移 量、更新值,再加上是顺序写,所以刷盘速度很快。

所以用 redo log 形式记录修改内容,性能会远远超过刷数据页的方式,这也让数据库的并发能力更强。

redo log(重做日志)让InnoDB存储引擎拥有了崩溃恢复能力。

binlog(归档日志)保证了MySQL集群架构的数据一致性。

虽然它们都属于持久化的保证,但是侧重点不同。

在执行更新语句过程,会记录redo logbinlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo logbinlog的写入时机不一样。

Mysql收集日志 mysql 日志在哪_MYSQL_15

1.6 回滚日志 undo log

我们知道如果想要保证事务的原子性,就需要在异常发生时,对已经执行的操作进行回滚,在 MySQL 中,恢复机制是通过 回滚日志(undo log) 实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后再执行相关的操作。如果执行过程中遇到异常的话,我们直接利用 回滚日志 中的信息将数据回滚到修改之前的样子即可!并且,回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚将之前未完成的事务。

另外,MVCC 的实现依赖于:隐藏字段、Read View、undo log。在内部实现中,InnoDB 通过数据行的 DB_TRX_IDRead View 来判断数据的可见性,如不可见,则通过数据行的 DB_ROLL_PTR 找到 undo log 中的历史版本。每个事务读到的数据版本可能是不一样的,在同一个事务中,用户只能看到该事务创建 Read View 之前已经提交的修改和该事务本身做的修改

1.7 总结

MySQL InnoDB 引擎使用 redo log(重做日志) 保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性

MySQL数据库的数据备份、主备、主主、主从都离不开binlog,需要依靠binlog来同步数据,保证数据一致性。