小谈 MySQL 第六话·日志文件

目录

写在最前:

一、初始上三宗

二、小谈上三宗

1、重做日志(redo log)

① redo log 原理

② redo log 作用

③ redo log 内容

④ redo log 什么时候产生❓

⑤ redo log 什么时候释放❓

⑥ redo log 对应的物理文件

⑦ 其它

2、回滚日志(undo log)

① undo log 原理

② undo log 作用

③ undo log 内容

④ undo log 什么时候产生❓

⑤ undo log 什么时候释放❓

⑥ undo log 对应的物理文件

⑦ 其它

3、二进制日志(binlog)

① binlog 作用

② 主从同步原理

③ binlog 内容

④ binlog 什么时候产生❓

⑤ binlog 什么时候释放❓

⑥ binlog 对应的物理文件

⑦ 其它

三、轻描淡写下四宗

1、错误日志(error log)

2、慢查询日志(slow query log)

3、一般查询日志(general log)

4、中继日志(relay log)

① relay log 作用

② relay log 相关参数

③ relay log 内容

④ relay log 什么时候产生❓

⑤ relay log 什么时候释放❓


写在最前:

日志文件是 MySQL 数据库的重要组成部分。MySQL 有几种不同的日志文件,通常包括重做日志、回滚日志、二进制日志、错误日志、慢查询日志、一般查询日志、中继日志等。这些日志可以帮助我们定位 MySQL 内部发生的事件,MySQL 性能故障,记录数据的变更历史,恢复数据等。

  • 重做日志(redo log),又被称为 Innodb 的在线 redo 日志(innodb redo log)
  • 回滚日志(undo log)
  • 二进制日志(bin log)
  • 错误日志(error log)
  • 慢查询日志(slow query log)
  • 一般查询日志(general log)
  • 中继日志(relay log)

其中重做日志和回滚日志与事务息息相关,二进制日志也与事务操作有一定的关系,这三种日志,对理解 MySQL 中的事务操作有着重要意义。所以接下来我称之为上三宗(O(∩_∩)O哈哈~斗罗大陆看多了)

一、初始上三宗

1、redo log:是为了持久化数据,在数据还没从内存刷新到磁盘时,如果发生故障,可读取 redo log 持久化到磁盘。

2、bin log:是为了复制和恢复数据的,即 MySQL 从服务器可以读取主服务器的 binlog 复制数据,数据库数据丢失,可以读取 binlog 恢复。

3、undo log:是为了保证事务的原子性的。在 InnoDB 存储引擎中,还用 undo log 来实现多版本并发控制(MVCC)。

二、小谈上三宗

1、重做日志(redo log)

① redo log 原理

redo log 记录的是新数据的备份。在事务提交前,只要将 redo log 持久化即可,不需要将数据化持久化到磁盘,当系统崩溃时,虽然数据还没持久化到磁盘,但 redo log 已经持久化,系统可以根据 redo log 的内容,将所有数据恢复到最新的状态。

redo log 是为了实现事务的持久性而出现的产物。

② redo log 作用

确保事务的持久化。redo log 记录事务执行后的状态,用来恢复未持久化到磁盘的已成功事务更新的数据,防止在发生故障的时间点,尚有脏页未持久化到磁盘,在重启 MySQL 服务的时候,根据 redo log 进行重做,从而达到事务持久性这一特性。

③ redo log 内容

物理格式的日志,记录的事务物理·数据页面的修改信息,其 redo log 是顺序写入 redo log file 的物理文件(ib_logfileN)中去的。

④ redo log 什么时候产生❓

事务开始之后就产生了 redo log,redo log 的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入 redo log 文件中,即随着事务的开始,逐步开始落盘。

⑤ redo log 什么时候释放❓

当对应事务的脏页写入到磁盘之后,redo log 的使命也就完成了,重做日志占用的空间就可以重用(被覆盖)。

⑥ redo log 对应的物理文件

默认情况下,对应的物理文件位于数据库的 data 目录下的 ib_logfile1 & ib_logfile2。

  • innodb_log_group_home_dir 指定日志文件组所在的路径,默认 ./ ,表示在数据库的数据目录下。
  • innodb_log_files_in _group 指定重做日志文件组中文件的数量,默认为 2。

关于文件的大小和数量,由以下两个参数配置:

  • innodb_log_file_size 重做日志文件的大小。
  • innodb_mirrored_log_groups 指定了日志镜像文件组的数量,默认 1。

⑦ 其它

很重要的一点,redo log 是什么时候写盘的?前面 ④ 中也说了是在事务开始之后逐步写盘的。

之所以说重做日志是在事务开始之后逐步写入重做日志文件,而不一定是事务提交才写入重做日志缓存,原因就是重做日志有一个缓存区 Innodb_log_buffer,Innodb_log_buffer 默认大小为 8M(这里设置为 96M),Innodb 存储引擎先将重做日志写入 Innodb_log_buffer 中。

mysql> show variables like 'innodb_log_buffer%';
+------------------------+-----------+
| Variable_name          | Value     |
+------------------------+-----------+
| innodb_log_buffer_size | 100663296 |
+------------------------+-----------+
mysql> select (100663296/1024/1024);
+-----------------------+
| (100663296/1024/1024) |
+-----------------------+
|           96.00000000 |
+-----------------------+

《MySQL 技术内幕 Innodb 存储引擎》(page 37):即使某个事务还没有提交,Innodb 存储引擎仍然每秒会将重做日志缓存刷新到重做日志文件。

这一点必须要知道的,因为这可以很好的解释再大的事务提交,时间也是很短暂的。

redo log 包括两部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。

在概念上,innodb 通过 force log at commit 机制实现事务的持久性,即在事务提交的时候,必须先将该事务的所有事务日志写入到磁盘上的 redo log file 和 undo log file 中进行持久化。

过程如下:

 

为了确保每次日志都能写入到事务日志文件中,在每次将 log buffer 中的日志写入日志文件的过程中都会调用一次操作系统的 fsync 操作(即 fsync() 系统调用)。因为 MySQL 是工作在用户空间的,MySQL 的 log buffer 处于用户空间的内存中。要写入到磁盘上的 log file 中(redo:ib_logfileN 文件,undo:share tablespace 或 .ibd 文件),中间还要经过操作系统内核空间的 OS Buffer,调用 fsync() 的作用就是将 OS Buffer 中的日志刷到磁盘上的 log file 中。

MySQL 支持用户自定义在 commit 时如何将 log buffer 中的日志刷到 log file 中。

这种控制通过参数 innodb_flush_log_at_trx_commit 的值来决定。该参数有 3 个值:0、1、2,默认为 1。

但注意,这个参数只是控制 commit 动作是否刷新 log buffer 到磁盘:

  • 当设置为 1 的时候,事务每次提交都会将 log buffer 中的日志写入 os buffer 并调用 fsync() 刷到 log file on disk 中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO 的性能较差;
  • 当设置为 0 的时候,事务提交时不会将 log buffer 中日志写入到 os buffer,而是每秒写入 os buffer 并调用 fsync() 写入到 log file on disk 中。也就是说设置为 0 时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失 1 秒钟的数据;
  • 当设置为 2 的时候,每次提交都仅写入到 os buffer,然后是每秒调用 fsync() 将 os buffer 中的日志写入到 log file on disk。

 

2、回滚日志(undo log)

① undo log 原理

为了满足事务的原子性,在操作任何数据之前,首先将数据备份存储到 undo log,然后进行数据修改,如果出现错误或者用户执行了 rollback 语句,系统可以利用 undo log 中备份的数据恢复到事务开始执行前的状态。

② undo log 作用

保证数据的原子性,保存了事务发生之前数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),即非锁定读。

③ undo log 内容

逻辑格式的日志,在执行 undo log 的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于 redo log 的。

④ undo log 什么时候产生❓

事务开始之前,将当前的版本生成 undo log,undo 也会产生 redo 来保证 undo log 的可靠性。

⑤ undo log 什么时候释放❓

当事务提交后,undo log 并不能立马被删除,而是放入待清理的链表,由 purge 线程判断是否有其它事务在使用 undo 段中表的上一个事务之前的版本信息,决定是否可以清理 undo log 的日志空间。

⑥ undo log 对应的物理文件

如果 undo 使用的共享表空间,这个共享表空间中又不仅仅是存储 undo 的信息,共享表空间默认在 MySQL 的数据目录下面,其属性由参数 innodb_data_file_path 配置。

  • MySQL5.6 之前,undo 表空间位于共享表空间的回滚段中,共享表空间默认的名称是 ibdata(.ibd 文件),位于数据文件目录中;
  • MySQL5.6 之后,undo 表空间可以配置成独立的文件,但是提前需要在配置文件中配置,完成数据库初始化后生效且不可改变 undo log 文件的个数;
  • 如果初始化数据库之前没有进行相关配置,那么就无法配置成独立的表空间了。

关于 MySQL5.7 之后的独立 undo 表空间配置参数请进一步查看官方文档。

  • innodb_undo_directory = /data/undospace/    # undo 独立表空间的存放目录
  • innodb_undo_log = 128    # 回滚段为 128KB
  • innodb_undo_tablespaces = 4    # 指定有 4 个 undo log 文件

⑦ 其它

undo 是在事务开始之前保存的被修改数据的一个版本,产生 undo log 的时候,同样会伴随类似于保护事务持久化机制的 redo log 的产生。

默认情况下 undo 文件是保存在共享表空间的,即 ibdatafile 文件中,当数据库中发生一些大的事务性操作的时候,要生成大量的 undo 信息,全部保存在共享表空间中。因此共享表空间可能会变的很大,也就是 undo log 使用共享表空间的时候,被“撑大”的共享表空间是不会也不能自动收缩的。

因此,MySQL5.7 之后的“独立 undo 表空间”的配置就显得很有必要了。

3、二进制日志(binlog)

① binlog 作用

用于复制,在主从复制中,从库利用主库上的 binlog 进行重播,实现主从同步。

② 主从同步原理

主服务器把数据更新记录到二进制日志中并通知从服务器同步,从服务器收到通知后通过 I/O 线程向主库发起 binlog 请求,主服务器通过 dump 线程把二进制日志传送给从服务器,从服务器通过 I/O 线程记录到自己的中继日志中,然后在通过 SQL 线程解析应用中继日志中的内容,完成同步。

 

从库在主从之间建立长连接,主从同步需要三个线程:master(binlog dump thread)、slave(I/O thread、SQL thread):

  1. 主库接收到更新命令,执行更新操作,生成 binlog;
  2. 主服务器创建 dump  thread 通知从服务器 I/O thread 有数据更新;
  3. 从服务器 I/O thread 收到通知后向主服务器 dump thread 发起请求;
  4. 主服务器 dump thread 收到从服务器 I/O thread 请求内容时会从本地读取 binlog;
  5. 主服务器 dump thread 将 binlog 传送给从服务器 I/O thread;
  6. 从服务器 I/O thread 将请求回来 binlog 存到本地 relay log 中;
  7. 从服务器 SQL thread 检测到 relay log 有更新后,会读取解析 relay log,
  8. 从服务器 SQL thread 将解析后的内容在本地重新执行一遍,保证主从数据同步。

③ binlog 内容

逻辑格式的日志,可以简单认为就是执行过的事务中的 SQL 语句。

但又不完全是 SQL 语句那么简单,而是包括了执行的 SQL语句反向的信息(也就意味着insert 对应着 insert 本身和 delete 的信息;update 对应着 update 执行前后的版本的信息;delete 对应着 delete 本身和其反向的 insert)。

在使用 mysqlbinlog 解析 binlog 之后就能发现,以下是 mysqlbinlog 几个常用选项:

-d,--database=name:只查看指定数据库的日志操作 -o,--offset=#:忽略掉日志中的前 n 个操作命令。
-r,--result-file=name:将输出的日志信息输出到指定的文件中,使用重定向也一样可以。
-s,--short-form:显示简单格式的日志,只记录一些普通的语句,会省略掉一些额外的信息如位置信息和时间信息以及基于行的日志。可以用来调试,生产环境千万不可使用。
--set-charset=char_name:在输出日志信息到文件中时,在文件第一行加上 set names char_name。
--start-datetime,--stop-datetime:指定输出开始时间和结束时间内的所有日志信息
--start-position=#,--stop-position=#:指定输出开始位置和结束位置内的所有日志信息
-v,-vv:显示更详细信息,基于 row 的日志默认不会显示出来,此时使用 -v 或 -vv 可以查看。

MySQL 的 binlog 有三种格式:statement、row 和 mixed。

mysql> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | MIXED |
+---------------+-------+

④ binlog 什么时候产生❓

事务提交的时候,一次性将事务中的 SQL 语句按照一定的格式记录到 binlog 中。

这里与 redo log 很明显的差异就是 redo log 并不一定是在事务提交的时候刷新到磁盘,redo log 是在事务开始之后就逐步写入磁盘,因此对于事务的提交,即便是较大的事务,提交(commit)都是很快的。

⑤ binlog 什么时候释放❓

binlog 的默认保存时间由参数 expire_logs_days 配置,也就是说对于非活动的日志文件,在生产时间超过 expire_logs_days 配置的天数之后,就会被自动删除。

mysql> show variables like 'expire_logs_days';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| expire_logs_days | 30    |
+------------------+-------+

⑥ binlog 对应的物理文件

物理文件的路径为 log_bin_basename,当日志文件达到指定大小之后进行滚动更新,生成新的日志文件。

对于每个 binlog 文件,通过一个统一的 index 文件来组织。

mysql> show variables like 'log_bin_basename';
+------------------+------------------------------------------------+
| Variable_name    | Value                                          |
+------------------+------------------------------------------------+
| log_bin_basename | /data/mysql5.6.16log/mysql3211/binlogs/log_bin |
+------------------+------------------------------------------------+
mysql> select (1073741824/1024/1024/1024);
+-----------------------------+
| (1073741824/1024/1024/1024) |
+-----------------------------+
|              1.000000000000 |
+-----------------------------+
# 1G
mysql> show variables like 'log_bin_index';
+---------------+------------------------------------------------------+
| Variable_name | Value                                                |
+---------------+------------------------------------------------------+
| log_bin_index | /data/mysql5.6.16log/mysql3211/binlogs/log_bin.index |
+---------------+------------------------------------------------------+
## 可以通过查看二进制的 index 文件来查看当前正在使用哪些二进制日志
# cat /data/mysql5.6.16log/mysql3211/binlogs/log_bin.index
## 也可以在 MySQL 环境中使用 show {binary | master} logs 来查看,binary 和 master 是同义词
mysql> show binary logs;
或
mysql> show master logs;
  
## 查看日志中进行了哪些操作
mysql> show binlog events in 'log_bin.000128';
## 可以指定起始位置,起始位置必须指定正确,不能指定不存在的位置
mysql> show binlog events in 'log_bin.000128' from 1024;
  
## 删除二进制日志有几种方法,不管哪种方法,都会将删除后的信息同步到二进制 index 文件中
# reset master 将会删除所有日志,并让日志文件重新从 000001 开始
mysql> reset master;
# PURGE { BINARY | MASTER } LOGS { TO 'log_name' | BEFORE datetime_expr }
mysql> purge master logs to "log_bin.000128";
或
mysql> purge binary logs to "log_bin.000128";
# 删除指定日期之前的所有日志,但是若指定的时间处在正在使用中的日志文件中,将无法进行purge
mysql> purge master logs before 'yyyy-mm-dd hh:mi:ss'

MySQL 提供了一个 sync_binlog 参数来控制数据库的 binlog 刷新到磁盘上去。默认 sync_binlog = 0,表示 MySQL 不控制 binlog 的刷新,由文件系统自己控制它的缓存的刷新,这时候性能是最好的,但风险也是最大的。一旦系统 crash,在 binlog_cache 中的所有 binlog 信息会被丢失。

如果 sync_binlog > 0,表示每 sync_binlog 次事物提交,MySQL 调用文件系统的刷新操作将缓存持久化。最安全的就是 sync_binlog = 1,表示每次事物提交,MySQL 都会把 binlog 刷下去,是最安全但性能损耗做大的设置。

mysql> show variables like 'sync_binlog';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog   | 600   |
+---------------+-------+

⑦ 其它

二进制日志的作用之一是还原数据库的,这与 redo log 很类似,但是亮着有本质的不同,可不要混淆了:

  • 作用不同:redo log 是保证事务的持久性的,是事务层面,binlog 作为还原的功能,是数据库层面的(当然也可以精确到事务层面),虽然都有还原的意思,但是其保护数据的层次是不一样的。
  • 内容不同:redo log 是物理日志,是数据页面的修改之后的物理记录,binlog 是逻辑日志(可以简单认为记录的及时 SQL 语句)。
  • 另外,两者产生的时间,可以释放的实际,在可释放的情况下清理机制,都是完全不同的。
  • 恢复数据时候的效率,基于物理日志的 redo log 恢复数据的效率要高于逻辑日志的 binlog。

三、轻描淡写下四宗

1、错误日志(error log)

在 MySQL 数据库中,错误日志功能是默认开启的,而且无法被关闭。默认情况,错误日志存储在 MySQL 数据库的数据文件中。

错误日志可以自己配置,错误日志可以通过 log_error 和 log_warnings 来定义,其中 log_error:配置是否启用错误日志功能和错误日志的存储位置;log_warning:配置是否将警告信息也定义至错误日志中。

错误日志记录信息:服务器启动关闭信息、运行错误信息、时间调度器运行一个事件时产生的信息、在服务器上启动进程产生的信息。

mysql> show variables like 'log_error';
+---------------+-----------------------------------------+
| Variable_name | Value                                   |
+---------------+-----------------------------------------+
| log_error     | /data/mysql5.6.16log/mysqld-5.6-err.log |
+---------------+-----------------------------------------+
mysql> show variables like 'log_warnings';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_warnings  | 1     |
+---------------+-------+

2、慢查询日志(slow query log)

慢查询日志是用来记录执行时间超过指定时间的查询语句。通过慢查询日志,可以查找出哪些查询语句的执行效率很低,以便进行优化。一般建议开启,它对服务器性能影响很小,但是可以记录 MySQL 服务器上执行很长时间的查询语句。可以帮助我们定义性能问题。

# 查看慢查询时间
mysql> show variables like 'long_query_time';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+
# 查看慢查询日志路径
mysql> show variables like 'slow_query_log_file';
+---------------------+-------------------------------+
| Variable_name       | Value                         |
+---------------------+-------------------------------+
| slow_query_log_file | /data/mysql5.6.16log/slow.log |
+---------------------+-------------------------------+

3、一般查询日志(general log)

默认情况,一般查询日志是关闭的。因为查询日志会记录用户所有的操作,其中还包括增删改查等信息,如果在高并发的环境下会产生大量的信息,导致不必要的磁盘 IO,会影响 MySQL 的性能。

使用 general_log = {0 | 1}  来决定是否启用一般查询日志,使用 general_log_file = file_name 来指定查询日志的路径,不给定路径时默认的文件名以 {hostname}.log 命名。

mysql> show variables like 'general_log%';
+------------------+----------------------------------------------------------------+
| Variable_name    | Value                                                          |
+------------------+----------------------------------------------------------------+
| general_log      | OFF                                                            |
| general_log_file | /data/mysql5.6.16data/mysql3211/data/yz-higo-accountdb-m01.log |
+------------------+----------------------------------------------------------------+
## 是否启用一般查询日志,为全局变量,必须在global上修改
mysql> set @@global.general_log=1;

4、中继日志(relay log)

① relay log 作用

从服务器 I/O thread 将主服务器的二进制日志读取过来记录到从服务器本地文件(即 relay log),然后从服务器 SQL thread 会读取 relay log 的内容并应用到从服务器,从而使从服务器和主服务器的数据保持一致。

② relay log 相关参数

mysql> show variables like '%relay%';
+---------------------------+----------------------------------------------------------+
| Variable_name             | Value                                                    |
+---------------------------+----------------------------------------------------------+
| max_relay_log_size        | 0                                                        |
| relay_log                 | /data/mysql5.6.16log/mysql3211/relaylogs/relay-bin       |
| relay_log_basename        | /data/mysql5.6.16log/mysql3211/relaylogs/relay-bin       |
| relay_log_index           | /data/mysql5.6.16log/mysql3211/relaylogs/relay-bin.index |
| relay_log_info_file       | relay-log.info                                           |
| relay_log_info_repository | FILE                                                     |
| relay_log_purge           | ON                                                       |
| relay_log_recovery        | OFF                                                      |
| relay_log_space_limit     | 0                                                        |
| sync_relay_log            | 10000                                                    |
| sync_relay_log_info       | 10000                                                    |
+---------------------------+----------------------------------------------------------+
# max_relay_log_size:relay log 允许的最大值,如果该值为 0,则默认值为 max_binlog_size (1G);如果不为 0,则 max_relay_log_size 则为最大的 relay_log 文件大小。
# relay_log:定义 relay_log 的位置和名称,如果值为空,则默认位置在数据文件的目录。
# relay_log_info_file:定义 relay-log.info 的位置和名称,relay-log.info 记录 master 主库的 binary_log 的恢复位置和 从库 relay_log 的位置。
# sync_relay_log:当设置为 1 时,slave 的 I/O thread 每次接收到 master 发送过来的 binlog 日志都要写入系统缓冲区,然后刷入 relay log 中继日志里,这样是最安全的,因为在崩溃的时候,你最多会丢失一个事务,但会造成磁盘的大量 I/O;当设置为 0 时,并不是马上就刷入中继日志里,而是由操作系统决定何时来写入,虽然安全性降低了,但减少了大量的磁盘 I/O 操作。这个值默认是 0,可动态修改。
# sync_relay_log_info:这个参数和 sync_relay_log 参数一样。

③ relay log 内容

逻辑格式日志。

④ relay log 什么时候产生❓

主服务器 dump thread 将 binlog 传送给从服务器 I/O thread,从服务器 I/O thread 将请求回来 binlog 存到本地 relay log 中。

⑤ relay log 什么时候释放❓

relay log 同步完成完成后就会被系统自动删除。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值