🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Mysql中的日志系统 Mysql中支持的日志有redo log、undo log、binlog(二进制日志文件)、error log、relay log;其日志系统相关的系统架构如下: :-: ![](https://img.kancloud.cn/b1/71/b171003fed581607b318ec74a427cff6_815x618.png) 说明:redo log和undo log是归属与innodb的,并不是所有存储引擎都有。查询缓存在mysql8之后就没有了。innodb存储引擎在5.5版本时候是`插件`的形式运行的,在5.5之后就成为了默认的存储引擎。 &nbsp; ## redo log redo操作用于将数据重新恢复到新值,用于已经提交的事务当中。对于一个事务来说,执行commit语句之后并不能够保证修改的数据真正的持久化到磁盘中,只能保证对应的redo log日志持久化到磁盘当中(因此redo log的落盘会在commit之前执行)。数据持久化真正持久化到磁盘是操作系统内核的行为。如果在数据还没有真正的持久化到磁盘的时候系统挂了,内核中的脏页数据将会丢失,这个时候就可以使用redo log来进行恢复了。 redo属于存储引擎(InnoDB)层管理的机制,在Buffer Pool中会维护一块redo log pool的内存空间,当有DML语句执行的时候,会先将对应的日志内容写入到redo log pool中,最后在执行commit时,会在redo log中做上commit标识,同时落盘。也就是说当事务被commit之后数据并不是真正的落盘了,有可能还在Buffer pool中,只能保证redo log的内容落盘了。这种方式就称为WAL(write ahead log,预习日志)。而Buffer pool中的数据会在checkpoint中择时落盘。 :-: ![](https://img.kancloud.cn/1a/03/1a031f0defd2b59f325c3be14b22ce56_1346x721.png) **Redo log的落盘机制** 在配置文件中的Mycat中可以配置`innodb_flush_log_at_trx_commit`属性来控制redo log的落盘机制,`innodb_flush_log_at_trx_commit`属性的取值如下: * 1,默认值,事务提交时执行一次fsync操作,将日志落盘。 * 0,事务提交时直将内容写入redo log buffer中,由其他后台线程选择落盘的时机。 * 2,事务提交时将redo log的内容写入pagecache中,之后每隔1秒由fsync命令刷新落盘。 可见设置为0的时候mysql的线程的性能最高,但是丧失了事务的一致性。为1的话就可以实现强一致性。 :-: ![](https://img.kancloud.cn/f1/02/f10203d8a2a53e4726e322f3b88b3929_1001x779.png) > 问:redo log是不是都是已经提交的事务? 当事务提交的时候会将redo log的内容写入redo log buffer中,这个时候并不是真正的写入redo log的日志文件中的。redo log buffer落盘的时机受后台线程的控制,由于redo log buffer是所有事务共享的且事务每次执行的命令的时候就会将命令写入redo log中;当事务A执行到了一半,而事务B提交了事务或者是后台线程刷新了redo log buffer中的脏页,因此就有可能导致事务A的redo log的内容也被落盘了,但是此时事务A并没有提交。 > 问:如何区分redo log中的事务是不是已经提交的事务? 对于一个修改x的命令,redo log的记录内容大致可以如下:<事务ID,修改行,旧值,新值>。 对于一个完整的事务T1,redo log的内容可能如下: ``` <T1 start> ... <T1 commit> ``` 当事务执行commit命令之前会在redo log中打上commit标志,如果事务T1在redo log file中没有最后的commit标志,是不用进行事务的恢复的。 > 问:checkpoint的作用是什么? 1. 在checkpoint之后开始或者提交的事务才需要进行恢复操作,可以缩短数据库进行重做日志时的恢复时间。 2. 当缓冲池不够用的时候,将脏页刷新到磁盘中。 记录的格式可能如下: ``` <checkpoint t1, t2,t3> ``` > 问:checkpoint什么时候起作用? 1. 数据库关闭时将所有的脏页落盘。 2. 主线程按照一定的时间刷新一定比例的脏页。 3. LRU可用页不多时。 4. 脏页的数量超过一定的比例时。 > 问:doublewrite是什么? 由于InnoDB每页的大小为16KB,而Linux文件系统支持的IO的最小单位是4K,磁盘IO的最小单位是512个字节,因此在脏页落盘的时候如果发现了断电而导致例如16KB只写了2KB,这个时候就会出现数据丢失的问题,使用redo是不能够恢复的。为了保证落盘这个过程的可靠性,InnoDB就引入了DoubleWrite机制,来解决部分写入的问题。 DoubleWrite由两部分组成,一个部分是内存中的DoubleWrite Buffer,大小为2MB;另外一部分是磁盘的共享表空间中连续的128个页,大小也是2MB。double的过程如下: 1. 当发生脏页落盘的时候,将脏页copy到doublewrite中。 2. 接着从double write buffer中写入顺序写入磁盘共享表空间中,每次1MB。 3. 做完之后将double write buffer中的数据写入各个表空间中,离散写入的。 在系统崩溃的时候在共享表空间中找到该页的最近一个副本,直接替换。 > 问:为什么redo log不需要doublewrite的支持? > > redo log每次写入的最小单位是512字节,也就是磁盘的最小单位。 &nbsp; ## undo log &nbsp; ## binlog binlog是Mysql server层维护的一种二进制文件,与redo log和undo log由存储引擎层维护不同。其主要作用有: * 主从复制:MySQL Replication在Master端开启binlog,Master把它的二进制日志传递给slaves并回放来达到master-slave数据一致的目的。 * 数据恢复:通过mysqlbinlog工具恢复数据。 * 增量备份。 binlog文件的位置一般放在mysql安装目录下的data目录,可以使用如下命令来具体查看binlog的状态信息: ~~~  show variables like '%log_bin%'; ~~~ :-: ![](https://img.kancloud.cn/59/60/59603cd6617eaa95f1098548e3eb200d_1182x262.png) 在mysql5.7中binlog默认是关闭的,可以修改配置文件my.cnf启动: ~~~ [mysqld] log-bin=ON ~~~ 查看binlog文件情况: ~~~  show binary logs;  ​  show master status; # 查看当前写入的binlog文件  ​  reset master; #清空binlog日志文件 ~~~ :-: ![](https://img.kancloud.cn/d4/a9/d4a9fef8672039262e988c2ec5010800_986x692.png) binlog文件是二进制文件,可以使用下面两种方式查看binlog文件的内容: 1. mysqlbinlog ~~~  mysqlbinlog binlog.000501 ~~~ mysqlbinlog是官方提供的一个binlog的查看工具,windows系统在安装目录的bin目录下有。 2. 直接命令行解析 ~~~  show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count] ~~~ **binlog主从复制** binlog主要用于主从复制中,在5.6版本之后有两种主从复制方式:binlog和GTID(全局事务标识符)。binlog用于主从复制的流程如下: 1. Master将数据改变记录到二进制日志(binary log)中。 2. Slave上的IO进程连接Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容。 3. Master接收到来自Slave的IO进程的请求后,负责复制的IO进程会根据请求信息读取日志指定位置之后的日志信息,返回给Slave的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置。 4. Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master从某个bin-log的哪个位置开始往后的日志内容。 5. Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行。 &nbsp; ### 事务的两阶段提交 Mysql中有两种日志是用于备份数据的,redo log和binlog;binlog是mysql的server层所有的,redo log是InnoDB引擎所有的,而只有redo log能用于故障恢复。因此为了保证redo log和binlog中的逻辑一致性,redo log会先写入一个prepare标识,之后binlog写入,之后再提交事务,写入commit。