MySQL中的7种日志
Opened this issue · 1 comments
MySQL中有7种日志文件
- 重做日志(redo log)
- 回滚日志(undo log)
- 二进制日志(bin log)
- 错误日志(error log)
- 慢查询日志(slow query log)
- 一般查询日志(general log)
- 中继日志(relay log)
事务的4大特性ACID。
一个很好的事务处理系统,必须具备这些标准特性:
- 原子性(Atomicity):一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。
- 一致性(consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态。(其实原子性和隔离性间接的保证了一致性)
- 隔离性(isolation):通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。
- 持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。
重做日志(redo log)
-
利用WAL技术(Write-Ahead-Logging, 即先写日志,后写磁盘)推迟物理数据页的刷新,从而提升数据库吞吐,有效降低了访问时延。
-
redo log是InnoDB引擎特有的:binlog是MySQL的Service层实现的,所有的引擎都可以使用
-
redo log提供了crash-safe的能力,即使MySQL异常重启,之前提交的记录也不会丢失。
-
redo log是物理日志,记录的是在某一个数据页面上做了什么修改,binlog是逻辑日志,记录的是这个语句的原始逻辑
-
redo log是固定大小的,从头开始写,写到末尾之后又回头开头循环写,binlog是可以追加写当到达一定大小后会切换到下一个不会覆盖之前的日志
-
redo log的写入分成了 prepare 和 commit 两个阶段, 称为两阶段提交
-
redo log并不是直接写入磁盘的,而是先写入到缓存区,我们把这个缓冲区叫做 redo日志缓冲区
在 MySQL Server 5.7 下 redo日志缓冲区的大小默认为 1M,我们可以通过 innodb_log_buffer_size 参数来设置 redo 日志缓冲区的大小。
缓冲区和磁盘之间的数据如何同步?
在 MySQL配置文件中提供了 innodb_flush_log_at_trx_commit 参数,这个可以用来控制缓冲区和磁盘之间的数据如何同步:
- 0:表示当提交事务时,并不将缓冲区的 redo 日志写入磁盘的日志文件,而是等待主线程每秒刷新。
- 1:在事务提交时将缓冲区的 redo 日志同步写入到磁盘,保证一定会写入成功。
- 2:在事务提交时将缓冲区的 redo 日志异步写入到磁盘,即不能完全保证 commit 时肯定会写入 redo 日志文件,只是有这个动作。
我们使用默认值 1 就好,这样可以保证 MySQL 异常重启之后数据不丢失。
-
InnoDb引擎会先将操作(更新)记录写到redo log中,并更新内存,此时就算更新完成了。InnoDb引擎会在空闲或适当的时候将操作记录写到磁盘上
- 上图中画出了序号从0-3,共4个redo log
- write pos为当前写入位置, check point为检查点, write pos和check point都一直向前推进;write pos和check point之间的绿色部分就可以用来写入redo log
- checkpoint之前的所有数据都已经刷新回磁盘,当DB crash后,通过对checkpoint之后的redo log进行恢复就可以了
- 如果redo log过多, 此时check point还没有推进, write pos就追上了check point, 那么就必须等待check point向前推进, 此时MySQL无法处理更新操作
回滚日志(undo log)
重做日志记录了事务的行为,可以很好的通过其对页进行“重做”操作。但是事务有时候还需要进行回滚操作,也就是ACID中的A(原子性),这时就需要Undo log了。因此在数据库进行修改时,InnoDB存储引擎不但会产生Redo,还会产生一定量的Undo。这样如果用户执行的事务或语句由于某种原因失败了,又或者用户一条ROLLBACK语句请求回滚,就可以利用这些Undo信息将数据库回滚到修改之前的样子。
Undo log是InnoDB MVCC事务特性的重要组成部分。当我们对记录做了变更操作时就会产生Undo记录,Undo记录默认被记录到系统表空间(ibdata)中,但从5.6开始,也可以使用独立的Undo 表空间。
Undo记录中存储的是老版本数据,当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着undo链找到满足其可见性的记录。当版本链很长时,通常可以认为这是个比较耗时的操作。
undo log主要记录的是数据的逻辑变化,为了在发生错误时回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误时才可以回滚。
undo log只将数据库逻辑地恢复到原来的样子,在回滚的时候,它实际上是做的相反的工作,比如一条INSERT ,对应一条 DELETE,对于每个UPDATE,对应一条相反的 UPDATE,将修改前的行放回去。undo日志用于事务的回滚操作进而保障了事务的原子性。
在InnoDB存储引擎中,undo存储在回滚段(Rollback Segment)中,每个回滚段记录了1024个undo log segment,而在每个undo log segment段中进行undo 页的申请,在5.6以前,Rollback Segment是在共享表空间里的,5.6.3之后,可通过 innodb_undo_tablespace设置undo存储的位置。
在InnoDB存储引擎中,undo log分为:insert undo log、update undo log
二进制日志(bin log)
MySQL的主库(Master)对数据库的任何变化(创建表,更新数据库,对行数据进行增删改),都以二进制文件的方式记录与主库的Binary Log(即binlog)日志文件中。
图来自1Dump Thread Enhancement On MySQL-5.7.2
- redolog是InnoDB特有的日志,binlog属于Server层日志
- 有两份日志的历史原因
- 一开始并没有InnoDB,采用的是MyISAM,但MyISAM没有crash-safe的能力,binlog日志只能用于归档
- InnoDB是以插件的形式引入MySQL的,为了实现crash-safe,InnoDB采用了redolog的方案
- binlog一开始的设计就是不支持崩溃恢复(原库)的,
如果不考虑搭建从库等操作,binlog是可以关闭的(sql_log_bin)
redolog vs binlog
-
redolog是InnoDB特有的,binlog是MySQL的Server层实现的,所有层都可以使用
-
redolog是物理日志,记录某个数据页上做了什么修改
- binlog是逻辑日志,记录某个语句的原始逻辑
- 逻辑日志:提供给别的引擎用,是大家都能理解的逻辑,例如搭建从库
- 物理日志:只能内部使用,其他引擎无法共享内部的物理格式
-
redolog是循环写,空间固定,不能持久保存,没有归档功能
- binlog是追加写,空间不受限制,有归档功能
-
redolog主要用于crash-safe,原库恢复
- binlog主要用于恢复成临时库(从库)
-
崩溃恢复的过程不写binlog(可能需要读binlog,如果binlog有打开,一般都会打开)
- 用binlog恢复实例(从库),需要写redolog
-
redolog支持事务的持久性,undolog支持事务的隔离性
-
redolog对应用开发来说是透明的
binlog有两种模式
- statement格式:SQL语句
- row格式:行内容(记两条,更新前和更新后),推荐
- 日志一样的可以用于重放
基于Binlog的流式日志抽取的架构与原理
从库的IO Thread异步地同步Binlog文件并写入到本地的Replay文件。SQL Thread再抽取Replay文件中的SQL语句在从库进行执行,实现数据更新。 需要注意的是,MySQL Binlog 支持多种数据更新格式 – 包括Row,Statement,或者mix(Row和Statement的混合)。我们建议使用Row这种Binlog格式(MySQL5.7之后的默认支持版本),可以更方便更加实时的反映行级别的数据变化。
图来自让你的数据库流动起来 – 利用MySQL Binlog实现流式实时分析架构
我们利用一些客户端工具“佯装”成MySQL Slave,抽取出Binlog的日志文件,并把数据变化注入到实时的流式数据管道中。我们在管道后端对Binlog的变化日志,进行消费与必要的数据处理(例如利用AWS的Lambda服务实现无服务器的代码部署),同步到多种异构数据源中 – 例如 Redshift, ElasticSearch, S3 (EMR) 等等。具体的架构如下图所示。
中继日志(relay log)
thanks
redo log的参数innodb_flush_method
mysql的innodb_flush_method这个参数控制着innodb数据文件及redo log的打开、刷写模式,对于这个参数,文档上是这样描述的:
有三个值:fdatasync(默认),O_DSYNC,O_DIRECT
- fdatasync,调用fsync()去刷数据文件与redo log的buffer
- 为O_DSYNC时,innodb会使用O_SYNC方式打开和刷写redo log,使用fsync()刷写数据文件
- 为O_DIRECT时,innodb使用O_DIRECT打开数据文件,使用fsync()刷写数据文件跟redo log
首先文件的写操作包括三步:open,write,flush
- 上面最常提到的fsync(int fd)函数,该函数作用是flush时将与fd文件描述符所指文件有关的buffer刷写到磁盘,并且flush完元数据信息(比如修改日期、创建日期等)才算flush成功。
- 使用O_DSYNC方式打开redo文件表示当write日志时,数据都write到磁盘,并且元数据也需要更新,才返回成功。
- O_DIRECT则表示我们的write操作是从MySQL innodb buffer里直接向磁盘上写。
这三种模式写数据方式具体如下:
- fdatasync模式:写数据时,write这一步并不需要真正写到磁盘才算完成(可能写入到操作系统buffer中就会返回完成),真正完成是flush操作,buffer交给操作系统去flush,并且文件的元数据信息也都需要更新到磁盘。
- O_DSYNC模式:写日志操作是在write这步完成,而数据文件的写入是在flush这步通过fsync完成
- O_DIRECT模式:数据文件的写入操作是直接从mysql innodb buffer到磁盘的,并不用通过操作系统的缓冲,而真正的完成也是在flush这步,日志还是要经过OS缓冲