InnoDB 的内存结构详情
文章目录
1、更新语句在MySQL中是如何执行的
2、重要的内存结构—Buffer Pool缓冲池
3、undo日志文件如何让更新的数据可以回滚
4、更新Buffer Pool缓冲池中的缓存数据
5、Redo Log Buffer如何避免宕机时数据丢失
6、如果还没提交事务时MySQL宕机了怎么办
7、提交事务时将redo日志写入磁盘中
8、redo日志刷盘策略的选择和建议
9、MySQL的redo log 和 binlog对比
10、提交事务时同时也会写入binlog11.binlog日志的刷盘策略分析
11、binlog日志的刷盘策略分析
12、基于binlog的redo log完成事务的提交
13、在redo日志中写入commit标记的意义
14、后台IO线程随机将内存更新后的脏数据刷盘
15、InnoDB存储引擎的架构原理总结
一、更新语句在MySQL中是如何执行的
假设有一条如下这样的SQL语句,那么这条语句是如何执行的呢?
首先Java系统会通过一个数据库连接将该SQL语句发送到MySQL上,然后经过SQL接口、解析SQL语句、预处理器、优化器生成了执行计划后,再由执行器调用InnoDB存储引擎的接口去执行生成的执行计划。
二、InnoDB的内存结构:Buffer Pool缓冲池
InnoDB有一个非常重要、放在内存里的组件,就是缓冲池(Buffer Pool)。缓冲池会缓存很多磁盘文件数据,以便在查询时不用去查磁盘
所以当InnoDB存储引擎要执行更新语句时:比如对"id=1"这一行数据,会先判断"id=1"这一行数据是否在缓冲池里。如果不在,则直接从磁盘里加载到缓冲池里,且对这行记录加独占锁 (更新“id=1”这行数据时,肯定不允许别人同时更新)
三、undo 日志文件如何让更新的数据可以回滚
假设“id=1”这行数据的name原来是“Java”,现在我们要更新为“Edge”,则此时得先把要更新的原来的值“Java”和“id=1”这些信息,写入undo日志文件。
若执行一个更新语句,要是他在一个事务里,则事务提交前,我们都可以对数据进行回滚,即把你更新为“Edge”的值回滚到之前的“Java”。
所以考虑到后续可能需要回滚数据,这里会把你更新前的值写入undo日志文件:
四、更新Buffer Pool缓冲池中的缓存数据
当要更新的那行记录从磁盘文件加载到缓冲池后,同时对其上锁,而且在记录更新前把旧值写入undo日志文件后,才开始更新该行记录。
更新时,先更新缓冲池中的记录, 此时这个数据就是脏数据了。
把内存里的“id=1”这行数据的name字段修改为“Edge”,为何此时这行数据就是脏数据了?因为这时磁盘上 中“id=1”这行数据的name还是“Java”,但内存里这行数据已被修改,所以它就是脏数据:
五、Redo Log Buffer如何避免宕机时数据丢失?
现在已经把内存里的数据进行了修改,但是磁盘上的数据还没修改。此时万一MySQL所在机器宕机,必然会导致内存里已修改的数据丢失。这该如何处理?
这时,就得将对内存所做的修改数据制成redo日志写到Redo Log Buffer, 也是内存里的一个缓冲区
redo日志,记录你对数据做了什么修改,如对id=1这行记录修改了name字段的值为Edge。
redo日志就是在MySQL宕机时,用来恢复你更新过的数据。
六、若还没提交事务,MySQL宕机了,咋办?
在数据库中,哪怕执行一条SQL语句,其实也可算做一个独立事务,只有当你提交事务后,SQL语句才算执行结束。
所以至此,其实还没提交事务,若此时MySQL宕机,导致内存里Buffer Pool中的修改过的数据丢失了,同时你写入Redo Log Buffer中的redo日志也会丢失,这咋办?
其实没必要惊恐,因为这条更新语句,没提交事务,就代表他还没执行成功,此时MySQL宕机了,虽然导致内存的数据更新都丢失了,但磁盘上的数据依然还停留在原样。
即“id=1”那行数据的name还是原值,所以此时你的这个事务就是执行失败了,没能成功完成更新,那你就会收到一个数据库异常。然后当MySQL重启正常后,你会发现你的数据并没有任何变化。所以此时即使MySQL宕机,也不会有任何问题。
七、提交事务时将redo日志写入磁盘中
如果InnoDB想要提交一个事务,就会根据一定的策略把redo日志从Redo Log Buffer中刷入到磁盘Redo文件里,这个策略是通过如下这个参数来配置的:innodb_flush_log_at_trx_commit。
1、当 innodb_flush_log_at_trx_commit = 0 时
innodb_flush_log_at_trx_commit = 0: 表示当提交事务时,并不会立即将 redo log buffer 缓存池的 redo 日志写入磁盘的Redo日志文件里,而是等待后台线程每秒写入一次,此时可能你都提交事务了,结果MySQL宕机了,然后此时内存里的数据全部丢失。相当于你提交事务成功了,但由于MySQL突然宕机,有可能导致丢失1 秒内 Buffer Pool内存中的数据 和 Redo log buffer的数据
2、当 innodb_flush_log_at_trx_commit = 1 时
你提交事务时,就必须把redo日志从Redo log buffer中刷入到磁盘的Redo日志文件里,只要事务提交成功,则redo日志必然在磁盘
那么只要提交事务成功后,redo日志一定在磁盘,此时你肯定会有一条redo日志说,“我此时对哪个数据做了一个什么修改,如name修改为Edge了”
即使此时Buffer Pool中更新过的数据还没刷盘,此时内存数据是更新后的“name=Edge”,而磁盘上的数据还是未更新的“name=Java”
所以之前由于系统崩溃,而现在MySQL重启后,还能根据磁盘的redo日志文件,恢复之前做过的修改:
3、当 innodb_flush_log_at_trx_commit = 2 时
提交事务时,把redo日志 从Redo log buffer写入磁盘文件对应的os cache缓存中,而不是直接进入磁盘的 Redo 日志文件,可能1s后,才把os cache 缓存里的 redo日志数据写入到磁盘文件。这种模式下,提交事务后,redo log可能仅停留在os cache内存缓存,还没实际进入磁盘文件,若此时宕机,则os cache里的redo log就会丢失,同样会让你感觉提交事务了,但结果数据丢了:
八、redo日志刷盘策略的选择和建议
通常建议设置 innodb_flush_log_at_trx_commit的值为1。也就是提交事务时,redo日志必须同时刷入磁盘文件里。这样可以严格保证提交事务后数据绝对不会丢失。
如果innodb_flush_log_at_trx_commit = 0,那么提交事务后如果MySQL宕机而此时redo日志还没有刷盘,则会导致内存里的redo日志丢失,内存更新好的数据也丢失。
如果innodb_flush_log_at_trx_commit = 2,那么提交事务后虽然redo日志进入了OS Cache,但OS Cache的数据此时还没进入磁盘文件而MySQL机器宕机了,则也会导致OS Cache的redo日志丢失。
所以一般设置redo日志刷盘策略为1,保证事务提交后数据不会丢失。
九、MySQL的redo log 和 binlog对比
1、Redo Log (重做日志)
用途:
- 崩溃恢复:当数据库崩溃时,已经写入磁盘的数据可能不完整,Redo 日志文件主要用于在数据库崩溃后恢复未完成的事务。以确保数据的完整性
工作原理:
先写日志后写数据:MySQL使用 "先写日志后写数据" 的方式,即在事务提交时,首先将事务的操作数据记录在redo日志中,然后再将redo日志从Redo Log Buffer写入磁盘Redo 日志文件中。这样可以确保在事务提交后,即使数据库崩溃,也可以通过Redo 日志文件恢复数据。
循环写入:redo log是循环写入的,即写满一个日志文件后,会覆盖最早的日志记录。因此,Redo 日志文件的大小是有限制的,通常由innodb_log_file_size参数控制
2、Binlog (二进制日志)
用途:
主从复制:binlog用于MySQL的主从复制架构中,主服务器将所有的写操作记录在binlog中,从服务器通过读取binlog来同步主服务器的数据。
数据恢复:通过binlog可以恢复数据库到某个时间点的状态。
工作原理:
所有修改操作的记录:binlog记录了所有对数据库的修改操作,包括INSERT、UPDATE、DELETE等。
按时间顺序记录:binlog按时间顺序记录所有的操作,因此在恢复数据时,可以按时间点进行恢复
多种格式:binlog有多种格式,包括STATEMENT、ROW和MIXED。其中,STATEMENT格式记录SQL语句,ROW格式记录修改的行数据,MIXED格式则根据情况自动选择。
小总结
MySQL的redo log, 是一种偏向物理性的重做日志。因为其记录的是:对哪个数据页中的哪条记录做了什么修改。而且redo log是属于InnoDB存储引擎特有的日志文件。
MySQL的binlog, 是一种偏向于逻辑性的日志,也叫归档日志。类似"对users表中id=1的一行记录做了更新操作,更新后的值是什么"。binlog不是InnoDB存储引擎特有的日志文件,binlog是属于MySQL数据库层面的日志文件。
Redo Log: 主要用于事务的崩溃恢复,确保数据的持久性和一致性。
Binlog: 主要用于主从复制和数据恢复,记录所有的修改操作
十、提交事务时同时也会写入binlog
提交事务时,除了会把redo日志写入到磁盘文件中,还会把这次SQL更新对应的binlog日志写入到磁盘文件中。
下图加入了执行器这个组件,它会负责和InnoDB存储引擎进行交互:
步骤1:从磁盘加载数据到Buffer Pool缓存
步骤2:写入undo日志
步骤3:更新Buffer Pool里的数据
步骤4:写入redo日志到Redo Log Buffer
步骤5:redo日志刷入磁盘
步骤6:写入binlog日志
实际上,执行器是非常核心的一个组件。执行器会与存储引擎完成SQL语句在磁盘与内存层面的全部数据更新操作。
下图把一次更新语句的执行,拆分为两个阶段。其中步骤1、2、3、4是执行更新语句的阶段, 而步骤5和6是属于提交事务的阶段。
十一、binlog日志的刷盘策略分析
binlog日志也有不同的刷盘策略,通过sync_binlog参数可以控制binlog的刷盘策略,默认值是0。
1、当 sync_binlog设置为 0 时
表示执行器没有直接将binlog日志写入磁盘binlog日志文件,而是先将binlog日志写入OS Cache缓存,与redo log的innodb_flush_log_at_trx_commit的值为2一样。
如果OS Cache里的数据还没写入磁盘文件时,MySQL所在机器宕机,那么binlog日志也会丢失。
2、当 sync_binlog设置为 1 时
表示在提交事务时,执行器会把binlog日志直接写入到磁盘binlog日志文件中。这样在提交事务后即便宕机,binlog也不会丢失。
十二、基于binlog的redo log完成事务的提交
当MySQL把binlog日志写入磁盘binlog日志文件后,接着就会完成最终的事务提交。此时会把本次更新对应的binlog日志文件名称和位置,都写入到redo日志里,同时在redo日志文件里写入一个commit标记。在完成这个事情后,才算是最终完成事务的提交。
十三、在redo日志中写入commit标记的意义
写入commit标记是用来保持redo日志与binlog日志一致。也就是说,在提交事务的时候,上图的步骤5、6、7必须都执行完毕,才算是提交了事务。
1、如果刚完成步骤5时,redo日志刚刷入到磁盘文件,MySQL宕机了
这时因为在redo日志没有最终的事务commit标记,所以此次事务不成功。因为不允许出现这样的情况:redo日志文件里有更新日志,但是binlog日志文件里没有对应的更新日志。否则就会导致数据不一致
2、如果在完成步骤6时,binlog日志已写入磁盘,MySQL宕机了
这时因为在redo日志没有最终的事务commit标记,所以此次事务也失败。所以必须要在redo日志写入最终的事务commit标记,才算事务提交成功。这样redo日志有本次更新的日志,binlog日志也有本次更新的日志,从而实现redo日志和binlog日志完全一致。
十四、后台IO线程随机将内存更新后的脏数据刷盘
当完成事务提交后,MySQL已把内存中的Buffer Pool缓存数据更新了,同时磁盘里也有redo日志和binlog日志,但磁盘上的数据文件还是旧值。
这时MySQL会有一个后台IO线程,在事务提交后的某个时间,随机把内存Buffer Pool中修改后的脏数据刷回到磁盘上的数据文件里。
当IO线程把Buffer Pool里修改后的脏数据刷回磁盘后,磁盘上的数据才会跟内存里的数据一样,都是修改后的值。
当IO线程把脏数据刷回磁盘之前,即便MySQL宕机也没关系。因为重启后会根据redo日志恢复提交事务时所做的修改到内存里。之后IO线程还是会把修改后的数据刷到磁盘的数据文件里。
十五、InnoDB存储引擎的架构原理总结
InnoDB存储引擎会使用Buffer Pool、Redo Log Buffer来缓存数据。InnoDB存储引擎有属于自己的undo日志文件、redo日志文件,MySQL也有属于自己的binlog日志文件。
执行更新时:会修改Buffer Pool里的数据、写undo日志、写Redo Log Buffer。
提交事务时:会把binlog刷入磁盘、在redo日志中写入事务标记,把redo日志刷入磁盘。最后InnoDB后台的IO线程会随机把Buffer Pool的脏数据刷入到磁盘文件。
(1)、MySQL宕机重启如何确定是否需要从redo日志恢复数据
MySQL宕机重启,如何确定脏数据在宕机前是否已全部刷写回磁盘文件。
MySQL宕机重启,InnoDB会首先去查看数据页中LSN的数值。LSN就是InnoDB使用的一个版本标记的计数。如果数据页中的LSN异于redo日志的commit标记,那么就去查看redo日志的LSN大小。如果数据页的LSN值大,则说明数据页领先redo日志,不需要恢复,反之则需要从redo日志中恢复。
(2)、从redo日志恢复数据时是全量恢复还是指定位置后恢复
redo日志是划归于一个redo日志组的。默认一个redo日志组有两个redo日志文件。写redo日志时是循环写入,写满一个redo日志文件再写另外一个。
在写满切换redo日志文件时,会触发数据库的检查点checkpoint。checkpoint所做的事就是把脏页刷新回磁盘。
当DB重启恢复时只需要恢复checkpoint之后的数据即可。所以redo日志文件大小不宜过大,不然导致恢复时需要更长的时间。redo日志文件大小也不宜过小,不然导致频繁切换触发检测点降低性能。
(3)、既然有redo日志来保证崩溃恢复,为什么还要有binlog日志
binlog日志其实就是归档日志,主要用来做数据恢复的。MySQL最开始设计时只有MyISAM引擎只有binlog,不支持InnoDB。此外数据库备份以及hadoop系统数据分析都是binlog来实现的,所以还需要binlog。
(4)、redo日志和binlog日志的数据结构是怎样的
redo日志是循环写,会把redo日志分为0,1,2,3四个区间,有两个指针。writepos指针是一边写一边向后移动,checkpoint指针是一边擦除一边向后移动。所以redo日志是不能保存很多记录的,必须持久化到磁盘中。binlog日志是追加写,不会覆盖之前的日志。
(5)、binlog日志和redo日志是怎么保持一致性的
binlog日志和redo日志是通过两阶段提交来保持一致性的。否则如果数据库系统发生crash,则通过redo日志恢复的数据库和通过binlog日志恢复出来的临时库不一致。
参考地址: https://www.zhihu.com/question/56612006/answer/32486671174
InnoDB 的内存结构详情的更多相关文章
- Innodb的内存结构
1.缓冲池从1.0.x版本开始,允许有多个缓冲池实例. mysql> show variables like 'innodb_buffer_pool_size'\G ************** ...
- 详细了解 InnoDB 内存结构及其原理
最近发现,文章太长的话,包含的信息量较大, 并且需要更多的时间去阅读.而大家看文章,应该都是利用的一些碎片时间.所以我得出一个结论,文章太长不太利于大家的吸收和消化.所以我之后会减少文章的长度,2-3 ...
- MySQL之 InnoDB 内存结构
从MySQL 5.5版本开始默认 使用InnoDB作为引擎,它擅长处理事务,具有自动崩溃恢复的特性,在日常开发中使用非常广泛 下面是官方的InnoDB引擎架构图,主要分为内存结构和磁盘结构两大部分. ...
- (1.3)学习笔记之mysql体系结构(C/S整体架构、内存结构、物理存储结构、逻辑结构)
目录 1.学习笔记之mysql体系结构(C/S架构) 2.mysql整体架构 3.存储引擎 4.sql语句处理--SQL层(内存层) 5.服务器内存结构 6.mysql如何使用磁盘空间 7.mysql ...
- JAVA常见错误处理方法 和 JVM内存结构
OutOfMemoryError在开发过程中是司空见惯的,遇到这个错误,新手程序员都知道从两个方面入手来解决:一是排查程序是否有BUG导致内存泄漏:二是调整JVM启动参数增大内存.OutOfMemor ...
- Java中的OutOfMemoryError的各种情况及解决和JVM内存结构
在JVM中内存一共有3种:Heap(堆内存),Non-Heap(非堆内存) [3]和Native(本地内存). [1] 堆内存是运行时分配所有类实例和数组的一块内存区域.非堆内存包含方法区和JVM内部 ...
- 转:JAVA常见错误处理方法 和 JVM内存结构
OutOfMemoryError在开发过程中是司空见惯的,遇到这个错误,新手程序员都知道从两个方面入手来解决:一是排查程序是否有BUG导致内存泄漏:二是调整JVM启动参数增大内存.OutOfMemor ...
- [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义
前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine ,既然是虚拟机, ...
- Innodb页面存储结构-2
上一篇<Innodb页面存储结构-1>介绍了Innodb页面存储的总体结构,本文会介绍页面的详细内容,主要包括页头.页尾和记录的详细格式. 学习数据结构时都说程序等于数据结构+算法,而在i ...
- java的线程安全、单例模式、JVM内存结构等知识学习和整理
知其然,不知其所以然 !在技术的海洋里,前路漫漫,我一直在迷失着自我. 欢迎访问我的csdn博客,我们一同成长! "不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!" 博 ...
随机推荐
- mysql数据库指定ip远程访问(设置远程连接),赋权操作
mysql数据库指定ip远程访问(设置远程连接) 远程访问mysql报错,ip不允许链接的情况:错误号码1045Access denied for user '用户名' @'数据库地址' (using ...
- 远程连接Windows
远程桌面连接 限制 1.同网段 (1)服务器关闭防火墙 (2)服务器端 右键点击'我的电脑'进入'属性'点击左侧菜单栏中的'远程设置': 把远程桌面选项设置成'允许运行任意版本远程桌面的计算机连接'. ...
- Pyinstaller打包工具
本篇博客主要介绍的是pyinstaller在windows下的基本使用和基础避坑 在windows中使用pyinstaller工具打包时会出现一个问题,在打包列表会看到这样的警告信息: django. ...
- Luogu P2540 NOIP2015提高组 斗地主 加强版 题解 [ 紫 ] [ 深搜 ] [ 剪枝 ]
斗地主:一步一步推性质就能做出来的剪枝题. 这题思路和小木棒的剪枝思路极其相似,剪枝的角度都差不多. 其实大部分搜索剪枝题都是先观察性质,列出性质后选择几个比较关键且代码好写的性质进行剪枝,特别要注意 ...
- FreeSql学习笔记——6.修改
前言 FreeSql 提供丰富的数据库更新功能,支持单条或批量更新,支持更新指定的字段,在特定的数据库执行还可以返回更新后的记录.与删除一样,没有条件的话不会执行,避免全表修改到全表: 指 ...
- Java中的输出格式化
在Java中,输出格式化是一个非常重要的功能,尤其是在需要精确控制输出格式的场景下. 以下是对代码中输出部分的详细解释: 原代码中的输出: System.out.printf("%.6f\n ...
- 快速集成和使用 solon-flow 规则与流引擎(用 yaml 编写业务规则)
本文参考自:https://www.cnblogs.com/studyjobs/p/18125096 规则引擎技术的主要思想是将应用程序中的业务规则分离出来,业务规则不再以程序代码的形式驻留在系统中, ...
- sql server 新建用户数据库授权
必须对数据库进行 db_owner 授权.
- css 各种居中
1. 内部容器居中 flex <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...
- Java - 高射炮打蚊子(第二弹)
题记部分 01 || 面试题 001 || 什么是JVM JVM(Java虚拟机)是Java程序运行的环境,它是一个抽象的计算机,包括指令集.寄存器集.堆栈.垃圾回收等.JVM屏蔽了与具体操作系统平台 ...