mysql 的日志分类

我们在使用mysql里会接触到三个核心日志分别是:binlog、redo log、undo log

binlog是server层的日志,而redo log 和undo log都是引擎层(innodb)的日志,要是换其他的数据引擎未必就会有了。

mysql undo文件在哪 mysql binlog undo_mysql undo文件在哪

binlog

binlog 设计目标

binlog 是作为mysql操作记录归档的日志,这个日志记录了所有对数据库的数据、表结构、索引等等变更的操作。也就是说只要是对数据库有变更的操作都会记录到binlog里面来, 可以把数据库的数据当成我们银行账户里的余额,而binlog就相当于我们银行卡的流水。账户余额只是一个结果,至于这个结果怎么来的,那就必须得看流水了。而同样在mysql里我们就是通过binlog来归档、验证、恢复、同步数据。

binlog 记录内容

binlog应该说是Mysql里最核心的日志, 它记录了除了查询语句(select、show)之外的所有的 DDL 和 DML
语句,也就意味着我们基本上所有对数据库的操作变更都会记录到binlog里面。binlog以事件形式记录,不仅记录了操作的语句,同时还记录了语句所执行的消耗的时间。

binlog 有三种记录格式,分别是ROW、STATEMENT、MIXED:

  1. ROW: 基于变更的数据行进行记录,如果一个update语句修改一百行数据,那么这种模式下就会记录100行对应的记录日志。
  2. STATEMENT:Statement 模式只记录执行的 SQL,不需要记录每一行数据的变化,因此极大的减少了 binlog 的日志量,避免了大量的 IO 操作,提升了系统的性能。但是,正是由于 Statement 模式只记录 SQL,而如果一些 SQL 中 包含了函数,那么可能会出现执行结果不一致的情况。比如说 uuid() 函数,每次执行的时候都会生成一个随机字符串,在 master 中记录了 uuid,当同步到 slave 之后,再次执行,就得到另外一个结果了。所以使用 Statement 格式会出现一些数据一致性问题。
  3. MIXED: 混合模式,此模式是ROW模式和STATEMENT模式的混合体,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog。

binlog 写入策略

在进行事务的过程中,首先会把binlog 写入到binlog cache中(因为写入到cache中会比较快,一个事务通常会有多个操作,避免每个操作都直接写磁盘导致性能降低),事务最终提交的时候再吧binlog写入到磁盘中。当然事务在最终commit的时候binlog是否马上写入到磁盘中是由参数 sync_binlog 配置来决定的。

sync_binlog 参数
1、sync_binlog=0 的时候,表示每次提交事务binlog不会马上写入到磁盘,而是先写到page cache,相对于磁盘写入来说写page cache要快得多,不过在Mysql 崩溃的时候会有丢失日志的风险。

2、sync_binlog=1 的时候,表示每次提交事务都会执行 fsync 写入到磁盘 ;

3、sync_binlog的值大于1 的时候,表示每次提交事务都 先写到page cach,只有等到积累了N个事务之后才fsync 写入到磁盘,同样在此设置下Mysql 崩溃的时候会有丢失N个事务日志的风险。

很显然三种模式下,sync_binlog=1 是强一致的选择,选择0或者N的情况下在极端情况下就会有丢失日志的风险,具体选择什么模式还是得看系统对于一致性的要求。

redo log 记录内容

在mysql中,如果修改了数据,那么事务提交前,首先会被记录成redo日志写入磁盘,等到事务提交时,再把新数据写入磁盘(你以为真的是这样)这也就是经常说的WAL(Write-Ahead Logging)。

redo log 是属于引擎层(innodb)的日志,它的设计目标是支持innodb的“事务”的特性.

1.保证数据的持久性。众所周知,数据是记录在磁盘上的,如果事务提交后mysql突然挂了(比如断电之类的),那么内存里的数据,是不是就丢失了?我们数据恢复时候,通过redo 就可以恢复回来。
解释:因为我们在事务提交前都已经把相关日志写入了磁盘,所以碰到意外当然可以恢复。如果写redo的时候断电了呢?大致上可以认为事务回滚了。不过没这么简单,到底是回滚还是提交,还牵扯到bin log。我们下文会讲到。

redo log记录的内容

redo log 的刷盘策略以及写如磁盘流程:

1.将上文提到的一组redo log写入redo log buffer(依然在内存中,依旧是为了调节CPU与磁盘写入速度的矛盾)。
2.redo log buffer写入page cache(操作系统里的页,操作系统会找个时间自动刷到磁盘。或者你调用fsync函数就能确保刷盘)。
3.page cache的数据刷到磁盘。

redo log 的刷盘策略
innodb_flush_log_at_trx_commit参数:

innodb_flush_log_at_trx_commit =0

表示每隔一秒把log buffer刷到文件系统中(os buffer)去,并且调用文件系统的“flush”操作将缓存刷新到磁盘上去。也就是说一秒之前的日志都保存在日志缓冲区,也就是内存上,如果机器宕掉,可能丢失1秒的事务数据。

innodb_flush_log_at_trx_commit=1,

表示在每次事务提交的时候,都把log buffer刷到文件系统中(os buffer)去,并且调用文件系统的“flush”操作将缓存刷新到磁盘上去。这样的话,数据库对IO的要求就非常高了,如果底层的硬件提供的IOPS比较差,那么MySQL数据库的并发很快就会由于硬件IO的问题而无法提升。

innodb_flush_log_at_trx_commit=2,

表示在每次事务提交的时候会把log buffer刷到文件系统中去,但并不会立即刷写到磁盘。如果只是MySQL数据库挂掉了,由于文件系统没有问题,那么对应的事务数据并没有丢失。只有在数据库所在的主机操作系统损坏或者突然掉电的情况下,数据库的事务数据可能丢失1秒之类的事务数据。这样的好处,减少了事务数据丢失的概率,而对底层硬件的IO要求也没有那么高(log buffer写到文件系统中,一般只是从log buffer的内存转移的文件系统的内存缓存中,对底层IO没有压力)。

mysql undo文件在哪 mysql binlog undo_sql_02

undo log

undo log设计目标

undo log是回滚日志,提供回滚操作。 undo log 是也属于引擎层(innodb)的日志,从上面的redo log介绍中我们就已经知道了,redo log 和undo log的核心是为了保证innodb事务机制中的持久性和原子性,事务提交成功由redo log保证数据持久性,而事务可以进行回滚从而保证事务操作原子性则是通过undo log 来保证的。
要对事务数据回滚到历史的数据状态,所以我们也能猜到undo log是保存的是数据的历史版本,通过历史版本让数据在任何时候都可以回滚到某一个事务开始之前的状态。undo log除了进行事务回滚的日志外还有一个作用,就是为数据库提供MVCC多版本数据读的功能。

undo log记录内容

在Mysql里数据每次修改前,都首先会把修改之前的数据作为历史保存一份到undo log里面的,数据里面会记录操作该数据的事务ID,然后我们可以通过事务ID来对数据进行回滚。

redo、undo、binlog的生成流程与崩溃恢复
当我们执行update user_info set name =“李四”where id=1 的时候大致流程如下:
1、从磁盘读取到id=1的记录,放到内存。

2、记录undo log 日志。

3、记录redo log (预提交状态)

4、修改内存中的记录。

5、记录binlog

6、提交事务,写入redo log (commit状态)

mysql undo文件在哪 mysql binlog undo_mysql undo文件在哪_03

我们根据上面的流程来看,如果在上面的某一个阶段数据库崩溃,如何恢复数据。

1、在第一步、第二步、第三步执行时据库崩溃:因为这个时候数据还没有发生任何变化,所以没有任何影响,不需要做任何操作。

2、在第四步修改内存中的记录时数据库崩溃:因为此时事务没有commit,所以这里要进行数据回滚,所以这里会通过undo log进行数据回滚。

3、第五步写入binlog时数据库崩溃:这里和第四步一样的逻辑,此时事务没有commit,所以这里要进行数据回滚,会通过undo log进行数据回滚。

4、执行第六步事务提交时数据库崩溃:如果数据库在这个阶段崩溃,那其实事务还是没有提交成功,但是这里并不能像之前一样对数据进行回滚,因为在提交事务前,binlog可能成功写入磁盘了,所以这里要根据两种情况来做决定。

如果binlog存在事务记录:那么就"认为"事务已经提交了,这里可以根据redo log对数据进行重做。其实你应该有疑问,其实这个阶段发生崩溃了,最终的事务是没提交成功的,这里应该对数据进行回滚。 这里主要的一个考虑是因为binlog已经成功写入了,而binlog写入后,那么依赖于binlog的其它扩展业务(比如:从库已经同步了日志进行数据的变更)数据就已经产生了,如果这里进行数据回滚,那么势必就会造成主从数据的不一致。另外一种情况就 是binlog不存在事务记录,那么这种情况事务还未提交成功,所以会对数据进行回滚。