有的时候博客内容会有变动,首发博客是最新的,其余博客地址可能会未同步,认准https://blog.zysicyj.top
这篇文章是从Github ReadMe拷贝的,内容实际下载是没问题的,可能失常发送短信,而且也不须要服务器,本地也能跑起来
首发博客地址
系列文章地址
上篇文章咱们介绍了一个查问语句的执行流程,并介绍了执行过程中波及的解决模块。一条查问语句的执行过程个别是通过连接器、分析器、优化器、执行器等功能模块,最初达到存储引擎。
那么,一条语句的更新流程是什么样的?
MySQL能够复原到半个月内任意一秒的状态,是怎么做到的?
咱们先温习下查问流程
这里咱们须要留神的是,更新语句的流程和查问流程有两个区别,更新流程波及两个重要的日志模块:
- redo log(重做日志)
- binlog(归档日志)
置信大家在这个面试,学习MySQL的过程中都重复听到这两个词
WAL技术
在MySQL中,WAL(Write-Ahead Logging)技术是一种罕用的长久化数据的机制,用于确保数据库的事务操作可能长久化到磁盘并保持数据的一致性。WAL技术的核心思想是在事务进行批改之前,先将批改操作记录到日志中,而后再将批改利用到数据库中。
具体来说,MySQL中的WAL技术次要包含以下几个组件和步骤:
- Redo Log(重做日志):Redo Log是一种事务日志,用于记录数据库中产生的批改操作。在事务提交之前,MySQL会将批改操作写入Redo Log,而不是间接写入磁盘。这样能够进步性能,因为磁盘写入是绝对较慢的操作。
- Write-Ahead Logging(预写式日志):WAL技术要求在事务提交之前,Redo Log必须先写入磁盘,而后再将批改操作利用到数据库中。这样即便在事务提交后产生零碎解体,MySQL也能够通过Redo Log来复原数据。
- Redo Log Buffer(重做日志缓冲区):Redo Log Buffer是一个内存缓冲区,用于暂存待写入Redo Log的批改操作。当事务提交时,Redo Log Buffer中的内容会被刷新到磁盘的Redo Log文件中。
- Checkpoint(检查点):Checkpoint是一个标记点,示意在这个点之前的所有事务曾经长久化到磁盘。MySQL会定期将Checkpoint的地位更新到磁盘,以确保曾经长久化的数据不会失落。
- Crash Recovery(解体复原):当数据库产生解体或重启时,MySQL会通过读取Redo Log来复原数据的一致性。它会依照Redo Log中的程序,将每个事务的批改操作从新利用到数据库中,以还原数据的最新状态。
WAL技术的长处是能够进步数据库的性能和可靠性。通过将批改操作先记录到Redo Log中,能够防止频繁地写入磁盘,从而进步性能。同时,WAL技术还能够确保数据的持久性和一致性,即便在零碎解体或断电的状况下也可能复原数据。
MySQL中的WAL技术通过应用Redo Log和预写式日志的机制,确保事务的批改操作可能长久化到磁盘并保持数据的一致性。它是一种进步性能和可靠性的重要技术。
Redo log执行流程
- 当一个事务开始时,MySQL会为该事务调配一个惟一的事务ID,并将该事务的相干信息存储在内存中的事务管制块(Transaction Control Block,TCB)中。
- 在事务执行过程中,所有的批改操作都会被写入redo log缓冲区。这些批改操作包含插入、更新和删除等操作。
- 当事务提交时,MySQL会将该事务的所有批改操作依照程序写入redo log文件中。这些批改操作会被写入到redo log缓冲区,而后通过后盾线程定期将缓冲区中的内容刷新到磁盘上的redo log文件中。这个过程称为redo log的刷新。
- 在事务提交之前,MySQL会将redo log的刷新操作和数据页的刷新操作进行协调,以保证数据的一致性。这是通过应用write-ahead logging(预写式日志)的机制来实现的。即在事务提交之前,redo log必须先写入磁盘,而后再将批改操作利用到数据库中。
- 当数据库产生解体或重启时,MySQL会在启动过程中读取redo log文件,并将其中的批改操作从新利用到数据库中,以复原数据的一致性。这个过程称为解体复原。
Write Pos和CheckPoint
在MySQL的redo log中,有两个重要的概念:write pos(写入地位)和checkpoint(检查点)。
- Write Pos(写入地位):Write Pos是指以后事务写入redo log的地位。当一个事务提交时,其批改操作会被写入redo log中的某个地位,Write Pos指向这个地位。下一个事务的批改操作将会从Write Pos指向的地位开始写入。
- Checkpoint(检查点):Checkpoint是指一个标记点,示意在这个点之前的所有事务曾经长久化到磁盘。当一个事务提交时,它的批改操作会被写入redo log,并且会更新Checkpoint的地位。这样,在Checkpoint之前的redo log中的操作能够被认为是曾经长久化到磁盘的。
Checkpoint的作用是用于数据库的复原和解体复原。当数据库产生解体或重启时,MySQL会从Checkpoint的地位开始,读取redo log中的操作,并将其利用到数据库中,以还原数据的一致性。
Write Pos和Checkpoint之间的关系是,Write Pos会一直向前挪动,指向最新的写入地位,而Checkpoint会依据肯定的策略进行更新,以标记曾经长久化到磁盘的操作。
须要留神的是,Write Pos和Checkpoint的地位是绝对于redo log文件的偏移量,而不是相对的字节地位。它们的值通常以字节为单位,示意绝对于redo log文件起始地位的偏移量。
Write Pos示意以后事务写入redo log的地位,Checkpoint示意曾经长久化到磁盘的操作的地位。Write Pos会一直向前挪动,而Checkpoint会依据肯定的策略进行更新,用于数据库的复原和解体复原。
Redo log是固定大小的,超出会产生什么
当redo log的固定大小不足以包容新的批改操作时,MySQL会触发一个称为"redo log空间有余"的谬误。在这种状况下,MySQL会进行新的事务提交,直到有足够的空间来写入redo log。
为了解决redo log空间有余的问题,能够采取以下几种办法:
- 减少redo log的大小:能够通过批改MySQL的配置参数
innodb_log_file_size
来减少每个redo log文件的大小。减少redo log的大小能够提供更多的空间来存储批改操作,从而缩短redo log的使用寿命。 - 减少redo log文件的数量:能够通过批改MySQL的配置参数
innodb_log_files_in_group
来减少redo log文件组中的文件数量。减少文件数量能够减少redo log的总大小,从而提供更多的空间来存储批改操作。 - 提交事务并清空redo log:如果以后的事务曾经提交,但redo log空间有余,能够尝试手动提交其余未提交的事务,以开释redo log空间。这能够通过执行
COMMIT
语句来提交事务。 - 优化事务的写入操作:能够通过优化事务的写入操作,缩小对redo log的写入量。例如,能够合并多个小事务为一个大事务,缩小redo log的写入次数。
须要留神的是,减少redo log的大小或数量可能会减少零碎的负载和解体复原的工夫。因而,在调整redo log大小时,须要综合思考零碎的性能和可靠性需要,并进行充沛的测试和验证。
什么是binlog日志
Binlog(二进制日志)是MySQL的服务器层产生的一种日志,用于记录数据库中的所有批改操作,包含数据定义语言(DDL)和数据操作语言(DML)等操作。
Binlog以二进制格局记录了对数据库的逻辑批改操作,而不是间接记录对数据页的具体批改。它蕴含了一系列的事件(Event),每个事件都代表了一个数据库操作,如插入、更新、删除等。
Binlog的次要作用是用于数据复制和复原。通过将Binlog传递给其余MySQL实例,能够实现数据的复制和同步。其余MySQL实例能够读取Binlog中的事件,并将其中的批改操作利用到本人的数据库中,从而实现数据的复制和同步。
此外,Binlog也能够用于数据恢复。在误操作、数据失落或劫难复原的状况下,能够通过读取Binlog来还原数据。通过一一回放Binlog中的事件,能够将数据库复原到特定的工夫点或特定的操作之前的状态。
Binlog是追加写入的,不会被重复使用,以保留残缺的批改历史。它能够通过配置参数进行启用和配置,包含指定Binlog的存储地位、设置Binlog的大小和保留工夫等。
为什么MySQL会有两个日志,redo log和binlog?
MySQL之所以同时应用redo log和binlog两个日志,是因为它们具备不同的性能和用处。
Redo Log(重做日志):
- 性能:Redo log是InnoDB存储引擎特有的日志,用于保障事务的持久性和一致性。它记录了数据库中产生的批改操作,包含插入、更新和删除等操作。
- 作用:在数据库解体或重启时,通过读取redo log来复原数据的一致性。它能够将未长久化到磁盘的批改操作从新利用到数据库中,以还原数据的最新状态。
- 特点:redo log是物理日志,记录了对数据页的具体批改操作。它是循环写入的,能够重复使用,以缩小磁盘IO的开销。
Binlog(二进制日志):
- 性能:Binlog是MySQL的服务器层产生的日志,记录了数据库中的所有批改操作,包含数据定义语言(DDL)和数据操作语言(DML)等操作。
- 作用:Binlog次要用于数据复制和复原。它能够被其余MySQL实例读取,并将其中的批改操作利用到本人的数据库中,实现数据的复制和同步。同时,Binlog也能够用于数据恢复,例如在误操作或数据失落时,能够通过读取Binlog来还原数据。
- 特点:Binlog是逻辑日志,记录了对数据的逻辑批改操作。它是追加写入的,不会被重复使用,以保留残缺的批改历史。
redo log保障了事务的持久性和一致性,而binlog则提供了数据复制和复原的性能。它们独特工作,确保了MySQL数据库的数据安全和可靠性。
举一个例子
mysql> update T set c=c+1 where ID=2;
- 执行器先找引擎取 ID=2 这一行。ID 是主键,引擎间接用树搜寻找到这一行。如果 ID=2 这一行所在的数据页原本就在内存中,就间接返回给执行器;否则,须要先从磁盘读入内存,而后再返回。
- 执行器拿到引擎给的行数据,把这个值加上 1,比方原来是 N,当初就是 N+1,失去新的一行数据,再调用引擎接口写入这行新数据。
- 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 外面,此时 redo log 处于 prepare 状态。而后告知执行器执行实现了,随时能够提交事务。
- 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
- 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新实现。
最初三步看上去有点“绕”,将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。
MySQL中的两阶段提交
在MySQL中,redo log和binlog是两个不同的日志文件,它们都用于确保数据的一致性和持久性。它们的写入程序和提交程序有所不同。
Redo Log(重做日志):
- Redo log是MySQL用于解体复原的机制,它记录了事务对数据库所做的批改操作。
- 当事务执行时,MySQL首先将批改操作记录到redo log中,而后将其写入磁盘。
- 这样做的目标是为了在零碎解体时,可能通过redo log来复原未实现的事务,保证数据的一致性。
Binlog(二进制日志):
- Binlog是MySQL用于数据复制和复原的机制,它记录了数据库的批改操作。
- 当事务提交时,MySQL将批改操作记录到binlog中,但不立刻写入磁盘。
- Binlog的写入是异步的,可能会有肯定的提早。
当初来解释为什么MySQL先写redo log,而后等binlog写完后才提交:
事务的持久性和恢复能力:
- 通过将批改操作记录到redo log中,MySQL能够确保即便零碎解体,也可能通过redo log来复原未实现的事务,保证数据的一致性。
- 因而,redo log的写入是在事务执行期间进行的,以提供更好的性能。
数据复制和复原:
- Binlog用于数据复制和复原,它记录了所有的数据库批改操作。
- 在事务提交之后,MySQL将批改操作记录到binlog中,以供主从复制等场景应用。
- 为了保证数据的一致性,MySQL会期待binlog的写入实现,而后才提交事务。
所以,MySQL先写redo log,而后等binlog写完后才提交的目标是为了保证数据的一致性和持久性,并提供数据复制和复原的能力。这样的设计能够进步性能,并确保在零碎解体或数据复制场景下的数据完整性。心愿这次解释更加清晰明了。如果还有任何疑难,请随时发问。
没写完产生Crash了会呈现什么状况?
依然用后面的 update 语句来做例子。假如以后 ID=2 的行,字段 c 的值是 0,再假如执行 update 语句过程中在写完第一个日志后,第二个日志还没有写完期间产生了 crash,会呈现什么状况呢?
- 先写 redo log 后写 binlog。假如在 redo log 写完,binlog 还没有写完的时候,MySQL 过程异样重启。因为咱们后面说过的,redo log 写完之后,零碎即便解体,依然可能把数据恢复回来,所以复原后这一行 c 的值是 1。然而因为 binlog 没写完就 crash 了,这时候 binlog 外面就没有记录这个语句。因而,之后备份日志的时候,存起来的 binlog 外面就没有这条语句。而后你会发现,如果须要用这个 binlog 来复原长期库的话,因为这个语句的 binlog 失落,这个长期库就会少了这一次更新,复原进去的这一行 c 的值就是 0,与原库的值不同。
- 先写 binlog 后写 redo log。如果在 binlog 写完之后 crash,因为 redo log 还没写,解体复原当前这个事务有效,所以这一行 c 的值是 0。然而 binlog 外面曾经记录了“把 c 从 0 改成 1”这个日志。所以,在之后用 binlog 来复原的时候就多了一个事务进去,复原进去的这一行 c 的值就是 1,与原库的值不同。
能够看到,如果不应用“两阶段提交”,那么数据库的状态就有可能和用它的日志复原进去的库的状态不统一。
本文由mdnice多平台公布