mysql 修改数据使用redolog

不使用redoLog方式问题:

因为 Innodb 是以  为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,如果采取第二种方式  ,这个时候将完整的数据页刷到磁盘的话,太浪费资源了!

比如图(页结构)中的逻辑上是连续的一行行数据,但它们在磁盘的位置可能不是连续的,是随机的。要把这一整页持久化到磁盘中,是随机的IO。 这时需要一个个找到磁盘中对应的位置,将BufferPool最新的页数据更新到磁盘,因为随机IO问题,这过程是很慢的。

使用redolog

redo log 包括两部分:一个是内存中的日志缓冲( redo log buffer ),另一个是磁盘上的日志文件( redo logfile)。

mysql 每执行一条 DML 语句,先将记录写入 redo log buffer,后续某个时间点再一次性将多个操作记录写到 redo log file。这种 先写日志,再写磁盘 的技术就是 MySQL里经常说到的 WAL(Write-Ahead Logging) 技术。

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

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

mysql 支持三种将 redo log buffer 写入 redo log file 的时机,

什么时候持久化,这跟事务有关系,比如开启一个事务,执行update,此时要持久化redo log吗?

这时不需要,只有当这个事务真真commit时才持久化。事务rollback肯定就不用持久化。

   可以通过 innodb_flush_log_at_trx_commit 参数配置,各参数值含义如下:

 

osbuffer ,操作系统的缓冲区。

比如写文件的write-->os  ,flush-->磁盘。


 

当事务提交 commit时, redo log才持久化

假如,mysql挂了,当myql再次启动时,从磁盘找到旧页数据+ redolog页数据, 就得到修改过的数据

为什么使用redolog快呢?

因为mysql启动后,就在磁盘中开辟一文件(ib_logfile,默认48M),只要有数据更新,将redolog日志(更新sql)写到此文件末尾,这种写是顺序写,因为文件本身已经存在(顺序IO)。这种IO读写速度就比第二种方式快更多了。

为什么redolog有两个文件循环写呢?

当然这文件大小和个数是可以配置的。

使用checkpoint机制,ib_logfile0,ib_logfile1写满后,再切到ib_logfile0时,就触发checkponint机制,发现这时,ib_logfile0满了,就找ib_logfile0对应BufferPool中的页数据刷到磁盘,清出空间继续使用。

刷盘时机

  • redo日志刷盘

    刷盘准备

    当修改buffer pool中的页时,会将这个脏页的控制块插入到flush链表中,控制块存储了两个变量:oldest_modification被加载到buffer pool中第一次修改mtr开始时对应的lsn值,newest_modification每次mtr修改结束时对应的lsn值;控制块按照oldest_modification从大到小排序存储。

    一个mtr可能修改多个页,所以多个控制块的oldest_modification/newest_modification可能一样。

    刷盘时机

  • log buffer空间不足,空闲空间小于一半时
  • 事务提交时,buffer pool中的脏页可以先不刷盘,但其中的log buffer需要刷盘,防止丢失
  • 后台线程定时刷盘
  • 正常关闭服务器时
  • checkpoint时:批量从flush链表中刷出脏页:如果系统修改页面频繁,且不能将脏页刷出,则不能及时checkpoint,可能会直接使用用户线程同步的从flush链表中最早修改的脏页刷盘,这样这些脏页对应的redo日志就没用了,就可以checkpoint了

redo日志文件存储

在MySQL的数据目录下,(由innodb_log_group_home_dir确定存储位置,由名称可知存储形式是一个日志文件组)名为ib_logfile0...n的文件,文件个数决定文件名称后缀,由系统参数innodb_log_files_in_group确定文件个数,每个文件的大小由innodb_log_file_size指定。

每个ib_logfile顺序循环写入log buffer中的block,会出现文件被覆盖的现象。

checkpoint:将缓冲池中的脏页刷回到磁盘。
InnoDB存储引擎内部,两种checkpoint,分别为:
1.Sharp Checkpoint
2.Fuzzy Checkpoint
Sharp Checkpoint发生在数据库关闭时,将所有的脏页都刷新回磁盘,这是默认的工作方式,即参数:innodb_fast_shutdown=1。
在数据库运行时,InnoDB存储引擎内部采用Fuzzy Checkpoint,只刷新一部分脏页。
Fuzzy Checkpoint的几种情况:
1.MasterThread Checkpoint
异步刷新,每秒或每10秒从缓冲池脏页列表刷新一定比例的页回磁盘。异步刷新,即此时InnoDB存储引擎可以进行其他操作,用户查询线程不会受阻。
2.FLUSH_LRU_LIST Checkpoint
InnoDB存储引擎需要保证LRU列表中差不多有100个空闲页可供使用。在InnoDB 1.1.x版本之前,用户查询线程(mysql5.6之后放在了单独的进程Page Cleaner中进行)会检查LRU列表是否有足够的空间操作。如果没有,根据LRU算法,溢出LRU列表尾端的页,如果这些页有脏页,需要进行checkpoint。
设置参数:innodb_lru_scan_dept:控制LRU列表中可用页的数量,该值默认1024
3.Async/Sync Flush Checkpoint
指重做日志不可用的情况,需要强制刷新页回磁盘,此时的页时脏页列表选取的。
这种情况是保证重做日志的可用性,说白了就是,重做日志中可以循环覆盖的部分空间太少了,换种说法,就是极短时间内产生了大量的redo log。

优化

可以将redolog调大点,或者文件个数调大点,减小刷盘频率,减少磁盘IO,但另一个问题,重启mysql时间就长点。

猜你喜欢

转载自blog.csdn.net/liuming690452074/article/details/113817552