专注Java教育14年 全国咨询/投诉热线:444-1124-454
星辉LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 详解MySQL事务持久性实现

详解MySQL事务持久性实现

更新时间:2021-01-22 17:47:12 来源:星辉 浏览885次

所谓MySQL事务持久性就是事务一旦提交,就是永久性的,不会因为宕机等故障导致数据丢失(外力影响不保证,比如磁盘损害)。持久性是保证了MySQL数据库的高可靠性(High Reliability),而不是高可用性(Hign Availability)。

 

MySQL的innoDB存储引擎,使用Redo log保证了事务的持久性。当事务提交时,必须先将事务的所有日志写入日志文件进行持久化,就是我们常说的WAL(write ahead log)机制。这样才能保证断电或宕机等情况发生后,已提交的事务不会丢失,这个能力称为 crash-safe。

 

Redo log包括两部分,重做日志缓冲(redo log buffer)和重做日志文件(redo log file),前者是易失的缓存,后者是持久化的文件。

 

举一个事务的例子:

步骤1:begin;

步骤2:insert into t1 …r

步骤3:insert into t2 …

步骤4:commit;

这个事务的写入过程实际拆解如下:

 

 

重点关注在这个事务提交前,将redo log的写入拆成了两个步骤,prepare 和 commit,这就是"两阶段提交”。那么为什么要采用两阶段提交呢?

 

实际上,两阶段提交是分布式系统常用的机制。MySQL使用了两阶段提交后,也是为了保证事务的持久性。Redo log 和bingo 有一个共同的数据字段,叫 XID,崩溃恢复的时候,会按顺序扫描 redo log。

 

假设在写入binlog前系统崩溃,那么数据库恢复后顺序扫描 redo log,碰到只有 parepare、而没有 commit 的 redo log,就拿着 XID 去 binlog 找对应的事务,而且binlog也没写入,所以事务就直接回滚了。

 

假设在写入binlog之后,事务提交前数据库崩溃,那么数据库恢复后顺序扫描 redo log,碰到既有 prepare、又有 commit 的 redo log,就直接提交,保证数据不丢失。

 

这个事务要往两个表中插入记录,插入数据的过程中,生成的日志都得先写入redo log buffer ,等到commit的时候,才真正把日志写到 redo log 文件。(当然,这里不绝对,因为redo log buffer可能因为其他原因被迫刷新到redo log)。

 

而为了确保每次日志都能写入日志文件,在每次将重做日志缓冲写入重做日志文件后,InnoDB存储引擎都需要调用一次fsync操作,确保写入了磁盘。

对于redo log的持久化,可以如下图所示。

 

 

1)先写入redo log buffer,在蓝色区域。

2)写入redo log file,但是还没有fsync,这时候是处于黄色的位置,处于系统缓存。

3)调用fsync,真正写入磁盘。

为了控制 redo log 的写入策略,InnoDB 提供了 innodb_flush_log_at_trx_commit 参数,它有三种可能取值:

设置为 0 的时候,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中 ;

设置为 1 的时候,表示每次事务提交时都将 redo log 直接持久化到磁盘;

设置为 2 的时候,表示每次事务提交时都只是把 redo log 写到 page cache。

binlog的写入和redo log一样,也是包括bingo cache和bingo file,同样跟上面的三色层次类似(当然,binlog是server层的,不是存储引擎层的),包括log buffer、文件系统page cache、hard disk。

写入page cache 和 fsync到disk 的时机,是由参数 sync_binlog 控制的:

sync_binlog=0 的时候,表示每次提交事务都只 写入文件系统的page cache,不 fsync;

sync_binlog=1 的时候,表示每次提交事务都会执行 fsync;

sync_binlog=N(N>1) 的时候,表示每次提交事务都写入文件系统的page cache,但累积 N 个事务后才 fsync。(如果主机发生异常重启,会丢失最近 N 个事务的 binlog 日志)

通常我们说MySQL的“双 1”配置,指的就是sync_binlog和 innodb_flush_log_at_trx_commit 都设置成 1。也就是说,一个事务完整提交前,需要等待两次刷盘,一次是 redo log(prepare 阶段),一次是 binlog。

 

以上就是MySQL的innoDB存储引擎,使用Redo log实现了MySQL事务持久性。除此之外,MySQL事务的其他特性也有着各自各样的机制来实现,详情可以观看本站的MySQL教程,展开拓展性的学习。

 

 

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>