前言:
MySql 中有三种 log 是非常中要的,因为MySql之所以能反对 事务(实现长久化、回滚等)、数据库解体复原、主从复制等,都是基于这三种日志的。
至关重要的三种log:
- binlog 二进制日志
- redo log 重做日志
- undo log 回滚日志
本文主线:
- 简要介绍三种日志
- MySql事务处理中三种日志承当的角色
简要介绍三种日志:
1、binlog 二进制日志:
binlog 二进制日志(归档日志),这个日志是由MySql的 server层 进行保护的;不论以后MySql应用的是什么存储引擎,binlog归档日志都是反对的;对MySql的server层不分明的大大们能够参考此文章:查问SQL的执行流程
作用:
- 用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
- 数据恢复,用于数据库的基于工夫点的还原。
内容:
逻辑格局的日志,binlog是用于记录所有数据库表构造和表数据变更的二进制日志,比方insert、update、delete、create、truncate等等操作,不会记录select、show操作,因为它们没有对数据自身产生扭转。
常见格局:
MySql的binlog的默认格局是应用 STATEMENT;须要记住的是应用此格局时,如果将事务隔离级别设置为 RC读已提交 时,在进行主从复制的时候会存在bug,导致复制后主从数据不统一;
具体存在什么样的bug能够参考此文章:互联网我的项目中mysql应该选什么事务隔离级别
留神:
binlog二进制日志文件在默认状况下并没有启动,须要手动进行开启的;有人可能会质疑,开启此日志文件的话,对数据库的性能会产生什么样的影响?
质疑是对的,的确开启此日志文件会影响到数据库的性能,然而这个影响是非常无限的,依据MySql的官网手册理解到,开启此日志会使性能降落1%左右,这个损失大体上是能够承受的。
2、redo log 重做日志:
redo log重做日志,这个日志是由MySql的 innodb存储引擎 提供保护的,此日志文件只存在于innodb存储引擎下;
作用:
确保事务的 持久性 。redo日志记录事务执行后的状态,用来复原未写入data file的已胜利事务更新的数据。避免在产生故障的工夫点,尚有脏页未写入磁盘,在重启mysql服务的时候,依据redo log进行重做,从而达到事务的持久性这一个性。
各位大大,如果下面这段话如果看的不是很明确,能够持续往下看看呀,通过下文中事务的例子能够很好了解;
内容:
物理格局的日志,记录的是物理数据页面的批改的信息,简略说就是记录着xxx页做了xxx批改;
innodb 存储引擎提供了重做日志文件组(group),每个重做日志文件组蕴含着重做日志文件;默认是提供了一个重做日志文件组,文件组下蕴含两个大小雷同的重做日志文件;
innodb存储引擎的重做日志文件写入流程:先写重做日志文件1,当文件1被程序写满时,会切换到重做日志文件2,再当重做日志文件2也被写满时,会再切换到重做日志文件1中,顺次循环; 所以说重做日志文件是 循环笼罩写入的 。
因为重做日志是循环笼罩写入的,所以不能应用其进行整个数据库的数据恢复,它只能保障数据库宕机时的事务的完整性数据;如果想要复原全副数据的话,只能应用 binlog 二进制日志(归档日志)进行复原。
留神:大家能够手动批改重做日志文件组下的文件数量,并能够指定每个重做日志文件的大小,通过上面的参数:
- innodb_log_file_size 指定重做日志文件的大小
- innodb_log_files_in_group 重做日志文件组下的文件数量
扩大:
留神:重做日志文件的大小设置对于innodb存储引擎的性能有很大的影响。
重做日志文件不能设置的太大,也不能设置的太小;如果设置的太大,在数据库意外宕机后进行复原时会须要很长时间;
然而也不能设置的太小,因为设置的太小会导致一个事务的日志须要屡次切换重做日志文件进行写入,那么在笼罩掉之前的重做日志时,须要将要被笼罩的重做日志对应在内存中的脏页进行写盘(刷盘);
因为不写盘的话,如果重做日志被笼罩掉了,而后数据库意外宕机了,那么之前没有写盘的数据将没法在数据库重启时进行复原了,并且如果频繁的进行重做日志的笼罩的话,那么就会频繁的进行脏页刷盘,进而导致数据库性能的抖动。
那重做日志应该设置多大呢? 一般来说,redo log日志文件的全副大小,应该足够包容服务器一个小时的流动内容。
如果统计出一小时的重做日志写入量为 500M 的话,因为 redo log 日志文件默认有 2 个,所以须要设置 innodb_log_file_size=250M ;
留神:如果各位大大们对 脏页等名词 不太分明的话,能够通过《丁奇大佬 - MySQL实战45讲》、《mysql技术底细 innodb存储引擎》进行学习理解呀。
3、undo log 回滚日志:
留神 undo log 回滚日志的写入是在事务开始执行前就曾经开始了;
作用:
保证数据的原子性,保留了事务产生之前的数据的一个版本,能够用于回滚,同时能够提供多版本并发管制下的读(MVCC),也即非锁定读;
内容:
逻辑格局的日志,在执行undo的时候,仅仅是将数据从逻辑上复原至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。
比如说咱们要insert一条数据,那么undo log就会生成一条对应的delete日志,并且与以后事务的txid(事务惟一标识)进行了关联,用于反对回滚和MVCC;
像如果在一个事务中执行了多个蕴含update、insert、delete的语句时,因为事务具备原子性,如果其中一个语句执行失败,那么之前执行胜利的语句要就要被回滚撤销掉,此时就会依据以后事务txid在undo log中查找到保留的日志进行执行回滚;
留神:写入undo log 的这个操作也是须要记录到redo log重做日志中的;
为什么也要记录到redo log中呢? 举个场景,当事务在没执行完时mysql意外宕机了,那么在数据库重启后须要复原事务,如果事务须要回滚,然而你在内存中保留的undo log还没有写入磁盘,在宕机时就失落了,那么就会导致无奈回滚,就会呈现数据不统一的问题;而如果记录到了redo log中,则能够依据redo log进行重做,而后依据重做的undo log进行回滚。
扩大:
留神:为了晋升数据库性能,mysql都是在内存的缓冲区中记录日志,而后依据策略再进行刷盘的(将缓冲区记录的日志写入到磁盘中进行保留);
通过innodb存储引擎的架构图能够进行深刻理解:
如果想深刻学习,请参考此文章 你竟然还不晓得Mysql存储引擎InnoDB分为内存架构、磁盘架构?
MySql事务处理中三种日志承当的角色:
首先咱通过一个update语句的执行流程图展现出三种日志文件在事务处理中承当的角色! SQL语句如下:update T set c=c+1 where ID=2;
为什么流程图中没有undo log:
在流程图中能够看到redo log、binglog,那怎么没有undo log 呀,因为 undo log在 事务开始执行前 就曾经开始写入了 。
为什么上图事务中必须存在redo log 和 binlog呢:
首先,下面介绍这两种日志时,曾经说道了binlog 是mysql的server层保护的日志,次要用来做主从复制和数据备份复原应用;而redo log是InnoDB存储引擎独有的日志,是用来实现crash-safe能力;
crash-safe 是什么?
即在 InnoDB 存储引擎中,事务提交过程中任何阶段,MySQL忽然奔溃,重启后都能保障事务的完整性,已提交的数据不会失落,未提交残缺的数据会主动进行回滚。
为了实现crash-safe除了须要redo log外,还须要 undo log对未残缺的事务进行回滚的;
想要对crash-safe进行具体理解的大大们能够参考此文章:MySQL 的 crash-safe 原理解析
上图中处于prepare阶段、处于commit阶段是什么:
其实这是mysql的外部XA事务!俗称日志的两阶段提交协定!看到这大家是不是有点含糊了,据说过分布式XA事务,怎么还有外部XA事务呀?
其实大家晓得的分布式XA事务指的是mysql的内部XA事务;外部xa事务次要是mysql外部为了保障binlog与redo log之间数据的一致性而存在的,这也是由其架构决定的(binlog由mysql的server层提供反对,而redo log 则是由 innodb存储引擎层提供反对);
对mysql的架构不太熟悉的大大能够参考此文章:查问SQL的执行流程
binlog与redo log之间数据的一致性问题是什么:
因为redo log 和 binlog 都是用来"复原" 数据的,redo log是用来复原事务,保障事务的完整性的,而 binlog 是能够用来进行整体数据恢复,或基于某个工夫点进行复原的,并且用于主从复制;
如果在进行一个事务执行时,曾经实现了 redo log重做日志的写入,然而还没有写入binlog,此时数据库意外宕机了,如果没有保障两个日志 逻辑上统一 的话;
那么在数据库重启时会依据redo log进行事务复原,并将在事务中曾经解决好但未写盘的数据进行复原;然而因为binlog没有写入,所以会导致在应用binlog进行数据恢复时,或者是主从复制时,呈现数据不统一的状况;
如果保障了两个日志的逻辑统一的话,那么在应用redo log复原事务时,会判断binlog是否也写入胜利了,如果binlog也写入胜利,那么才会进行事务复原,否则将不进行事务复原,会应用undo log 进行回滚的;
MySql外部XA事务是什么呢:
外部XA事务就是将事务提交分为了两个阶段,prepare阶段和commit阶段!
prepare:写入redo log,并将回滚段置为prepared状态,此时binlog不做操作。
commit:innodb开释锁,开释回滚段,设置提交状态,写入binlog,而后存储引擎层提交。
扩大:
各位大大们,上图update的语句执行流程中,写入redo log重做日志,写入binglog二进制日志,其实都只是 先 写入到日志缓冲区中,前面还会波及到日志缓冲区中数据写入到具体磁盘中的日志文件中;那何时才会将缓冲区的日志数据写入到磁盘中?这是由mysql中的几个配置参数管制的;
缓冲区的日志写入到磁盘中的流程:
在介绍配置参数前,咱们先理解下缓冲区的日志写入到磁盘中的流程是什么样:
- 用户空间:是指用户程序运行的空间,例如mysql就运行在此空间内;
- 内核空间: 内核空间是指操作系统内核运行的空间,是为了保障操作系统内核的可能平安稳固地运行而为内核专门开拓的空间;
为什么须要内核空间呢?
次要是为了平安起见,不能让用户空间的程序间接去磁盘空间中读取数据,必须由经由内核空间通过DMA来获取;并且用户空间和内核空间两者之间是相互隔离的 。
redo log刷盘配置参数:
innodb_flush_log_at_trx_commit 配置参数用来管制重做日志刷新到磁盘的策略。
该参数的值存在三种:
- 0:示意事务提交时不进行写入重做日志擦操作,MySql会应用其后盾线程每一秒将日志缓冲区中的重做日志写入到 OS cache(磁盘缓存),同时立刻调用 fsync 操作将 OS cache 中的重做日志写入到磁盘文件中(刷盘);
- 1:示意在事务提交时就会进行重做日志的写入操作,实时的将日志缓冲区中的重做日志写入到 OS cache(磁盘缓存),同时立刻调用 fsync 操作将 OS cache 中的重做日志写入到磁盘文件中(刷盘); 此值为默认值 ,因为当设置值为1时能够保障事务的ACID中的持久性;
- 2:示意在事务提交时就会进行重做日志的写入操作,然而只是将日志缓冲区中的重做日志写入到 OS cache(磁盘缓存),不会立刻调用 fsync 操作进行刷盘,MySQL前面会被动将OS cache中的重做日志数据每秒批量进行一次刷盘; 抉择此值时,mysql的并发性最好,然而存在危险,当操作系统一旦宕机,会丢数据,然而如果MySql数据库宕机的话,则不会失落数据,因为数据保留在了OS cache中;
binlog 刷盘配置参数:
sync_binlog 配置参数用来管制二进制日志刷新到磁盘的策略。
该参数罕用的三种值:
- 0:示意在事务提交后,mysql会将日志缓冲区中的binlog数据写入到 OS cache(磁盘缓存),但并不会调用 fsync 操作进行刷盘,而是由操作系统本人管制它的缓存的刷盘; 此值为默认值 。
- 1:示意在事务提交时就会进行binlog的写入操作,实时的将日志缓冲区中的重做日志写入到 OS cache(磁盘缓存),同时立刻调用 fsync 操作将 OS cache 中的重做日志写入到磁盘文件中(刷盘);
- N:示意每次进行提交后都只是将日志缓冲区中的binlog数据写入到 OS cache(磁盘缓存),在进行N次事务提交当前,Mysql将执行一次fsync操作指令将OS cache中的binlog数据批量刷新到磁盘中; 留神 N 代表的是数值;
一道经典的面试题:
面试官:你有遇到过数据库宕机重启,事务失落的状况么?
咱们:其实这道题就是redo log、binlog的刷盘机会,下面曾经聊了这两种日志的全副刷盘机会了,大家能够两两联合进行答复就好了;
也能够间接参考此文中提供的答案进行答复:面试官:谈谈你对mysql事务的意识?
各位大大们,MySql中至关重要的三种日志就介绍到此啦;因为自己水品无限,如有问题请留言探讨呀!
♡ 点赞 + 评论 + 转发 哟
如果本文对您有帮忙的话,请挥动下您爱发财的小手点下赞呀,您的反对就是我一直创作的能源,谢谢啦!
您能够微信搜寻 【木子雷】 公众号,大量Java学习干货文章,您能够来瞧一瞧哟!