innodb 01 redo 日志详解

redo 和binlog的区别。

1、二进制日志server层产生,redo是innodb层产生。并且binlog先于redolog被记录
2、binlog记录操作的方法是逻辑性的语句,基于行格式。redolog是innodb层产生的日志,记录数据库每个页的修改。
3、binlog是事务提交的时候,一次性写入,redolog是数据准备修改的时候写入redobuffer,然后才对缓存中数据操作。并且保证,事务提交时:redobuffer冲刷到磁盘
4、binlog是一次性写入,所以有顺序。redolog是物理页的修改,所以可能同一个事务多次记录,并且redolog是并发写入的,不同事务之间的不同版本会穿插到redolog中。
5、事务日志记录的是物理页的情况,它具有幂等性,因此记录日志的方式极其简练。而二进制日志记录的是所有影响数据的操作,记录的内容较多。

redo基本概念:

redo包含两个部分:内存中的日志缓冲redobuffer + 磁盘上的日志文件redolog.事务提交的时候,必须把该事务的所有日志都写入到磁盘的redolog中。
redobuffer 在用户区,先复制到内核取,然后fsync刷盘。
关于为何要经过内核缓冲区的理解:使用O_DIRECT表示写磁盘绕过OS Buffer,但是这样会降低顺序写的效率(写abcde,将发起五次fsync)。

redolog:double write写入,保证写入一定是成功的。redolog是循环写的。

Double Write的思路很简单:
A. 在覆盖磁盘上的数据前,先将Page的内容写入到磁盘上的其他地方(InnoDB存储引擎中的doublewrite buffer,这里的buffer不是内存空间,是持久存储上的空间).
B. 然后再将Page的内容覆盖到磁盘上原来的数据。
如果在A步骤时系统故障,原来的数据没有被覆盖,还是完整的。
如果在B步骤时系统故障,原来的数据不完整了,但是新数据已经被完整的写入了doublewrite buffer. 因此系统恢复时就可以用doublewrite buffer中的新Page来覆盖这个不完整的page。

doublewrite由两部分组成,一部分是内存中的 doublewrite buffer,大小为2MB,另部分是物理磁盘上共享表空间中连续的128个页,
即2个区( extent),大小同样为2MB。在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过 memcpy函数将脏页先复制到内存中的
doublewrite buffer,之后通过 doublewrite buffer再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用 fsync函数,
同步磁盘,避免缓冲写带来的问题。在这个过程中,因为 doublewrite页是连续的,因此这个过程是顺序写的,开销并不是很大。
在完成 doublewrite页的写入后,再将 doublewrite buffer中的页写入各个表空间文件中,此时的写入则是离散的。

redolog commit 后,有三种写入模式:

innodb_flush_log_at_trx_commit参数决定:
0:提交事务的时候,并不把redolog刷新到磁盘上去。而是等待主线程每秒的刷新
1:提交事务的时候,同时刷盘redolog。
2:表示将事务异步写到磁盘,即写到文件系统的缓存中去。

日志块512字节:

redo buffer 或者redo file 由很多日志块组成。
block = 块头(12字节) + 块(492) + 块尾(8字节)
块头 = 日志块在buffer中的ID + 日志块已写日志的大小 + 日志块中第一个日志的位置 +写入检查点信息的位置、
块尾 = 日志块在buffer中的ID

log group 和 redo log file

一个log group由多个完全相同的redolog file 组成。log group是逻辑的。redo log file是物理的。
innodb_log_files_group 参数决定 redo log file 的数量
innodb_log_group_home_dir 参数决定 redo log file的位置
每个redo log file前2KB都是预留空间。第一个redo log file记录了group的信息。其他redo log file的这2KB为空。

redo_log 的格式。

在redo block 中,中间的块部分是log body(492字节)
log body = 日志类型(1字节)+ 表空间ID(4字节) + 页的偏移量 + 数据
其中数据部分,插入和删除格式是不一样的。

redo日志刷盘时机:

1.发出commit动作时。已经说明过,commit发出后是否刷日志由变量 innodb_flush_log_at_trx_commit 控制。
2.每秒刷一次。这个刷日志的频率由变量 innodb_flush_log_at_timeout 值决定,默认是1秒。要注意,这个刷日志频率和commit动作无关。
3.当log buffer中已经使用的内存超过一半时。
4.当有checkpoint时,checkpoint在一定程度上代表了刷到磁盘时日志所处的LSN位置。

innodb数据刷盘(checkpoint机制):

在innodb中,数据刷盘的规则只有一个:checkpoint。但是触发checkpoint的情况却有几种。
两种触发:
sharp(锐利的; 急剧的) checkpoint:在数据库关闭的时候,将所有脏页刷盘
fuzzy(毛茸茸的) checkpoint:
master :线程每秒或者每10秒,进行刷新。
flush_lRU_list :保证LRU中有100个空闲(数量可调整)。page clearner thread 刷新
Async/Sync Flush:重做日志文件不可用的时候进行的刷新(75%—>异步、90%—>同步)。(redo log是循环使用的,避免覆盖,见上文)
Dirty Page too much:脏页太多了,导致缓冲区没有足够可用的页。MySQL 5.6默认的值为75,即当脏页占缓冲池的百分之75后,就强制刷一部分脏页到磁盘。

MySQL停止时是否将脏数据和脏日志刷入磁盘:

由变量innodb_fast_shutdown={ 0|1|2 }控制,默认值为1,即停止时只做一部分purge,忽略大多数flush操作(但至少会刷日志),在下次启动的时候再flush剩余的内容,实现fast shutdown。

LSN

log sequence number就是当前的redo log(in buffer)中的lsn;
log flushed up to是刷到redo log file on disk中的lsn;
pages flushed up to是已经刷到磁盘数据页上的LSN;
last checkpoint at是上一次检查点所在位置的LSN。
但是其实:内存数据页也有LSN。所以
内存数据页的LSN >= redo log(buffer)的LSN >= redo log(disk)的LSN >= 已经刷到磁盘数据页上的LS >= 上一次检查点所在位置的LSN(上一次checkpoint)

宕机恢复:

1、重启innodb时,checkpoint表示已经完整刷到磁盘上data page上的LSN,因此恢复时仅需要恢复从checkpoint开始的日志部分
2、还有一种情况,在宕机前正处于checkpoint的刷盘过程,且数据页的刷盘进度超过了日志页的刷盘进度。这时候一宕机,数据页中记录的LSN就会大于日志页中的LSN,在重启的恢复过程中会检查到这一情况,这时超出日志进度的部分将不会重做,因为这本身就表示已经做过的事情,无需再重做。
3、另外,事务日志具有幂等性,所以多次操作得到同一结果的行为在日志中只记录一次。而二进制日志不具有幂等性,多次操作会全部记录下来,在恢复的时候会多次执行二进制日志中的记录,速度就慢得多。

大佬博客 https://www.cnblogs.com/f-ck-need-u/p/9001061.html#blog5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值