不使用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了
在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时间就长点。