您的当前位置:首页正文

MySQL日志剖析

来源:爱go旅游网
MySQL⽇志剖析

说起MySQL的⽇志,有三种类型的⽇志对于MySQL来说是⾄关重要的,这三种⽇志分别为:Binlog、Undo Log 和 Redo Log。由于Binlog和UndoLog有类似的地⽅,所以按照如下顺序依次介绍MySQL中的三⼤⽇志原理:Undo Log——> Redo Log ——> Binlog。

Undo Log⽇志

顾名思义,Undo Log的字⾯意思就是撤销操作的⽇志,指的是使MySQL中的数据回到某个状态。

在MySQL数据库中,事务开始之前,MySQL会将待修改的记录保存到Undo Log中,如果数据库崩溃或者事务需要回滚时,MySQL可以通过利⽤Undo Log⽇志,将数据库中的数据回滚到之前的状态。

MySQL新增、修改和删除数据时,在事务开始前,就会将信息写⼊Undo Log中。事务提交时,并不会⽴刻删除Undo Log, InnoDB存储引擎会将事务对应的Undo Log放⼊待删除列表中,之后会通过后台的purge thread对待删除的列表进⾏删除处理。这⾥,值得注意的是:Undo Log是⼀种 逻辑⽇志, 记录的是⼀个变化过程。⽐如,MySQL执⾏⼀个delete操作,Undo Log就会记录⼀个insert操作;MySQL执⾏⼀个insert操作,Undo Log就会记录⼀个delete操作;MySQL执⾏⼀个update操作,Undo Log就会记录⼀个相反的update操作。

Undo Log以段的⽅式来管理和记录⽇志信息,在InnoDB存储引擎的数据⽂件中,包含了⼀种叫做rollback segment的回滚段,其内部包含了1024个undo log senment。

Undo Log对于MySQL实现事务来说,起着⾄关重要的作⽤,它实现了事务的原⼦性和多版本并发控制,也就是我们经常说的MVCC。

实现事务的原⼦性Undo

Log能够实现MySQL事务的原⼦性,在事务的处理过程中,如果MySQL出现了错误或者⽤户⼿动执⾏了事务的回滚操作(执⾏了rollback操作),MySQL可以利⽤

Undo Log⽇志将数据库中的数据恢复到之前的状态。

实现MVCC机制

Undo Log在MySQL的InnoDB存储引擎中实现了多版本并发控制(MVCC)机制。事务未提交前,Undo Log保存了未提交之前的版本数据,Undo Log中的数据可以作为旧版本数据的副本或者快照以便其他并发事务进⾏读取操作。

事务A⼿动开启事务后,对goods数据表中id为1的数据进⾏更新操作,⾸先会把更新命中的数据写⼊到Undo Buffer中。在事务A未提交之前,此时,事务B⼿动开启事务,对goods数据表中的id为1的数据进⾏查询操作,此时的事务B会读取Undo Log中的数据并返回给客户端,这就是MySQL中的MVCC机制。可以在MySQL中通过下⾯的命令来查看控制Undo Log⽇志的参数。show variables like '%innodb_undo%';

Redo Log⽇志

说了MySQL中的Undo Log,我们再来看看MySQL中的Redo Log⽇志。

顾名思义Redo Log的字⾯意思就是重做⽇志,指的是在数据库出现意外情况时能够对重新执⾏某种操作。在MySQL中,事务中修改的任何数据,都会将最新的数据写⼊Redo Log中进⾏备份。

在MySQL中,随着事务操作的执⾏,就会产⽣Redo Log⽇志,在事务提交时会产⽣Redo Log并将其写⼊Redo Buffer,Redo Buffer也并不是随着事务的提交就会被⽴刻写⼊到磁盘中,⽽是等事务操作的脏页写⼊到磁盘之后,Redo Log的使命也就完成了,此时,Redo Log⽇志占⽤的空间可以重新利⽤,会被后续产⽣的Redo Log⽇志覆盖。

Redo Log 能够实现事务的持久性,防⽌在发⽣故障的时间点,有脏页未写⼊表的 ibd ⽂件中,在重启 MySQL 服务的时候,根据 Redo Log 进⾏重做,从⽽将未提交的事务进⾏持久化。这个过程可以简化为下图所⽰。

Redo Log⽂件的内容是以顺序循环的⽅式写⼊⽂件的,写满时就会回到第⼀个⽂件,进⾏覆盖写。

Write Pos 是当前记录的位置,⼀边写⼀边后移,写到最后⼀个⽂件末尾后就回到 0 号⽂件开头;CheckPoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据⽂件;

Write Pos 和 CheckPoint之间还空着的部分,可以⽤来记录新的操作。如果 Write Pos 追上 CheckPoint,表⽰已经写满,此时就需要向后移动CheckPoint来擦除数据。每个InnoDB存储引擎⾄少有1个重做⽇志⽂件组(group),每个⽂件组⾄少有2个重做⽇志⽂件,默认为ib_logfile0和ib_logfile1 。可以在MySQL中通过如下命令来查看控制Redo Log的参数。show variables like '%innodb_log%';

在Redo Log⽇志信息从Redo Buffer持久化到Redo Log时,具体的持久化策略可以通过innodb_flush_log_at_trx_commit 参数进⾏设置,具体策略如下所⽰。

0:每秒提交 Redo buffer ->OS cache -> flush cache to disk,可能丢失⼀秒内的事务数据。由后台Master线程每隔 1秒执⾏⼀次操作。1(默认值):每次事务提交执⾏ Redo Buffer -> OS cache -> flush cache to disk,这种⽅式最安全,性能最差。

2:每次事务提交执⾏ Redo Buffer -> OS cache,然后由后台Master线程再每隔1秒执⾏OS cache -> flush cache to disk 的操作。⼀般建议选择取值2,因为 MySQL 挂了数据没有损失,整个服务器挂了才会损失1秒的事务提交数据。

Binlog⽇志

Binlog记录所有MySQL数据库表结构变更以及表数据修改的⼆进制⽇志,不会记录select和show这类查询操作的⽇志。Binlog⽇志是以事件形式记录,还包含语句所执⾏的消耗时间。开启Binlog⽇志有以下两个最重要的使⽤场景。

主从复制:在主库中开启Binlog功能,这样主库就可以把Binlog传递给从库,从库拿到Binlog后实现数据恢复达到主从数据⼀致性。数据恢复:通过mysqlbinlog等⼯具来恢复数据

Binlog⽂件记录模式有STATEMENT、ROW和MIXED三种,具体含义如下。

ROW(row-based replication, RBR):⽇志中会记录每⼀⾏数据被修改的情况,然后在slave端对相同的数据进⾏修改。

优点:能清楚记录每⼀个⾏数据的修改细节,能完全实现主从数据同步和数据的恢复。缺点:批量操作,会产⽣⼤量的⽇志,尤其是alter table会让⽇志暴涨。

STATMENT(statement-based replication, SBR):每⼀条被修改数据的SQL都会记录到master的Binlog中,slave在复制的时候SQL进程会解析成和原来master端执⾏过的相同的SQL再次执⾏。简称SQL语句复制。

优点:⽇志量⼩,减少磁盘IO,提升存储和恢复速度

缺点:在某些情况下会导致主从数据不⼀致,⽐如last_insert_id()、now()等函数。

MIXED(mixed-based replication, MBR):以上两种模式的混合使⽤,⼀般会使⽤STATEMENT模式保存binlog,对于STATEMENT模式⽆法复制的操作使⽤ROW模式保存binlog,MySQL会根据执⾏的SQL语句选择写⼊模式 。

对于MySQL的Binlog⽂件结构有三种版本,见下图。

关于Binlog⽂件结构的具体信息,⼩伙伴们可以参考MySQL的官⽅⽂档,具体链接为:

根据记录模式和操作触发event事件⽣成log event(事件触发执⾏机制)。

将事务执⾏过程中产⽣的⽇志时间(log event)写⼊缓冲区,每个事务线程都有⼀个缓冲区。Log Event保存在⼀个binlog_cache_mngr数据结构中,在该结构中有两个缓冲区,⼀个是stmt_cache,⽤于存放不⽀持事务的信息;另⼀个是trx_cache,⽤于存放⽀持事务的信息。事务在提交阶段会将产⽣的log event写⼊到外部binlog⽂件中。不同事务以串⾏⽅式将log event写⼊Binlog⽂件中,所以⼀个事务包含的log event信息在binlog⽂件中是连续的,中间不会插⼊其他事务的log event。

Binlog状态查看

show variables like 'log_bin';

开启Binlog功能,需要修改my.cnf或my.ini配置⽂件,在[mysqld]下⾯增加log_bin=mysql_bin_log,重启MySQL服务。binlog-format=ROWlog-bin=mysqlbinlog使⽤show binlog events命令

show binary logs; //等价于show master logs;show master status;show binlog events;

show binlog events in 'mysqlbinlog.000001';使⽤mysqlbinlog 命令mysqlbinlog \"⽂件名\"

mysqlbinlog \"⽂件名\" > \"test.sql\"使⽤ binlog 恢复数据//按指定时间恢复

mysqlbinlog --start-datetime=\"2021-02-28 18:00:00\" --stopdatetime=\"2021-03-01 00:00:00\" mysqlbinlog.000001 | mysql -uroot -p123456//按事件位置号恢复

mysqlbinlog --start-position=1789 --stop-position=2674 mysqlbinlog.000001| mysql -uroot -p123456删除Binlog⽂件

purge binary logs to 'mysqlbinlog.000001'; //删除指定⽂件

purge binary logs before '2021-03-01 00:00:00'; //删除指定时间之前的⽂件reset master; //清除所有⽂件

可以通过设置expire_logs_days参数来启动⾃动清理功能。默认值为0表⽰没启⽤。设置为⼤于0的整数表⽰超出多少天binlog⽂件会⾃动清除。

因篇幅问题不能全部显示,请点此查看更多更全内容