1. InnoDB事务日志
InnoDB的事务日志主要分为redo log(重做日志,提供前滚操作)和undo log(回滚日志,提供回滚操作和快照读)。
2. redo log
2.1 redo log 区分binlog
1)binlog日志是在Server层产生的,适用所有存储引擎。所有对数据库变更的写入到binlog日志。redo log是由InnoDB存储引擎产生的,只记录改存储引擎对象的数据变更页。
2)日志格式不同,binlog是一种逻辑日志,而redo log是物理格式日志,记录innodb引擎数据页的修改。
3)刷盘时间点不同,binlog只在事务提交完成后一次写入,而redo log是在事务执行过程不断写入。
2.2 redo log
它包含两部分内容(日志缓存[redo log_buffer]和redo log file[datadir/ib_logfileN]),InnoDB通过force log at commit机制实现事务的持久性。
1)log buffer刷日志文件配置参数
MySQL通过控制innodb_flush_log_at_trx_commit参数值方式自定义刷盘方式,从log buffer中的日志刷log file中。这个变量只是控制commit动作是否刷新log buffer到磁盘。
innodb_flush_log_at_trx_commit=1: 事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。 innodb_flush_log_at_trx_commit=0: 事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file on disk中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。 innodb_flush_log_at_trx_commit=2: 每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。
2)redo log block(日志块)
Innodb存储引擎中,redo log以块为单位进行存储的,每个块占512字节,这称为redo log block。所以不管是log buffer中还是os buffer中以及redo log file on disk中,都是这样以512字节的块存储的。
3) rodo log参数
> show global variables like ‘innodb_log%‘; +-----------------------------+----------+ | Variable_name | Value | +-----------------------------+----------+ | innodb_log_buffer_size | 16777216 | # 重做日志缓冲区大小,默认16M | innodb_log_checksums | ON | # 校验 | innodb_log_compressed_pages | ON | # 是否启用压缩 | innodb_log_file_size | 50331648 | # 日志文件大小 | innodb_log_files_in_group | 2 | # 日志文件数量,默认2个日志文件 | innodb_log_group_home_dir | ./ | # 日志文件目录,默认datadri | innodb_log_write_ahead_size | 8192 | # 表示redo log写前的块大小(MySQL 5.7.4) +-----------------------------+----------+
innodb_log_write_ahead_size:为了处理redo log block得大小和OS block间操作数据块大小协调一致得问题。在InnoDB中以512字节一个block的方式对齐写入redo file(ib_logfileN)文件,而操作系统一般以4096字节为一个block单位(OS block)读写。如果即将写入的日志块不在OS buffer Cache时,就需要将对应的4096字节的block读入内存,修改其中的512字节,然后再把该block写回磁盘。引入write-ahead是将当前写入redo文件的偏移量整除innodb_log_write_ahead_size参数值,不能整除时则补0补全,使得需要写入的内容刚好是block的倍数,那么就直接覆盖写入即可。不再需要read-modify-write得过程。提升效率。
4)日志页刷盘规则
log buffer中未刷到磁盘的日志称为脏日志(dirty log)。
刷日志到磁盘规则:
[1] 发出commit动作时,是否刷日志由变量 innodb_flush_log_at_trx_commit 控制。
[2] 每秒刷一次。刷日志的频率由变量 innodb_flush_log_at_timeout 值决定,默认是1秒。这个刷日志频率和commit动作无关。
[3] 当log buffer中已经使用的内存超过一半时。
[4]当有checkpoint时,checkpoint在一定程度上代表了刷到磁盘时日志所处的LSN位置。
5)数据页刷盘规则
内存中(buffer pool)未刷到磁盘的数据称为脏数据(dirty data)。由于数据和日志都以页的形式存在,所以脏页表示脏数据和脏日志。在InnoDB中触发checkpoint动作将buffer中的脏数据页和脏日志页都刷到磁盘中。
触发checkpoint的情形:
[1] sharp checkpoint:在切换日志文件的时候,将所有已记录到redo log 文件中对应的脏数据刷到磁盘。
[2] fuzzy checkpoint:一次只刷一小部分的日志到磁盘,而非将所有脏日志刷盘。有以下几种情况会触发该检查点:
master thread checkpoint:由master线程控制,每秒或每10秒刷入一定比例的脏页到磁盘。
flush_lru_list checkpoint:从MySQL5.6开始可通过 innodb_page_cleaners 变量指定专门负责脏页刷盘的page cleaner线程的个数,该线程的目的是为了保证lru列表有可用的空闲页。
async/sync flush checkpoint:同步刷盘还是异步刷盘。例如还有非常多的脏页没刷到磁盘(非常多是多少,有比例控制),这时候会选择同步刷到磁盘,但这很少出现;如果脏页不是很多,可以选择异步刷到磁盘,如果脏页很少,可以暂时不刷脏页到磁盘
dirty page too much checkpoint:脏页太多时强制触发检查点,目的是为了保证缓存有足够的空闲空间。too much的比例由变量 innodb_max_dirty_pages_pct 控制,MySQL 5.6默认的值为75,即当脏页占缓冲池的百分之75后,就强制刷一部分脏页到磁盘。
由于刷脏页需要一定的时间来完成,所以记录检查点的位置是在每次刷盘结束之后才在redo log中标记的。
MySQL服务停止时是否将脏数据和脏日志刷入磁盘,由变量innodb_fast_shutdown={ 0|1|2 }控制,默认值为1,即停止时只做一部分purge,忽略大多数flush操作(但至少会刷日志),在下次启动的时候再flush剩余的内容,实现fast shutdown。
3. undo log
undo log的作用是提供事务的回滚和多个行版本控制(MVCC-非锁定读)。undo log是逻辑日志,如执行一条delete操作时,undo log将它的反向操作记录下来,undo log也会产生redo日志。当事务失败需要回滚时,就可以从undo log中的逻辑记录进行回滚到修改前的样子。
3.1 undo log存储方式
undo存放在数据库内一个称为回滚段(rollback segment)的特殊段中。默认情况,undo segment在共享表空间(ibdata1)内,如果开启innodb_file_per_table ,将放在每个表的.ibd文件中。可以通过py_innodb_page_info.py工具查看当前biaokongji按中undo的数量。
每个回滚段有1024个undo log segment,在使用时在每个undo log segment中申请undo 页。在旧版本只有一个回滚段。mysql5.5开始支持128个回滚段。每个事务占用一个undo log segment,因此,可以支持最多128*1024个并发事务运行。
3.2 相关参数
+--------------------------+------------+ | Variable_name | Value | +--------------------------+------------+ | innodb_max_undo_log_size | 1073741824 | # undo log的最大容量限制,默认1G | innodb_undo_directory | ./ | # 设置回滚段文件路径,可以设置独立表空间(MySQL5.6) | innodb_undo_log_truncate | OFF | # 是否开启自动清理undo log的功能,MySQL5.7.5 | innodb_undo_logs | 128 | # 设置undo log segment的数量,默认128 | innodb_undo_tablespaces | 0 | # 设置undo 表空间的数量,至少2个。在初始化配置,以后不能修改 +--------------------------+------------+
3.3 查看undo信息
show engine innodb status\G; ... ------------ TRANSACTIONS ------------ Trx id counter 2819 Purge done for trx‘s n:o < 0 undo n:o < 0 state: running but idle History list length 12 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 421561295218512 ... # 视图查看 select * from information_schema.innodb_trx_rollback_segment\G; select * from information_schema.innodb_trx_undo\G;
4. rudo和undo日志工作过程
备注:图片均来自互联网