6.2 Redo log 作用
-
前滚操作:具备crash-safe能力,提供断电重启时解决事务丢失数据问题。
-
提高性能:先写Redo log记录更新。当等到有空闲线程、内存不足、Redo log满了时 “刷脏”。写Redo log是顺序写入,刷脏是随机写,节省的是随机写磁盘的 IO 消耗(转成顺序写),所以性能得到提升。此技术称为WAL技术:Write-Ahead Logging,它的关键点就是先写日记磁盘,再写数据磁盘。
6.3 Redo log 的两阶段提交
更新内存后引擎层写Redo log将状态改成prepare为预提交第一阶段,Server层写Binlog,将状态改成commit为提交第二阶段。两阶段提交可以确保Binlog和Redo log数据一致性。
6.4 Redo log 容灾恢复过程
MySQL的处理过程如下
-
判断redo log是否完整,如果判断是完整(commit)的,直接用Redo log恢复
-
如果redo log只是预提交prepare但不是commit状态,这个时候就会去判断binlog是否完整,如果完整就提交Redo log,用Redo log恢复,不完整就回滚事务,丢弃数据。
只有在redo log状态为prepare时,才会去检查binlog是否存在,否则只校验redo log是否是 commit就可以啦。 怎么检查binlog:一个完整事物binlog结尾有固定的格式。
6.5 Redo log 刷盘时机
Undo log的刷盘时机和Redo log差不多,但是对于Undo log我没找到对应的刷盘参数设计,所以不再提。Redo log每次先写入Redo Log Buffer中,然后通过刷盘时机控制刷入OS Buffer时间和刷入日记磁盘的时间。
在Undo Log中,MySQL是通过参数innodb_flush_log_at_trx_commit来控制刷盘时机,取值是0、1和2三种值。0表示事务提交后,每秒写入OS Buffer并调用fsync()写入日记磁盘中;1表示每次事务提交会写入OS Buffer并调用fsync()将日记写入日记磁盘中。2表示事务每次提交写入到OS Buffer,每秒调用fsync()写入日记磁盘。可见参数为1是最安全的,同时也是默认值。
6.6 Redo log 存储方式
上图是日记磁盘的Redo log环形设计图(从头写,写到结束又从头开始写~循环)。write pos和check point是两个指针,write pos指针指向当前日记文件写入的位置,check point指针指向当前要擦除的开始位置。图中绿色部分是可以写入Redo log地方,每次写入,write pos指针会顺时针推进,当然基本不会与check point指针重合,因为MySQL有这种机制去实现,每次触发检查点checkpoint,check point会指针向前推进,这个过程就是需要进行刷日记和数据磁盘,记录相应的LSN,引出难点LSN。
6.7 Redo Log 检查点
啥时候会触发检查点checkpoint,网上找了点资料:啥时候数据库会触发检查点checkpoint
Checkpoint发生的时间、条件及脏页的选择等都非常复杂。而Checkpoint所做的事情无外乎是将缓冲池中的脏页刷回到磁盘,不同之处在于每次刷新多少页到磁盘,每次从哪里取脏页,以及什么时间触发Checkpoint。这些本文不会去研究。
6.8 Redo Log LSN
LSN这个概念,比较复杂,我介绍完你们不一定懂!LSN称为日志的逻辑序列号(log sequence number),在innodb存储引擎中,lsn占用8个字节。LSN的值会随着日志的写入而逐渐增大。可以简单理解SLN就是记录从开始到现在已经产生了多少字节的Redo log值。
存储方式两个指针又是通过LSN计算得到指向位置,因为LSN记录的是文件的大小字节,当超过文件大小时,需要用取模计算出这两个指针位置,取模使得写入就会从头开始写,这样使得两个指针在一个文件中,一直落在循环位置,你追我赶的过程。这就是Redo log 环形逻辑思想设计实现。
上面提到LSN比较复杂,是因为它有很多个值,输入命令"show engine innodb status;",可以看到四个的lsn记录
为了方便识别,我都为它们重新命名,如下。名词记不住,后面无法继续深入
- 内存日记:redo log buffer lsn;磁盘日记:redo log file lsn;
一般关系为:redo log buffer lsn >= redo log file lsn,如果刷盘时机为1,则redo log buffer lsn = redo log file lsn。
- 内存数据页:data buffer lsn;数据磁盘数据页:data disk lsn;
一般关系为data buffer lsn > data disk lsn,如果已经刷入数据磁盘,则data buffer lsn = data disk lsn。
- 检查点:chckpoint lsn;
后面提到检查点刷盘,数据刷盘和日记刷盘(如果有日记刷盘:则说明我假设的日记刷盘的时机设置值不为1,为1是同步的,即始终redo log buffer lsn = redo log file lsn,不会由检查点触发刷日记磁盘)。
都说Redo log是环形记录,那么怎么记录的?下面结合LSN给出记录过程虚构图,可以对比6.6 Redo log 存储方式图 相关知识:日记磁盘 + redo log file lsn + checkpoint lsn + 双指针(write pos、check point)
1-8按时间顺序发生。1点是假设最初的状态;2、3点写日记磁盘;4点是触发了检查点checkpoint,进行刷盘,checkpoint lsn=1开始,刷盘结束并更新checkpoint lsn=512。在5点、6点已经刷过了一循环内存、二循环内存,从头开始写入log,两个指针指向回到了头部。第7点也是一个触发checkpoint的过程。9点是假设没有更新,最后达到平衡的结果,即内存中数据页和日记都完成了刷盘。
整个流程:
在某些情况下,触发checkpoint,触发数据页和日志页刷盘,此时将内存中的脏数据—“数据脏页"和"日志脏数据” 分别刷到数据磁盘和日记磁盘中,而且两者刷盘速度不一样。checkpoint会保护机制,当数据刷盘速度超过日志刷盘时,将会暂时停止数据刷盘,等待日志刷盘进度超过数据刷盘。
刷盘时,对于数据磁盘,全部都是在内存中,此时每次刷一个数据页到内存更新数据页也更新了data disk lsn为data buffer lsn(在更新内存数据页时,会更新data buffer lsn)。
对于日记磁盘,除了要记录checkpoint lsn的值为检查点 checkpoint的值(必须在结束时 直接记录一个值,速度很快),这里是针对日记刷盘时机不是1(1是同步缓存刷日记刷盘)时,并且日记还没刷到日记磁盘需要触发将缓存中日记提前刷到日记磁盘中,此时会将redo buffer log刷到redo log file中也更新了redo log file lsn为redo log buffer lsn 。
模拟检查点触发前后,整个流程变化,一个数据页和日记,数据变化及lsn从179-180的变化图(刷盘时机不为1)
6.9 Redo log 容灾恢复过程与LSN
结合6.4 Redo log 容灾恢复过程和6.8的LSN知识,再次细化6.4的Redo log恢复过程
重启innodb时,Redo log完不完整,采用6.4知识过程。用Redo log恢复,启动数据库时,InnoDB会扫描数据磁盘的数据页data disk lsn和日志磁盘中的checkpoint lsn。两者相等则从checkpoint lsn点开始恢复,恢复过程是利用 redo log到buffer pool,直到checkpoint lsn等于redo log file lsn,则恢复完成。
如果checkpoint lsn 小于 data disk lsn,说明在检查点触发后还没结束刷盘时数据库宕机了。因为checkpoint lsn最新值是在数据刷盘结束后才记录的,检查点之后有一部分数据已经刷入数据磁盘,这个时候数据磁盘已经写入部分的部分恢复将不会重做,直接跳到没有恢复的lsn值开始恢复。
七、了解 ChangeBuffer
7.1 为啥提到ChangeBuffer
为啥本文我会提到ChangeBuffer呢,其实很多时候会将ChangeBuffer和Redo log搞混,两者都是巧用内存,减少磁盘IO,为了不弄混我觉得有必要专门对这个进行一个讲解。
7.2 ChangeBuffer概念及作用
下面是我对ChangeBuffer的简单介绍
也就是说对于更新的操作,如果用到了ChangeBuffer,更新的数据所在的数据页如果不在内存中,将不用去数据磁盘将数据页读到内存,而是将这一次操作记录在ChangeBuffer中,ChangeBuffer 主要节省的则是随机读磁盘的 IO 消耗,下次读取查询等读取数据页时用上ChangeBuffer中的记录即可。其实也是一种巧用内存的思想。
7.3 ChangeBuffer与Redo log区别
Redo log 主要节省的是随机写磁盘的 IO 消耗(转成顺序写),而 ChangeBuffer 主要节省的则是随机读磁盘的 IO 消耗。
这句话怎么理解,看下面:
Redo log 与 ChangeBuffer(含磁盘持久化) 这2个机制,不同之处在于优化了整个变更流程的不同阶段。
先不考虑Redo log、ChangeBuffer机制,简化抽象一个更新(insert、update、delete)流程:
-
从磁盘读取待变更的行所在的数据页,读入内存页中
-
对内存页中的行,执行变更操作
-
将变更后的数据页,写入至数据磁盘中
其中,流程中的步骤1涉及随机读磁盘IO;步骤3涉及随机写磁盘IO;刚好对应ChangeBuffer和Redo log。
对那句话的理解答案:
-
ChangeBuffer机制,优化了步骤1——避免了随机读磁盘IO ,将不在内存中的数据页的操作写入ChangeBuffer中,而不是将数据页从磁盘读入内存页中
-
Redo log机制, 优化了步骤3——避免了随机写磁盘IO,将随机写磁盘,优化为了顺序写磁盘(写Redo log,确保crash-safe)
7.4 有没有用到ChangeBuffer对于Redo log的区别
Redo log机制,为了保证crash-safe,一直都会用到。 有无用到ChangeBuffer机制,对于redo log这步的区别在于—— 用到了ChangeBuffer机制时,在Redo log中记录的本次变更,是记录new change buffer item相关的信息,而不是直接的记录物理页的变更(文章中第八节都有体现这一过程)。 在我们mysql innodb中, ChangeBuffer机制不是一直会被应用到,仅当待操作的数据页当前不在内存中,需要先读磁盘加载数据页时,ChangeBuffer才有用武之地。
7.5 ChangeBuffer的merge过程
除了访问这个数据也会触发 merge 外,系统有后台线程会定期 merge。在数据库正常关闭(shutdown)的过程中,也会执行 merge 操作。
merge过程做三步
-
从磁盘读入数据页到内存(老版本的数据页);
-
从 change buffer 里找出这个数据页的 change buffer 记录 (可能有多个),依次应用,得到新版数据页;
-
写 redo log。这个 redo log 包含了数据的变更和 change buffer 的变更。
八、日记大连贯U-R-B,一举攻破拿下
前面分别讲的是Binlog、Undo log和Redo log,下面将他们都串联起来,在一些流程体现全部日记。
同样,以一些最经典的更新语句例子展开说明。
8.1 制造演示数据
测试语句:插入语句+查询语句,a字段是普通索引
insert into ta(a,b) values(2,5),(7, 5)2、select * from t where a in (2, 7)
假设原来的数据如下图,数据页page1在内存中,page2不在。插入的数据(2,5)落在page1,数据(7,5)落在page2中。
最后
现在其实从大厂招聘需求可见,在招聘要求上有高并发经验优先,包括很多朋友之前都是做传统行业或者外包项目,一直在小公司,技术搞的比较简单,没有怎么搞过分布式系统,但是现在互联网公司一般都是做分布式系统。
所以说,如果你想进大厂,想脱离传统行业,这些技术知识都是你必备的,下面自己手打了一份Java并发体系思维导图,希望对你有所帮助。
包项目,一直在小公司,技术搞的比较简单,没有怎么搞过分布式系统,但是现在互联网公司一般都是做分布式系统。
所以说,如果你想进大厂,想脱离传统行业,这些技术知识都是你必备的,下面自己手打了一份Java并发体系思维导图,希望对你有所帮助。