MySQL-InnoDB事务日志

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机制实现事务的持久性。


clipboard

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。

83-690986409

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的数量。

image

每个回滚段有1024个undo log segment,在使用时在每个undo log segment中申请undo 页。在旧版本只有一个回滚段。mysql5.5开始支持128个回滚段。每个事务占用一个undo log segment,因此,可以支持最多128*1024个并发事务运行。

image


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 statusG;
...
------------
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_segmentG;

select * from information_schema.innodb_trx_undoG;



4. rudo和undo日志工作过程




备注:图片均来自互联网

原文地址:https://www.cnblogs.com/binliubiao/p/12667326.html