任何对Innodb表的变动, redo log都要记录对数据的修改,redo日志就是记录要修改后的数据。redo 日志是保证事务一致性非常重要的手段,同时也可以使在bufferpool修改的数据不需要在事务提交时立刻写到磁盘上减少数据的IO从而提高整个系统的性能。这样的技术推迟了bufferpool页面的刷新,从而提升了数据库的吞吐,有效的降低了访问时延。带来的问题是额外的写redo log操作的开销。而为了保证数据的一致性,都要求WAL(Write Ahead Logging)。而redo 日志也不是直接写入文件,而是先写入redo log buffer,而是批量写入日志。当需要将日志刷新到磁盘时(如事务提交),将许多日志一起写入磁盘。关于redo的产生及其生命周期详细过程,详见:https://yq.aliyun.com/articles/219。

MySQL redo日志是一组日志文件,它们会被循环使用。Redo log文件的大小和数目可以通过特定的参数设置,详见innodb_log_file_size 和 innodb_log_files_in_group 。

每个日志文件的前2048字节是存放的文件头信息。头结构定义在”storage/innobase/include/log0log.h” 中。其在重做日志文件内的布局如下图所示:

所有的redo日志记录是以日志块为单位组织在一起的,日志块的大小为OS_FILE_LOG_BLOCK_SIZE(默认值为512字节),所有的日志记录以日志块为单位顺序写入日志文件。每一条记录都有自己的LSN(log sequence number, 表示从日志记录创建开始到特定的日志记录已经写入的字节数)。每个日志块包含一个日志头段(12字节)、一个尾段(4字节),以及一组日志记录(512 – 12 – 4 = 496字节) 。

Redo 日志块结构

在MySQL Innodb引擎中LSN是一个非常重要的概念,表示从日志记录创建开始到特定的日志记录已经写入的字节数,LSN的计算是包含每个BLOCK的头和尾字段的。那如何由一个给定LSN的日志,在日志文件中找到它存储的位置的偏移量并能正确的读出来呢。所有的日志文件要属于日志组,而在log_group_t里的lsn和lsn_offset字段已经记录了某个日志lsn和其存放在文件内的偏移量之间的对应关系。我们可以利用存储在group内的lsn和给定lsn之间的相对位置,来计算出给定lsn在文件中的存储位置。可以参考函数log_group_calc_lsn_offset()的实现。其核心代码实现如下: