redo log和事务的两次提交

        当mysql进行写操作时,会优先把数据再去写change buffer,(更新的话,change buffer没有此数据时,会去硬盘里面查出来放到change buffer中,再修改),再写入redo log buffer中。然后在进行刷盘的时候,redo log buffer中的数据才会写入redo log日志文件里。

        注:redo的是记录由“表空间号+数据页号+偏移量+修改数据长度+具体修改的数据”组成。

        redo log包括两部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。

        在概念上,innodb通过force log at commit机制实现事务的持久性,即在事务提交的时候,必须先将该事务的所有事务日志写入到磁盘上的redo log file和undo log file中进行持久化。

        为了确保每次日志都能写入到事务日志文件中,在每次将log buffer中的日志写入日志文件的过程中都会调用一次操作系统的fsync操作(即fsync()系统调用)。

redo log 结构

redo log的三层架构:

粉色:是InnoDB的一项很重要的内存结构(In-Memory Structure),日志缓冲区(Log Buffer),这一层,是MySQL应用程序用户态

黄色:是操作系统的缓冲区(OS cache),这一层,是OS内核态

蓝色:是落盘的日志文件

redo log最终落盘的步骤如何?

        首先,事务提交的时候,会写入redo Log Buffer,这里调用的是MySQL自己的函数WriteRedoLog;

        接着,只有当MySQL发起系统调用写文件write时,redo Log Buffer里的数据,才会写到OS cache。注意,MySQL系统调用完write之后,就认为文件已经写完,如果不flush,什么时候落盘,是操作系统决定的;

        最后,由操作系统(当然,MySQL也可以主动flush)将OS cache里的数据,最终fsync到磁盘上;

操作系统为什么要缓冲数据到OS cache里,而不直接刷盘呢?

        这里就是将“每次写”优化为“批量写”,以提高操作系统性能。

数据库为什么要缓冲数据到Redo Log Buffer里,而不是直接write呢?

        这也是“每次写”优化为“批量写”思路的体现,以提高数据库性能。

        这个优化思路,非常常见,高并发的MQ落盘,高并发的业务数据落盘,都可以使用。

redo log的三层架构,MySQL做了一次批量写优化,OS做了一次批量写优化,确实能极大提升性能,但有什么副作用吗?

这个副作用,就是可能丢失数据:

  1. 事务提交时,将redo log写入Log Buffer,就会认为事务提交成功;
    (2)如果写入Log Buffer的数据,write入OS cache之前,数据库崩溃,就会出现数据丢失;
    (3)如果写入OS cache的数据,fsync入磁盘之前,操作系统奔溃,也可能出现数据丢失;

如上文所说,应用程序系统调用完write之后(不可能每次write后都立刻flush,这样写日志很蠢),就认为写成功了,操作系统何时fsync,应用程序并不知道,如果操作系统崩溃,数据可能丢失。

刷盘策略

策略一:最佳性能(innodb_flush_log_at_trx_commit=0)

每隔一秒,才将Log Buffer中的数据批量write入OS cache,同时MySQL主动fsync。

这种策略,如果数据库奔溃,有一秒的数据丢失。

策略二:强一致(innodb_flush_log_at_trx_commit=1)

每次事务提交,都将Log Buffer中的数据write入OS cache,同时MySQL主动fsync。

这种策略,是InnoDB的默认配置,为的是保证事务ACID特性。

策略三:折衷(innodb_flush_log_at_trx_commit=2)

每次事务提交,都将Log Buffer中的数据write入OS cache;每隔一秒,MySQL主动将OS cache中的数据批量fsync。

问题:磁盘IO次数不确定,因为操作系统的fsync频率并不是MySQL能控制的。这种策略,如果操作系统奔溃,最多有一秒的数据丢失。因为OS cache 也会fsync,MySQL主动fsync的周期是一秒,所以最多丢一秒数据。

两阶段提交

redo log 的两阶段提交是为了保障redo log和bin log数据的一致性, 即mysql主从服务的数据一致性。

 这样直接看流程图,并不能直观的感受到两阶段提交的作用,我们分两步来理解两阶段提交起到的作用。

第一步:没有两阶段提交会发生什么?

  在没有两阶段提交的情况下,事务对redo log和bin log的写入顺序为:

1、事务执行过程中,写入redo log

2、事务完成后,写入bin log

  问题非常明显,如果在第二步执行时,MySQL宕机了,那么就会出现redo log中显示事务已经提交了,而bin log中并不存在对应的事务信息。

  此时,MySQL主机通过redo log恢复,MySQL从机通过bin log恢复,这就导致了MySQL主从架构下,主从机数据不一致的问题。

第二步:两阶段提交是如何解决这个问题的?

  两阶段提交将redo log的提交拆分为两次提交,此时事务对redo log和bin log的写入顺序为

1、事务执行过程中,写入redo log并标记redo log为prepare阶段

2、事务完成后,写入bin log

3、写完bin log后,标记redo log为commit阶段

  在这样的顺序下,即使在第二步执行时,MySQL宕机了,MySQL主机在恢复时,会有三种情况:

1、redo log的状态为commit,代表bin log也成功写入了,则提交事务

2、redo log的状态为prepare,但bin log中存在对应的事务信息,依旧提交事务

3、redo log的状态为prepare,并且bin log中不存在对应的事务信息,则回滚事务。

可以看到,两阶段提交成功保证了MySQL主从机的数据一致性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值