MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log

文章目录

  • 一、前言
    • 1.1 MySQL体系结构
    • 1.2 MySQL日志分类
    • 1.3 其他几种日志
      • 1.3.1 查询日志
      • 1.3.2 慢查询日志
      • 1.3.3 错误日志
  • 二、bin log 二进制日志
    • 2.1 bin log简介
    • 2.2 binlog日志格式
    • 2.3 日志删除
    • 2.4 写入/刷盘机制
  • 三、undo log 回滚日志
    • 3.1 undo log简介
    • 3.2 隐藏字段 —— 事务ID(TRX_ID)、ROLL_PTR
    • 3.3 版本链
  • 四、redo log 重做日志
    • 4.1 redo log详解
    • 4.2 redo log的写入过程、刷盘时机
    • 4.3 redo log file 的结构
    • 4.4 什么是 crash-save
    • 4.5 redo log细节
  • 五、补充
    • 5.1 binlog与redolog对比、逻辑日志与物理日志
    • 5.2 update语句的执行流程
    • 5.3 两阶段提交
    • 5.4 总结、使用场景
      • binlog的应用场景
      • undolog的使用场景
      • redolog的使用场景

MySQL作为最流行的开源数据库,其重要性不言而喻。日志是mysql数据库的重要组成部分,记录着数据库运行期间各种状态信息。常见的日志有以下几种:
在这里插入图片描述

作为开发,我们重点需要关注的是 二进制日志bin log(归档日志)事务日志redo log(重做日志)undolog(回滚日志),本文接下来会详细介绍这三种日志。

  • 二进制binlog(归档日志):是Server层生成的日志,主要用于数据备份和主从复制;
  • undolog(回滚日志):是Innodb存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和MVCC
  • 事务日志redolog(重做日志):是Innodb存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复

下面就带着这个问题,看看这三种日志是怎么工作的。

一、前言

1.1 MySQL体系结构

在这里插入图片描述
在这里插入图片描述

1)连接层

最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。

2)服务层

第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化,部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如过程、函数等。在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化如确定表的查询的顺序,是否利用索引等,最后生成相应的执行操作。如果是select语句,服务器还会查询内部的缓存,如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。

3)引擎层

存储引擎层,存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。数据库中的索引是在存储引擎层实现的。

4)存储层

数据存储层,主要是将数据(如: redolog、undolog、数据、索引、二进制日志、错误日志、查询日志、慢查询日志等)存储在文件系统之上,并完成与存储引擎的交互。

和其他数据库相比,MySQL有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎上,插件式的存储引擎架构,将查询处理和其他的系统任务以及数据的存储提取分离。这种架构可以根据业务的需求和实际需要选择合适的存储引擎。

其中slowlog、binlog、errorlog、relaylog归属于MySQL服务层;undolog、redolog归属于引擎层,为innodb所特有。

1.2 MySQL日志分类

MySQL有不同类型的日志:慢查询日志、通用查询日志、错误日志、事务日志、二进制日志等几大类,在MySQL8之后又新增了两种日志——中继日志、数据定义语句日志。其中比较重要的是二进制日志binlog (归档日志) 、事务日志redo log(重做日志) 和 undo log(回滚日志)。

MySQL日志主要包括八种

  • 慢查询日志(slow query log):记录所有执行时间超过long_query_time的所有查询,方便对查询进行优化
  • 通用查询日志(general log):记录索引连接的起始时间和终止时间,以及连接发送给数据库服务的所有指令,对复原操作的实际场景、发现问题、数据库操作的审计都有帮助
  • 二进制日志(bin log):记录所有更改数据的语句,用于主从服务器之间的数据同步、服务器遇到故障时数据的无损恢复
  • 错误日志(error log):记录MySQL服务的启动、运行或停止MySQL服务时出现的问题,方便了解服务器的状态,从而对服务器进行维护
  • 中继日志(relay log):用于主从服务器架构,从服务器用来存放主服务器二进制日志内容的一个中间件文件。从服务器通过读取中继日志的内容,来同步主服务器上的操作
  • 回滚日志(undo log):是Innodb存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和MVCC
  • 重做日志(redo log):是Innodb存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复
  • 数据定义语句日志:记录数据定义语句执行的元数据操作

除了二进制日志外,其他日志均为文本文件。默认情况下,所有日志均创建于MySQL数据目录中

1.3 其他几种日志

1.3.1 查询日志

查询日志中记录了客户端的所有操作语句(包括所有的增删改查、DDL、DML、DQL语句),而二进制日志不包含查询数据的SQL语句。默认情况下,查询日志是未开启的。如果需要开启查询日志,可以设置以下配置:
在这里插入图片描述
在这里插入图片描述

如果想要禁用查询日志,可将general_log设置为0,而后重启MySQL服务sudo systemctl restart mysql

1.3.2 慢查询日志

慢查询日志记录了所有执行时间超过参数 long_query_time 设置值并且扫描记录数不小于 min_examined_row_limit 的所有SQL语句的日志,默认未开启。long_query_time 默认为10秒,最小为0,精度可以到微秒。如果要开启慢查询日志,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:

# 开启MySQL慢日志查询开关
slow_query_log=1
# 执行时间参数,设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
long_query_time=2

在这里插入图片描述
在这里插入图片描述

同理,如果想要禁用慢查询日志,可将slow_query_log设置为0,而后重启MySQL服务sudo systemctl restart mysql

1.3.3 错误日志

错误日志是MySQL中最重要的日志之一,它记录了当mysqld启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。

该日志是默认开启的,默认存放目录/var/log/,默认的日志文件名为mysqld.log。查看日志位置:

-- 登录mysql,查看系统变量
show variables like '%log_error';

在这里插入图片描述

二、bin log 二进制日志

2.1 bin log简介

二进制日志(BINLOG)记录了所有的DDL(数据定义语言,创建库、表)语句和DML数据操纵语言,增删改)语句,但不包括数据查询(SELECT、SHOW)语句

作用:1.灾难时的数据恢复;2.MySQL的主从复制

  • binlog用于记录数据库执行的DDL、DML操作信息(不包括查询),以二进制的形式保存在磁盘中。binlog是mysql的逻辑日志,并且由Server层进行记录,使用任何存储引擎的mysql数据库都会记录binlog日志。
  • binlog是通过追加的方式进行写入的,可以通过max_binlog_size参数设置每个binlog文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。

在MySQL8版本中,默认二进制日志是开启着的,涉及到的参数如下:

show variables like '%log_bin';

在这里插入图片描述

常用的5.7版本可能只有以下参数:

mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.7.35    |
+-----------+
1 row in set (0.00 sec)

mysql> show variables like '%log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | OFF   |
| sql_log_bin   | ON    |
+---------------+-------+
2 rows in set (0.00 sec)

2.2 binlog日志格式

binlog日志有三种格式:分别为STATMENT、ROW和MIXED,具体格式及特点如下:

  • STATMENT:基于SQL语句的复制,每一条会修改数据的sql语句会记录到binlog中。
    • 优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,从而提高了性能;
    • 缺点:在某些情况下会导致主从数据不一致,比如执行sysdate()、sleep()等。
  • ROW:基于行的复制,不记录每条sql语句的上下文信息,仅需记录哪条数据被修改了。
    • 优点:不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题;
    • 缺点:会产生大量的日志,尤其是alter table的时候会让日志暴涨
  • MIXED:基于 STATMENT 和 ROW 两种模式的混合复制,一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog
日志格式含义
STATEMENT基于SQL语句的日志记录,记录的是SQL语句,对数据进行修改的SQL都会记录在日志文件中
ROW默认格式,基于行的日志记录,记录是每一行的数据变更
MIXED混合了STATEMENT和ROW两种格式,默认采用STATEMENT,在某些特殊情况下会自动切换为ROW进行记录
show variables like '%binlog_format%';

-- 如果想修改二进制日志格式
--  1.vim /etc/my.cnf
--  2.往文件内添加 binlog_format=STATEMENT
--  3.systemctl restart mysqld

在这里插入图片描述

具体日志格式详解

由于日志是以二进制方式存储的,不能直接读取,需要通过二进制日志查询工具mysqlbinlog来查看,具体语法:

mysqlbinlog [options] log-files

参数选项:
    -d, --database=name     指定数据库名称,只列出指定的数据库相关操作
    -o, --offset=#          忽略掉日志中的前n行命令
    -v, --verbose           将行事件(数据变更)重构为SQL语句
    -vv                     将行事件(数据变更)重构为SQL语句,并输出注释信息
    
    
mysqlbinlog -v binlog.00002

mysql中有score记录成绩,执行 update score set math = math + 1;

ROW格式下,执行mysqlbinlog -v binlog.00002,得到如下内容

在这里插入图片描述

STATEMENT格式下,执行mysqlbinlog binlog.00003,得到如下内容

在这里插入图片描述

2.3 日志删除

对于比较繁忙的业务系统,每天生成的binlog数据巨大,如果长时间不清除,将会占用大量磁盘空间。可以通过以下几种方式清理日志:

MySQL指令含义
reset master;删除全部binlog日志,删除之后,日志编号将从binlog.000001重新开始
purge master logs to ‘binlog.******’;删除******编号之前的所有日志
purge master logs before ‘yyyy-mm-dd hh24:mi:ss’;删除日志为“yyyy-mm-ddhh24:mi:ss"之前产生的所有日志

2.4 写入/刷盘机制

事务执行过程中,先把日志写入binlog cache,事务提交时,再把binlog cache写到binlog文件中。一个事务的binlog不能被拆开,确保一次性写入,系统将给每个线程分配一块内存作为binlog cache

对于InnoDB存储引擎而言,只有在事务提交时才会记录binlog,那么binlog什么时候才会将内存中的数据刷到磁盘呢?其实mysql是通过sync_binlog参数控制binlog的刷盘时机,取值范围是0-N【write和fsync的时机,由参数sync_binlog控制,默认为0】

  • 0:每次提交事务都只write,由系统自行判断什么时候执行fsync。虽然性能得到提升,但是机器宕机,page cache里的binlog会丢失(不去强制要求,由系统自行判断何时写入磁盘)
  • 1:每次提交事务都会执行fsync,如同redolog刷盘流程一样(每次commit的时候都要将binlog写入磁盘)
  • N:每次提交事务都write,但累计N个事务后才fsync(每N个事务,才会将binlog写入磁盘)

在出现IO瓶颈时,将sync_binlog设置成一个较大的值,能提升性能。同样的,若机器宕机会丢失最近N个事务的binlog日志

三、undo log 回滚日志

3.1 undo log简介

undo log(回滚日志):是Innodb存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和MVCC

它是InnoDB存储引擎在insert、update、delete的时候产生的便于数据回滚的日志。在数据更新之前,MySQL就需要先把更新前的数据记录到 undo log 日志中,当事务回滚时,可以利用 undo log 来进行回滚。作用包含两个——提供回滚、MVCC(多版本并发控制)。undo log主要分为两种:

  • insert undo log:当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除(因为这种log只是对本事务可见,其他事务不可见,所以当事务提交后,这种类型的undo log就会被系统直接删除回收,也就是该undo log占用的undo页面链表被释放)。
  • update undo log:update、delete的时候,产生的undo log日志不仅在事务回滚时需要,在快照读时也需要(也就是MVCC),所以不能在事务提交后马上删除,只在提交后放入undo log的链表,等待purge线程进行最后的删除。

事务需要保证原子性,也是说事务中的操作要么全部完成,要么什么也不做。如果事务执行到一半,出错了怎么办-回滚。但是怎么回滚呢,靠 undo 日志。undo 日志就是我们执行sql的逆操作

  • undo 日志有两个作用:提供回滚和多个行版本控制(MVCC)
  • 数据页里一行数据的格式 见3.3版本链,其中 roll_point 会指向一个undo 日志
  • undo 日志一般会在事务提交时被删除,但是如果 undo 日志为 MVCC 服务 则暂时保留
  • 一个事务会产生多个 undo 日志,mysql有专门的 undo 页 保存 undo 日志。innodb 会为每一个事务单独分配 undo 页链表(最多分配 4 个链表)

比如现在Tom的账户余额有100,现在有一个事务需要把Tom的账户余额更新为300,大致的流程如下图:

在这里插入图片描述

3.2 隐藏字段 —— 事务ID(TRX_ID)、ROLL_PTR

在这里插入图片描述

当我们创建了上面的这张表,我们在查看表结构的时候,就可以显式的看到 id、user_name、balance、wealth 这四个字段。 实际上除了这四个字段以外,InnoDB还会自动的给我们添加三个隐藏字段,分别是:

隐藏字段含义
DB_TRX_ID最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。
DB_ROLL_PTR回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本。
DB_ROW_ID隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。

而上述的前两个字段是肯定会添加的, 是否添加最后一个字段DB_ROW_ID,得看当前表有没有主键,如果有主键,则不会添加该隐藏字段。

3.3 版本链

不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。

在这里插入图片描述

然后,有四个并发事务同时在访问这张表。

在这里插入图片描述
在这里插入图片描述

四、redo log 重做日志

事务日志redo log(重做日志):是Innodb存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复。比如MySQL实例挂了或宕机了,重启时,InnoDB存储引擎会使用redo log恢复数据

  • redo log是物理日志,记录页的物理修改操作:在某个数据页做了什么修改,比如对x表空间中的N数据页ZZ偏移量的地方做了AAAA更新,每当执行一个事务就会产生这样的一条或者多条物理日志
  • 保证数据的持久性:redo log会在事务提交时将日志存储到磁盘redo log file,保证日志的持久性。同时mysql会将数据写入磁盘,保证数据的持久性【在事务提交时,只要先将redo log 持久化到磁盘即可,可以不需要等到将缓存在 Buffer Pool 里的脏页数据持久化到磁盘;当系统崩溃时,虽然脏页数据没有持久化,但是redo log已经持久化,接着MySQL重启后,可以根据redo log的内容,将所有数据恢复到最新的状态】

介绍下 缓冲池与数据页的概念

  • 缓冲池(buffer pool):主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度
  • 数据页(page):是InnoDB 存储引擎磁盘管理的最小单元,每个页的大小默认为 16KB。页中存储的是行数据

MySQL中数据是以页为单位,你查询一条记录,会从硬盘把一页的数据加载出来,加载出来的数据叫数据页,会放入到Buffer Pool中。后续的查询都是先从Buffer Pool中找,没有命中再去硬盘加载,减少硬盘IO开销,提升性能。

更新表数据的时候,也是如此,发现Buffer Pool里存在要更新的数据,就直接在Buffer Pool里更新。然后会把在某个数据页上做了什么修改记录到重做日志缓存(redo log buffer)里,接着刷盘到redo log文件里。同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面。

redo log的更新流程如下,以一次update操作为例

在这里插入图片描述

  1. 执行Update操作
  2. 先将原始数据读从磁盘读取到内存,修改内存中的数据。
  3. 生成一条重做日志写入redo log buffer ,纪录数据被修改后的值。
  4. 当事物提交时,需要将redo log buffer中的内容刷新到redo log file。
  5. 事物提交后,也会将内存中修改的数据写入到磁盘。

4.1 redo log详解

什么是 redo log?为了方便理解,先举个来自极客时间的例子:

还记得《孔乙己》这篇文章,饭店掌柜有一个粉板,专门用来记录客人的赊账记录。如果赊账的人不多,那么他可以把顾客名和账目写在板上。但如果赊账的人多了,粉板总会有记不下的时候,这个时候掌柜一定还有一个专门记录赊账的账本

如果有人要赊账或者还账的话,掌柜一般有两种做法:

  • 一种做法是直接把账本翻出来,把这次赊的账加上去或者扣除掉;
  • 另一种做法是先在粉板上记下这次的账,等打烊以后再把账本翻出来核算。

在生意红火柜台很忙时,掌柜一定会选择后者,因为前者操作实在是太麻烦了。首先,你得找到这个人的赊账总额那条记录。你想想,密密麻麻几十页,掌柜要找到那个名字,可能还得带上老花镜慢慢找,找到之后再拿出算盘计算,最后再将结果写回到账本上。

这整个过程想想都麻烦。相比之下,还是先在粉板上记一下方便。你想想,如果掌柜没有粉板的帮助,每次记账都得翻账本,效率是不是低得让人难以忍受?

为什么需要 redo log?

为什么需要写Redo Log Buffer 和 Redo Log Flle?而不是直接持久化到磁盘?

跟上述案例类似,在 MySQL 中,如果每一次的更新要写进磁盘,这么做会带来严重的性能问题:

  • 因为 Innodb 是以页为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这时将完整的数据页刷到磁盘的话,太浪费资源了!
  • 一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机 IO 写入性能太差

为了解决这个问题,MySQL 的设计者就用了类似掌柜粉板的思路来提升更新效率。这种思路在 MySQL 中叫 WAL(Write-Ahead Logging),意思就是:先写 redo log 日志,后写磁盘。日志和磁盘就对应上面的粉板和账本。

具体到 MySQL 是这样的:有记录需要更新,InnoDB 把记录写到 redo log 中,并更新内存中的数据页,此时更新就算完成。同时,后台线程会把操作记录更新异步到磁盘中的数据页。

PS:当需要更新的数据页在内存中时,就会直接更新内存中的数据页;不在内存中时,在可以使用 change buffer(篇幅有限,后面写文章再聊) 的情况下,就会将更新操作记录到 change buffer 中,并将这些操作记录到 redo log 中;如果此时有查询操作,则触发 merge 操作,返回更改后的记录值

有些人说 InnoDB 引擎把日志记录写到 redo log 中,redo log 在哪,不也是在磁盘上么?

对,这也是一个写磁盘的过程,但是与更新过程不一样的是,更新过程是在磁盘上随机 IO,费时。 而写 redo log 是在磁盘上顺序 IO,效率要高

PPS:redo log 的存在就是把全局的随机写,变换为局部的顺序写,从而提高效率

4.2 redo log的写入过程、刷盘时机

redo log 记录了事务对数据页做了哪些修改。它包括两部分:分别是内存中的日志缓冲(redo log buffer)和磁盘上的日志文件(redo log file)。

mysql 每执行一条 DML 语句,先将记录写入 redo log buffer,后续某个时间点再一次性将多个操作记录写到 redo log file。也就是我们上面提到的 WAL 技术。

计算机操作系统告诉我们:用户空间下的缓冲区数据是无法直接写入磁盘的。因为中间必须经过操作系统的内核空间缓冲区(OS Buffer)。

所以,redo log buffer 写入 redo logfile 实际上是先写入 OS Buffer,然后操作系统调用 fsync() 函数将日志刷到磁盘。过程如下:

在这里插入图片描述

mysql 支持三种将 redo log buffer 写入 redo log file 的时机,可以通过 innodb_flush_log_at_trx_commit 参数配置,各参数值含义如下:建议设置成1,这样可以保证MySQL 异常重启之后数据不丢失

参数值含义
0(延迟写)事务提交时不会将 redo log buffer 中日志写到 os buffer,而是每秒写入os buffer 并调用 fsync() 写入到 redo logfile 中。也就是说设置为0时 是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。
1(实时写、实时刷新)事务每次提交都会将 redo log buffer 中的日志写入 os buffer 并调用 fsync() 刷到 redo logfile 中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能差。
2(实时写、延迟刷新刷新)每次提交都仅写入到 os buffer,然后是每秒调用 fsync() 将 os buffer 中的日志写入到 redo log file。

4.3 redo log file 的结构

InnoDB 的 redo log 是固定大小的。比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么 redo log file 可以记录 4GB 的操作。从头开始写。写到末尾又回到开头循环写。如下图:

在这里插入图片描述

上图中,write pos 表示 redo log 当前记录的 LSN (逻辑序列号) 位置,一边写一遍后移,写到第 3 号文件末尾后就回到 0 号文件开头; check point 表示数据页更改记录刷盘后对应 redo log 所处的 LSN(逻辑序列号) 位置,也是往后推移并且循环的。

PS:check point 是当前要擦除的位置,它与数据页中的 LSN 应当是一致的

write pos 到 check point 之间的部分是 redo log 的未写区域,可用于记录新的记录;check point 到 write pos 之间是 redo log 已写区域,是待刷盘的数据页更改记录。

当 write pos 追上 check point 时,表示 redo log file 写满了,这时候有就不能执行新的更新。得停下来先擦除一些记录(擦除前要先把记录刷盘),再推动 check point 向前移动,腾出位置再记录新的日志。

4.4 什么是 crash-save

有了 redo log ,即在 InnoDB 存储引擎中,事务提交过程中任何阶段,MySQL 突然奔溃,重启后都能保证事务的完整性,已提交的数据不会丢失,未提交完整的数据会自动进行回滚。这个能力称为 crash-safe,依赖的就是 redo log 和 undo log 两个日志。

比如:重启 innodb 时,首先会检查磁盘中数据页的 LSN ,如果数据页的 LSN 小于日志中 check point 的 LSN ,则会从 checkpoint 开始恢复。

4.5 redo log细节

  • redo log是物理日志(并非sql执行语句 sql语句是逻辑操作),顺序写入,性能比较高
  • 重做日志是innodb存储引擎产生的
  • 重做日志由redo logo buffer和redo log file构成,即由 内存中的重做日志缓存、日志文件构成

五、补充

5.1 binlog与redolog对比、逻辑日志与物理日志

redo log 和 binlog 主要有三种不同:

  • redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
  • redo log 是物理日志(并非sql执行语句 sql语句是逻辑操作),记录的是在某个数据页上做了什么修改,比如"对XXX表空间中的YYY数据页ZZZ偏移量的地方做了AAA更新" ;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如 “给 ID=2 这一行的 age 字段加1”
  • redo log 是循环写的,空间固定会用完;binlog是可以追加写入的。追加写是指 binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

逻辑日志:可以简单理解为记录的就是sql语句

物理日志:因为mysql数据最终是保存在数据页中的,物理日志记录的就是数据页变更

5.2 update语句的执行流程

了解了binlog、redolog两种日志的概念,再来看看执行器和 InnoDB 引擎在执行 update 语句时的流程:

  • 执行器取 id = 2 的行数据。ID 是主键,引擎用树搜索找到这一行。如果这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,再返回。
  • 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。
  • 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。
  • 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
  • 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,redo log 会写入 binlog 的文件名和位置信息来保证 binlog 和 redo log 的一致性,更新完成。

整个过程如下图所示,其中橙色框表示是在 InnoDB 内部执行的,绿色框表示是在执行器中执行的:

在这里插入图片描述

5.3 两阶段提交

在执行更新语句过程中,会记录redolog、binlog两块日志,以基本的事务为单位。

redolog在事务执行过程中可以不断写入,binlog只在提交事务时写入

为了解决日志之间的逻辑一致问题,InnoDB存储引擎使用两阶段提交方案

在这里插入图片描述

由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完 redo log 再写 binlog,或者采用反过来的顺序。我们看看这两种方式会有什么问题。

仍然用前面的 update 语句来做例子。假设当前 id=2 的行,字段 age 的值是 22,再假设执行update 语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了 crash,会出现什么情况呢?

  1. 先写redo log 后写binlog。假设在redo log写完,binlog 还没有写完的时候,MySQL进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 age 的值是 22。

但是 binlog 没写完就 crash 了,这时 binlog 里面并没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。

等到需要用这个binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 age 值就是 22,与原库的值不同。

  1. 先写 binlog 后写 redo log。如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以 age 的值是 22。但是 binlog 里面已经记录了"把从 22 改成 23" 这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 age 的值就是 23,与原库的值不同。

所以,如果不使用"两阶段提交",数据库的状态就有可能和用 binlog 恢复出来的不一致。

另外:sync_binlog 这个参数建议设置成 1,表示每次事务的binlog都持久化到磁盘,这样可以保证 MySQL 异常重启之后 binlog 不丢失

5.4 总结、使用场景

  • 二进制binlog(归档日志):是Server层生成的日志,主要用于数据备份和主从复制;
  • undolog(回滚日志):是Innodb存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和MVCC
  • 事务日志redolog(重做日志):是Innodb存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复

binlog的应用场景

  • 主从复制:在Master端开启binlog,然后将binlog 发送到各个Slave端,Slave端重放binlog从而达到主从数据一致。
  • 数据恢复:通过使用mysqlbinlog工具来恢复数据。

undolog的使用场景

  • 事务回滚
  • MVCC

redolog的使用场景

掉电等故障恢复

redo log一旦提交意味着持久化了,但是有时候需要对其进行rollback操作,那就需要undo log

主从:写数据时只写主库,在读数据时只读从库,这样即使写请求会锁表或者锁记录,也不会影响读请求的执行;

参考:

MySQL面试题(最全、超详细)—— 定位慢查询、undo log与redo log

MVCC 原理分析、MySQL是如何解决幻读的

《MySQL》系列 - 十张图详解 MySQL 日志(建议收藏)

MySQL进阶(日志)——MySQL的日志 & bin log (归档日志) & 事务日志redo log(重做日志) & undo log(回滚日志)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/958891.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

electron打包客户端在rk3588上支持h265硬解

目录 前言 chromium是如何支持h265硬解 electron/chromium第一次编译 electron/chromium第二次编译 前言 我们的客户端程序是用electron打包的前端程序,其在rk3588主机上的linux环境运行。之前使用客户端查看h264编码的视频直播是没有问题的,但视频源…

关于CAN(FD)转以太网详细介绍

一、功能描述 CANFD 完全向下兼容 CAN ,以下统称 CAN(FD) 。 SG-CAN(FD)NET-210 是一款用来把 CANFD 总线数据转为网口数据的设备。 网口支持 TCP Sever 、 TCP Client 、 UDP Sever 、 UDP Client 四种模式。 可以通过软件配置和 Web 网页配置。 两路…

DRG_DIP 2.0时代医院程序结构转型与数据结构优化研究

一、引言 1.1 DRG_DIP 2.0 改革背景与意义 医保支付方式改革在医疗保障制度改革中占据着极为关键的地位,是推动医疗领域变革的核心力量。它犹如一把精准的手术刀,对医疗资源的合理分配、医疗服务质量的稳步提升以及医疗费用的有效控制起着决定性作用。在这一改革进程中,DR…

Arcgis国产化替代:Bigemap Pro正式发布

在数字化时代,数据如同新时代的石油,蕴含着巨大的价值。从商业决策到科研探索,从城市规划到环境监测,海量数据的高效处理、精准分析与直观可视化,已成为各行业突破发展瓶颈、实现转型升级的关键所在。历经十年精心打磨…

洛谷 B2031:计算三角形面积 ← 叉积

【题目来源】 https://www.luogu.com.cn/problem/B2031 【题目描述】 平面上有一个三角形,它的三个顶点坐标分别为 (x1, y1),(x2, y2),(x3, y3),那么请问这个三角形的面积是多少。 【输入格式】 输入仅一行,包括 6 个…

从 Spark 到 StarRocks:实现58同城湖仓一体架构的高效转型

作者:王世发,吴艳兴等,58同城数据架构部 导读: 本文介绍了58同城在其数据探查平台中引入StarRocks的实践,旨在提升实时查询性能。在面对传统Spark和Hive架构的性能瓶颈时,58同城选择StarRocks作为加速引擎&…

Kafak 单例生产者实现-C#操作

前面写了一篇入门操作的文章,因为工作需要,简单修改了下如何实现单例生产者。 Kafka入门-C#操作_c# kafka-CSDN博客文章浏览阅读1.6k次,点赞20次,收藏9次。2).报错:“kafka.zookeeper.ZooKeeperClientTimeoutException: Timed out waiting for connection while in state…

【GoLang】利用validator包实现服务端参数校验时自定义错误信息

在C/S架构下,服务端在校验请求参数时,若出现参数错误,要响应给客户端一个错误消息,通常我们会统一响应“参数错误”。 但是,如果只是一味的提示参数错误,我并不知道具体是哪个参数错了呀!能不能…

机器学习 vs 深度学习

目录 一、机器学习 1、实现原理 2、实施方法 二、深度学习 1、与机器学习的联系与区别 2、神经网络的历史发展 3、神经网络的基本概念 一、机器学习 1、实现原理 训练(归纳)和预测(演绎) 归纳: 从具体案例中抽象一般规律…

Unity git版本管理

创建仓库的时候添加了Unity的.gitignore模版,在这个时候就能自动过滤不需要的文件 打开git bash之后,步骤git版本管理-CSDN博客 如果报错,尝试重新进git 第一次传会耗时较长,之后的更新就很快了

【JWT】jwt实现HS、RS、ES、ED签名与验签

JWT 实现 HS、RS、ES 和 ED 签名与验签 签名方式算法密钥类型签名要点验签要点HSHMAC-SHA256对称密钥- 使用 crypto/hmac 和对称密钥生成 HMAC 签名- 将 header.payload 作为数据输入- 使用同一密钥重新计算 HMAC 签名- 比较计算结果与接收到的签名是否一致RSRSA-SHA256公钥 …

【Bug 记录】el-sub-menu 第一次进入默认不高亮

项目场景: 项目场景:el-sub-menu 第一次进入默认不高亮 问题描述 例如:sub-menu 的 index 后端默认传过来是 number,我们需要手动转为 string,否则会有警告,而且第一次进入 sub-menu 默认不高亮。 解决方…

LLM幻觉(Hallucination)缓解技术综述与展望

LLMs 中的幻觉问题(LLM 幻觉:现象剖析、影响与应对策略)对其可靠性与实用性构成了严重威胁。幻觉现象表现为模型生成的内容与事实严重不符,在医疗、金融、法律等对准确性要求极高的关键领域,可能引发误导性后果&#x…

挖掘机的市场现状和发展前景:全球增长潜力,重塑基础设施建设新篇章

引言:工程机械的心脏,挖掘机的崛起之路 在现代化建设的浪潮中,挖掘机作为工程机械领域的核心设备,正以其强大的作业能力和广泛的应用场景,成为推动全球基础设施建设不可或缺的力量。从高速公路到大型矿场,…

算法每日双题精讲 —— 二分查找(山脉数组的峰顶索引,寻找峰值)

🌟快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 🌟 别再犹豫了!快来订阅我们的算法每日双题精讲专栏,一起踏上算法学习的精彩之旅吧💪 在算法的…

Flutter_学习记录_基本组件的使用记录

1.TextWidge的常用属性 1.1TextAlign: 文本对齐属性 常用的样式有: TextAlign.center 居中TextAlign.left 左对齐TextAlign.right 有对齐 使用案例: body: Center(child: Text(开启 TextWidget 的旅程吧,珠珠, 开启 TextWidget 的旅程吧&a…

二叉树的存储(下)c++

链式存储 我们可以创建两个数组L[N]、r[N]&#xff0c;分别存储i 号结点的左右孩子的编号&#xff0c;这样就可以通过数组下标实现链式访问。 本质上还是孩子表示法&#xff0c;存储的是左右孩子的信息 #include <iostream>using namespace std;const int N 1e6 10; …

基于Docker的Kafka分布式集群

目录 1. 说明 2. 服务器规划 3. docker-compose文件 kafka{i}.yaml kafka-ui.yaml 4. kafka-ui配置集群监控 5. 参数表 6. 测试脚本 生产者-异步生产: AsyncKafkaProducer1.py 消费者-异步消费: AsyncKafkaConsumer1.py 7. 参考 1. 说明 创建一个本地开发环境所需的k…

Linux系统 C/C++编程基础——基于Qt的图形用户界面编程

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天周四了&#xff0c;距离除夕只有4天了&#xff0c;各位今年卫生都搞完了吗&#xff01;&#x1f606; 本文是接着昨天Linux 系统C/C编程的知识继续讲&#xff0c;基于Qt的图形用户界面编程概念及其命令&#xff0c;后续会不断…

C++11(二)

目录 左值引用与右值引用 左值引用 右值引用 右值与左值交叉引用 移动语义 移动构造 移动赋值 完美转发 本期我们将学习C11中比较重要的一个知识点------右值引用。 左值引用与右值引用 在学习左值引用和右值引用之前&#xff0c;我们得先知道什么是左值&#xff0…