硬核干货,带你一文掌握 MySQL 的binlog 、redo log、undo log

news2024/12/24 14:19:33

​hello,大家好。

在MySQL 中我们经常会接触到三个核心日志,它们分别是:binlog 、redo log、undo log。

好多同学对于它们可能并不陌生,但是具体区分起来各自的功能用途以及实现原理,那可能认知就会比较模糊了,今天就跟大家一起,来清晰明了的介绍一下这些日志的核心思想和功能原理。

1 binlog

1.1 binlog 设计目标

binlog 记录了对MySQL数据库执行更改的所有的写操作,包括所有对数据库的数据、表结构、索引等等变更的操作。

注意:这其中不包含SELECT、SHOW等,因为对数据没有修改

只要是对数据库有变更的操作都会记录到binlog里面来,我们可以把数据库的数据看做银行账户里的余额,而binlog就相当于我们银行卡的流水记录。账户余额只是一个结果,至于这个结果怎么来的,那就必须得看流水了。

在实际应用中, binlog 的主要应用场景分别是 主从复制 和 数据恢复。

  1. 主从复制 :在 Master 端开启 binlog ,然后将 binlog 发送到各个 Slave 端, Slave 端重放 binlog 来达到主从数据一致。

  2. 数据恢复 :通过使用 mysqlbinlog 工具来恢复数据。

1.2 binlog 数据格式

binlog 日志有三种格式,分别为 STATMENT 、 ROW 和 MIXED。

在 MySQL 5.7.7 之前,默认的格式是 STATEMENT , MySQL 5.7.7 之后,默认值是 ROW。日志格式通过 binlog-format 指定。

  • ROW:基于行的复制(row-based replication, RBR),不记录每条SQL语句的上下文信息,仅需记录哪条数据被修改了。如果一个update语句修改一百行数据,那么这种模式下就会记录100行对应的记录日志。

  • 优点:不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题;

  • 缺点:会产生大量的日志,尤其是 alter table 的时候会让日志暴涨。

  • STATMENT:基于SQL语句的复制( statement-based replication, SBR ),每一条会修改数据的SQL语句会记录到 binlog 中 。相对于ROW模式,STATEMENT模式下只会记录这个 update 的语句,所以此模式下会非常节省日志空间,也避免着大量的IO操作。

  • 优点:不需要记录每一行的变化,减少了 binlog 日志量,节约了 IO , 从而提高了性能;

  • 缺点:在某些情况下会导致主从数据不一致,比如执行sysdate() 、 slepp() 等 。

  • MIXED:基于 STATMENT 和 ROW 两种模式的混合复制(mixed-based replication, MBR),一般的复制使用 STATEMENT 模式保存 binlog ,对于一些函数,STATEMENT 模式无法复制的操作使用 ROW 模式保存 binlog。

基于这三种模式需要注意的是:

1)使用 row 格式的 binlog 时,在进行数据同步或恢复的时候不一致的问题更容易被发现,因为它是基于数据行记录的。

2)使用 mixed 或者 statement 格式的 binlog 时,很多事务操作都是基于SQL逻辑记录,我们都知道一个SQL在不同的时间点执行它们产生的数据变化和影响是不一样的,所以这种情况下,数据同步或恢复的时候就容易出现不一致的情况。

1.3 binlog 写入策略

对于 InnoDB 存储引擎而言,在进行事务的过程中,首先会把binlog 写入到binlog cache中(因为写入到cache中会比较快,一个事务通常会有多个操作,避免每个操作都直接写磁盘导致性能降低),只有在事务提交时才会记录 biglog ,此时记录还在内存中,那么 biglog 是什么时候刷到磁盘中的呢?

MySQL 其实是通过 sync_binlog 参数控制 biglog 的刷盘时机,取值范围是 0-N:

  • 0:每次提交事务binlog不会马上写入到磁盘,而是先写到page cache。不去强制要求,由系统自行判断何时写入磁盘,在Mysql 崩溃的时候会有丢失日志的风险;

  • 1:每次提交事务都会执行 fsync 将 binlog 写入到磁盘;

  • N:每次提交事务都先写到page cach,只有等到积累了N个事务之后才 fsync 将 binlog 写入到磁盘,在 MySQL 崩溃的时候会有丢失N个事务日志的风险。

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

2、redo log

2.1 redo log 设计目标

redo log 是属于引擎层(innodb)的日志,称为重做日志 ,当MySQL服务器意外崩溃或者宕机后,保证已经提交的事务持久化到磁盘中(持久性)。

它能保证对于已经COMMIT的事务产生的数据变更,即使是系统宕机崩溃也可以通过它来进行数据重做,达到数据的持久性,一旦事务成功提交后,不会因为异常、宕机而造成数据错误或丢失。

2.2 redo log 数据格式

redo log 包括两部分:

  • 内存中的日志缓冲(redo log buffer)

  • 内存层面,默认16M,通过innodb_log_buffer_size参数可修改

  • 磁盘上的日志文件(redo logfile)

  • 持久化的,磁盘层面

MySQL 每执行一条 DML 语句,先将记录写入 redo log buffer,后续某个时间点再一次性将多个操作记录写到 redo log file。

通常所说的Write-Ahead Log(预先日志持久化)指的是在持久化一个数据页之前,先将内存中相应的日志页持久化。

在计算机操作系统中,用户空间( user space )下的缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统内核空间( kernel space )缓冲区( OS Buffer )。

因此, redo log buffer 写入 redo logfile 实际上是先写入 OS Buffer ,然后再通过系统调用 fsync() 将其刷到 redo log file中,过程如下:

修改数据的操作流程:

  1. 先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝,产生脏数据

  2. 生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值

  3. 默认在事务提交后将redo log buffer中的内容刷新到redo log file,对redo log file采用追加写的方式

  4. 定期将内存中修改的数据刷新到磁盘中(这里说的是那些还没及时被后台线程刷盘的脏数据)

2.3 关于 redo log 的几点疑惑

读到这里,相必有同学会有如下疑问:

Q1:为什么不直接修改磁盘中的数据?

因为直接修改磁盘数据的话,它是随机IO,修改的数据分布在磁盘中不同的位置,需要来回的查找,所以命中率低,消耗大,而且一个小小的修改就不得不将整个页刷新到磁盘,利用率低;

与之相对的是顺序IO,磁盘的数据分布在磁盘的一块,所以省去了查找的过程,节省寻道时间。

使用后台线程以一定的频率去刷新磁盘可以降低随机IO的频率,增加吞吐量,这是使用buffer pool的根本原因。

Q2:同为操作数据变更的日志,有了binlog为什么还要redo log?

我认为最核心的一点就是两者记录的数据变更粒度是不一样的。

以修改数据为例,binlog 是以表为记录主体,在ROW模式下,binlog保存的表的每行变更记录。

MySQL 是以页为单位进行刷盘的,每一页的数据单位为16K,所以在刷盘的过程中需要把数据刷新到磁盘的多个扇区中去。而把16K数据刷到磁盘的每个扇区里这个过程是无法保证原子性的,如果数据库宕机,那么就可能会造成一部分数据成功,而一部分数据失败的情况。而通过 binlog 这种级别的日志是无法恢复的,因为一个update可能更改了多个磁盘区域的数据,所以这个时候得需要通过redo log这种记录到磁盘数据级别的日志进行数据恢复。

​由以上两者的对比可知:binlog 日志只用于归档,只依靠 binlog 是没有 crash-safe 能力的。

同样只有 redo log 也不行,因为 redo log 是 InnoDB特有的,且日志上的记录落盘后会被覆盖掉。因此需要 binlog和 redo log二者同时记录,才能保证当数据库发生宕机重启时,数据不会丢失。

Q3:redo log一定能保证事务的持久性吗?

不一定,这要根据redo log的刷盘策略决定,因为redo log buffer同样是在内存中,如果提交事务之后,redo log buffer还没来得及将数据刷新到redo log file进行持久化,此时发生宕机照样会丢失数据。

那该如何解决呢?刷盘写入策略。

2.4 redo log 写入策略

当redo log空间满了之后又会从头开始以循环的方式进行覆盖式的写入。MySQL 支持三种将 redo log buffer 写入 redo log file 的时机,可以通过 innodb_flush_log_at_trx_commit 参数配置,各参数含义如下:

  • 0(延迟写):表示每次事务提交时都只是把 redo log 留在 redo log buffer 中,开启一个后台线程,每1s刷新一次到磁盘中 ;

  • 1(实时写,实时刷):表示每次事务提交时都将 redo log 直接持久化到磁盘,真正保证数据的持久性;

  • 2(实时写,延迟刷):表示每次事务提交时都只是把 redo log 写到 page cache,具体的刷盘时机不确定。

除了上面几种机制外,还有其它两种情况会把redo log buffer中的日志刷到磁盘。

  • 定时处理:有线程会定时(每隔 1 秒)把redo log buffer中的数据刷盘。

  • 根据空间处理:redo log buffer 占用到了一定程度( innodb_log_buffer_size 设置的值一半)占,这个时候也会把redo log buffer中的数据刷盘。

3、undo log

3.1 undo log设计目标

redo log 是也属于引擎层(innodb)的日志,从上面的redo log介绍中我们就已经知道了,redo log 和undo log的核心是为了保证innodb事务机制中的持久性和原子性,事务提交成功由redo log保证数据持久性,而事务可以进行回滚从而保证事务操作原子性则是通过undo log 来保证的。

原子性 是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。

undo log 的主要应用场景分别:

  1. 事务回滚 :前面提到过,后台线程会不定时的去刷新buffer pool中的数据到磁盘,但是如果该事务执行期间出现各种错误(宕机)或者执行rollback语句,那么前面刷进去的操作都是需要回滚的,保证原子性,undo log就是提供事务回滚的。

  2. MVCC:当读取的某一行被其他事务锁定时,可以从undo log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据——快照读。

3.2 undo log 数据格式

undo log 数据主要分两类:

  • insert undo log

insert 操作的记录,只对事务本身可见,对其他事务不可见(这是事务隔离性的要求),故该undo log可以在事务提交后直接删除,不需要进行purge操作。

  • update undo log

update undo log记录的是对delete和update操作产生的undo log。该undo log可能需要提供MVCC机制,因此不能在事务提交时就进行删除。提交时放入undo log链表,等待purge线程进行最后的删除。

在InnoDB存储引擎中,undo log使用rollback segment回滚段进行存储,每隔回滚段包含了1024个undo log segment。MySQL5.5之后,一共有128个回滚段。即总共可以记录128 * 1024个undo操作。

每个事务只会使用一个回滚段,一个回滚段在同一时刻可能会服务于多个事务。

3.3 undo log 操作实例

1、首先准备一张原始原始数据表(user_info)

对于InnoDB引擎来说,每个行记录除了记录本身的数据之外,还有几个隐藏的列:

  • DB_ROW_ID∶记录的主键id。

  • DB_TRX_ID:事务ID,当对某条记录发生修改时,就会将这个事务的Id记录其中。

  • DB_ROLL_PTR︰回滚指针,版本链中的指针。

2、开启一个事务A

对 user_info 表执行如下SQL:

update user_info set name =“李四”where id=1 复制代码

将会进行如下流程操作:

1、首先获得一个事务编号 104

2、把user_info表修改前的数据拷贝到undo log

3、修改user_info表 id=1的数据

4、把修改后的数据事务版本号改成 当前事务版本号,并把DB_ROLL_PTR 地址指向undo log数据地址。

3、最后执行结束

结果如下所示:

​可以发现每次对数据的变更都会产生一个undo log,当一条记录被变更多次时,那么就会产生多条undo log,undo log记录的是变更前的日志,并且每个undo log的序号是递增的,那么当要回滚的时候,按照序号依次向前推,就可以找到我们的原始数据了。

总结

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

它的设计目标是支持innodb的“事务”的特性,事务ACID特性分别是原子性、一致性、隔离性、持久性, 一致性是事务的最终追求的目标,隔离性、原子性、持久性是达成一致性目标的手段,根据的之前的介绍我们已经知道隔离性是通过锁机制来实现的,而事务的原子性和持久性则是通过redo log 和undo log来保障的。

写入策略

事务执行过程中,先把日志写到bin log cache ,事务提交的时候,再把binlog cache写到binlog文件中。因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。

​binlog vs redo log

  • redo log 物理日志:记录内容是“在xx数据页做了xx修改”,属于InnoDB存储引擎层产生的。

  • binlog 逻辑日志:记录内容是语句的原始逻辑,类似于给ID=2这一行的c字段加1,属于服务层。

两个侧重点也不同, redo log让InnoDB有了崩溃恢复的能力,binlog保证了MySQL集群架构的数据一致性。

在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的写入时机不一样。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Web前端开发技术课程大作业_ 关于美食的HTML网页设计——HTML+CSS+JavaScript在线美食订餐网站html模板源码30个页面_

👨‍🎓静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计👩‍🎓,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等,用的最多的还是DW,当然不同软件写出的…

Git基础|配置Git账号信息,Git存储的原理详解【建议收藏】

Git作为分布式版本管理,就需要对用户进行认证,账号名和邮箱,方便开发者从不同的电脑进行登录。同时,要想真的记住Git的命令,也必须要清楚Git的存储、上传原理。 Git基础2一、用户签名1、打开命令界面2、进入到用户管理…

CleanMyMac2023最新版软件功能及使用心得教程

电脑明明有100G,但是只剩下几个G,明明已经清理了很多,但是还是没有释放出内存,怎么办?可以试试CleanMyMac X,怎么使用呢?来看看吧!CleanMyMac X是一款颇受欢迎的专业清理软件&#x…

【2022.12.10】备战春招Day5——每日一题 + 96. 不同的二叉搜索树

【每日一题】1691. 堆叠长方体的最大高度 题目描述 给你 n 个长方体 cuboids ,其中第 i 个长方体的长宽高表示为 cuboids[i] [widthi, lengthi, heighti](下标从 0 开始)。请你从 cuboids 选出一个 子集 ,并将它们堆叠起来。 如…

​创新不是公司的救命良药

阅读本文大概需要1.06 分钟。之前问说当整个大环境都差的时候,公司还有项目可做就不错了,不要觉得只能赚点小钱就看不上,现在已经从伸手抓钱,变成弯腰捡钱的时代了。 开始赚的钱是不多,但能验证方向,先把跑…

web前端期末大作业 基于HTML+CSS+JavaScript学生宿舍管理系统

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

SSM+Mysql实现的仿网盘系统(功能包含注册登录,文件上传、所有文件、分类资源查看、用户管理、分享资源等)

博客目录SSMMysql实现的仿网盘系统实现功能截图系统功能使用技术代码完整源码SSMMysql实现的仿网盘系统 本系统是一个模拟百度网盘的系统,通过实现了图片/文本文件/视频等资源上传,并且分类管理、资源分享,实现了资源的在线管理。 (文末查看…

Vue2.0开发之——Vue组件-组件属性(34)

一 概述 为Count组件添加自定义属性为自定义属性添加v-bind自定义属性props是只读的自定义属性default默认值自定义属性type值类型自定义属性required必填值 二 为Count组件添加自定义属性 2.1 组件的props props 是组件的自定义属性,在封装通用组件的时候&#…

【Vue核心】6.数据代理

1.回顾Object.defineProperty方法 Object.defineproperty Object.defineproperty 的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性。Object.defineproperty方法需要传递3个参数,1.属性所在的对象 2.属性的名字 3.一个描述符对象…

Wireshark TS | PMTU 问题实例

前言 PMTU,说到网络上的 PMTU 所能实现的功能,网工对它的原理自然是如数家珍,不熟悉的可能就感觉高大上了,觉得路径 MTU 能自动发现了,自然端到端数据包传输就能避免数据包分片了。可是理想很丰满,现实很骨…

防火墙NAT综合实验——nat控制,豁免,远程,DMZ区域(带命令)

作者简介:一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.实验 实验要求 实验命令 前言 本章将会进行NAT的综合配置…

编程零基础转行Python,往这个方向走,绝对没有错

近几年Python的受欢迎程度可谓是扶摇直上,当然了学习的人也是愈来愈多。一些学习Python的小白在学习初期,总希望能够得到一份Python学习路线图,小编经过多方汇总为大家汇总了一份Python学习路线图。 对于一个零基础的想学习python的朋友来说…

对造轮子Say NO!如何移植并使用Linux内核的通用链表?(附源代码)

1. 什么是链表 链表是一种常用的组织有序数据的数据结构,它通过指针将一系列数据节点连接成一条数据链,是线性表的一种重要实现方式。 相对于数组,链表具有更好的动态性,建立链表时无需预先知道数据总量,可以随机分配…

字节跳动技术总监整理的这份MySQL学习文档,看完才发现要学的可太多了!

对于程序员来说,去任何一家公司面试,数据库是避不开的。开发人员对MySQL掌握的越深入,你能做的事情就越多。 完成业务功能,要懂基本的Sql语句。做性能优化,要懂索引,懂引擎。做分库分表,要懂主从…

Head First设计模式(阅读笔记)-13.代理模式

监控糖果机 假设现在需要一台监视器去生成报告,报告中包括糖果机的位置、库存等信息 // 糖果机 public class GumballMachine{String loc;public GumballMachine(String loc, int count){this.loc loc;}public String getLoc(){return loc;}// 其他方法省略 } // 监…

详解Pytorch中的torch.nn.MSELoss函数(包括每个参数的分析)

一、函数介绍 Pytorch中MSELoss函数的接口声明如下,具体网址可以点这里。 torch.nn.MSELoss(size_averageNone, reduceNone, reduction‘mean’) 该函数默认用于计算两个输入对应元素差值平方和的均值。具体地,在深度学习中,可以使用该函数用…

玩转webpack(03):webpack进阶使用

一、自动清理构建目录 避免构建前每次都要手动删除dist 使用 clean-webpack-plugin(默认删除output指定的输出目录) (1)依赖安装 npm i clean-webpack-plugin -D (2)使用 --- webpack.prod.js const Cl…

基于java学生签到考勤系统

开发工具eclipse,jdk1.8 技术:java swing 数据库:mysql5.7 学生选课系统功能:管理员、教师、学生三个角色 一、管理员功能: 1.登录、修改密码、退出系统 2.学生管理:添加、修改、删除、查询 3.班级管理&#x…

YOLOV1算法学习记录

前言 R-CNN系列算法(R-CNN、SPPNet、Fast R-CNN、Faster R-CNN)均是采用two-stage的方法(1.提取region proposal 2.分类边框回归),主要是对region proposal进行识别定位。虽然这类方法检测精度很高,但由于…

Leetcode番外篇——滑动窗口的应用

各位好,博主新建了个公众号《自学编程村》,拉到底部即可看到,有情趣可以关注看看哈哈,关注后还可以加博主wx呦~~~(公众号拉到底部就能看到呦) 我们刚刚在上一节讲述了TCP的滑动窗口。殊不知,它…