JAVA

3.1、事务日志

2022-05-26  本文已影响0人  flyjar

Mysql事务日志
前言
一、事务四大特性ACID的实现机制
二、REDO日志
1.为什么需要REDO日志?
2.REDO日志的好处和特点?
3.REDO的组成
4.REDO的整体流程
5.REDO的刷盘策略
三、UNDO日志
1.为什么需要UNDO日志?
2.UNDO LOG的作用
3.UNDO LOG的组成
3.1.回滚段与undo页
3.2.回滚段与事务
3.3.回滚段中的数据分类
3.4.undo的类型
3.5.undo log的生命周期
最后
前言
  上一章《Mysql数据库事务四大特性、事务状态、事务使用、事务隔离级别》讲到了事务有4种特性:原子性、一致性、隔离性、持久性。那么 ,这些特性到底是基于什么机制实现的呢?本章理论或许枯燥,但是,我们不正是要会别人不会的,才能安享35岁晚年吗?

一、事务四大特性ACID的实现机制
  事务的隔离性由锁机制实现;
  事务的原子性、一致性、持久性由REDO LOG和UNDO LOG实现的。
  REDO LOG称为重做日志,提供在写入操作,恢复提交事务修改的页操作,用来保证事务的持久性;
  UNDO LOG称为回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。
注意:
  UNDO LOG并不是REDO LOG的逆过程,二者都是一种恢复操作。
  REDO LOG是存储引擎层(Innodb)生成的日志,记录的是物理级别上的页修改操作,比如页号,偏移量 写入‘ddd’数据,主要为了保证数据可靠性。
  UNDO LOG是存储引擎层(Innodb)生成的日志,记录的是逻辑操作,比如当用户进行insert操作时,UNDO LOG就记录一条与之相反的delete操作,主要用于事务回滚和一致性非锁定读(undo log回滚行记录到某种特定的版本…MVCC,即多版本并发控制)。

二、REDO日志
  InnoDB存储引擎是以页为单位来管理存储空间的,会将磁盘上的页缓存到内存buffer Pool之后才可以访问,所有变更都必须先更新缓冲池中的数据,然后缓冲池中的脏页(脏页:与磁盘页数据发生变化的页)会以一定的频率刷入到磁盘(checkPoint机制),通过缓冲池来优化CPU和磁盘之间的鸿沟,保证性能。

1.为什么需要REDO日志?
  checkPoint是操作系统master线程隔一段时间去处理的,所以最坏的情况是事务提交后,刚写完缓冲池,数据库宕机了,那么这段数据就是丢失了,违背了“事务提交后,对数据修改不能丢失”的原则。那么如何保证这个持久性呢?有人会说,在事务提交完成后立即把修改刷新到磁盘,但是这个简单粗暴的做法有些问题:
(1)修改量与刷新磁盘工作量严重不成比例
  Innodb是以页为单位来进行磁盘IO的,页默认是16kB,如果我们只修改了一个字节就要刷新16KB的数据到磁盘上,显然小题大做了。
(2)随机IO刷新较慢
  一个事务包含很多语句,即使是一条语句也可能修改很多页,而且这些页并不相邻,那么在刷盘时,随机IO比顺序IO要慢,特别是传统机械硬盘。

另一个解决思路:我们不需要把每次commit的修改都立即更新到磁盘,只需要把修改了哪些东西记录一下就好,比如:某个事务将系统空间中第10号页中偏移量为100处的值更新成2。
  Innodb引擎的事务采用WAL技术,就是先写日志,在写磁盘,只要日志写入成功,才算事务提交成功,这里的日志就是REDO LOG,当数据库突然宕机,重启时也能通过REDO LOG恢复数据,保证持久性,这就是REDO LOG的作用。

2.REDO日志的好处和特点?
好处:
(1)REDO日志降低了刷盘频率;
(2)REDO日志占用的空间非常小。
  存储表空间ID、页号、偏移量以及要更新的值,存储空间小,刷新快。

特点:
(1)REDO日志是顺序写入磁盘的;
  当一条执行语句产生多条redo日志时,是顺序写入磁盘的,也就是顺序IO,效率比随机IO快。
(3)事务执行过程中,redo log不断记录
  Redo log和bin log的区别,redo log是存储引擎层的,bin log是数据库层的。比如,一个事务对表做10万条插入,在这个插入过程中,会持续往redo log中记录。直到事务提交时,才会一次写入到bin log文件中。

3.REDO的组成
(1)重做日志缓存(redo log buffer)
保存在内存中,在Mysql服务器启动时,会向操作系统申请一大片称为redo log buffer的连续内存空间,翻译中文叫“redo日志缓冲区”,这片内存空间被划分成若干个联系的redo log block,一个redo log block占用512字节大小。
注意:redo log buffer默认16M,最大是4096M,最小是1M。

(2)重做日志文件(redo log file)

4.REDO的整体流程

5.REDO的刷盘策略
  Innodb以一定频率将redo log buffer中的数据刷新到磁盘(redo log file)中,这个一定频率是分刷盘策略的。
注意:
  这里的刷盘不是只是真正刷到磁盘中,只是刷入到文件系统缓存(page cache)中去(这是现代操作系统为了提高文件写入效率做的一个优化),真正写入会交给系统自己来决定。
  如果page cache足够大,那么对于Innodb来说,就存在一个问题,如果系统宕机,那么数据依然会丢失。
  另外,Innodb存储引擎有一个后台线程,每隔1s,就会把redo log buffer中的内容写到文件系统缓存(page cache),然后调用刷盘操作。也就是说,一个没有提交事务的redo log记录,也可能会刷盘,因为在事务执行过程中redo log记录是会写入redo log buffer中,这些redo log记录会被后台线程刷盘。

Innodb给出Innodb_flush_log_at_trx_commit参数:
设置为0:表示每次事务提交时只是写到redo log buffer里(系统默认master thread每隔1s进行一次重做日志的同步)。
事务提交成功,数据也仅仅只是写到redo log buffer里,这时如果Mysql挂了,会丢失1s的数据。

设置为1:表示每次事务提交时都将进行同步,并立即刷盘操作(默认)。
因此,只要事务提交成功,redo log记录一定在磁盘里,不会有数据丢失,但是效率最差。

设置为2:表示每次事务提交时都只把redo log buffer内容写入page cache,由系统默认master thread每隔1s进行一次重做日志的同步。
因此,只要事务提交成功,redo log记录一定写到文件系统缓存中,这时Mysql挂了不会有数据丢失,这时操作系统挂了可能会丢失1s的数据,但是效率高。

效率对比:

三、UNDO日志
1.为什么需要UNDO日志?
  事务需要保证原子性,要么都成功,要么都失败。当事务失败时,就需要把数据改回原先的样子,这个过程叫“回滚”。
  当你插入一条数据时,至少要把数据记下来,方便回滚时删除。
  当你删除一条记录时,至少要把数据记下来,方便回滚时插入。
  当你更新一条记录时,至少把旧值记下来,方便回滚是恢复。
  这些为了回滚而记录的内容,就称为“回滚日志”或“UNDO LOG”。
注意:
(1)查询是不会修改记录,所有不会记录UNDO LOG。
(2)undo log也会产生redo log,这是因为undo log也需要持久性的保护。

2.UNDO LOG的作用
回滚数据:只是将数据库逻辑地恢复原来的样子,对物理层面的数据结构和页本身的变化是无法恢复的。
MVCC:Innodb存储引擎中MVCC的实现是通过undo来完成的。当用户读一条已经被其他事务占用的数据时,当前事务可以通过undo读取之前的行版本信息,以此实现非锁定读取。

3.UNDO LOG的组成
3.1.回滚段与undo页
  Innodb对undo log的管理采用段的方式,也就是回滚段(rollback segment),每个回滚段记录了1024个undo log segment,而在每个undo log segment段中进行undo页的申请。
  在Innodb1.1版本之前,只有一个rollback segment,因此最大同时只支持1024个事务。
  在Innodb1.1版本开始,有128个rollback segment,因此最大同时只支持128*1024个事务。
  可以通过SHOW VARIABLES like '%undo%'查看,虽然支持128个rollback segment,但是这些rollback segment都存储在共享表空间ibdata中。
  在Innodb1.2版本开始,可以通过参数对rollback segment进行设置:

innodb_undo_tablespaces=3 #设置为3个
innodb_undo_logs=128 #默认128个
innodb_undo_directory =/dbfiles/mysql_home/undologs
1
2
3
MySQL设置undo为独立表空间

Undo页的重用
  我们知道,Mysql默认一页大小是16k,为每一个事务分配页,是非常浪费的。
  举个例子:假设一个场景,一秒处理的事务数是1000,一秒需要16M。一分钟大概需要1G的存储。要求Mysql必须非常快速清理,否则,磁盘占用会越来越大。
  因此,undo页设计的也是可以重用的。Undo log提交后,并不会删除undo页,会被放到一个链表中,然后判断undo页的使用空间是否小于四分之三,是的话,undo页会被重用。

3.2.回滚段与事务
  每一个事务只使用一个回滚段,一个回滚段在同一时刻可能服务于多个事务。
  事务进行过程中,当数据修改时,原始的数据会被复制到回滚段。
  当事务提交时,Innodb存储引擎会做以下两件事情:
  (1)将undo log放入列表中,以供之后的purge操作;
  (2)判断undo log所在的页是否可以重用,若可以分配给下一个事务使用。

3.3.回滚段中的数据分类
(1)未提交的回滚数据;
(2)已提交未过期的回滚数据。
(3)已提交已过期的回滚数据。
  事务提交之后并不能立即删除undo log和所在的页,因为可能有其他事务需要通过undo log来得到行记录之前的版本。因此事务提交后会将undo log放入一个链表中,是否可以最终删除undo log和所在的页,由purge线程来判断。

3.4.undo的类型
在Innodb存储引擎中,undo log分为:
(1)insert undo log
插入的undo log,因为对其他事务不可见,所以commit提交后直接删除,不需要purge。
(2)update undo log
修改和删除的undo log,因为undo log可能需要提供MVCC机制,所以commit提交后不能直接删除,需要purge。

3.5.undo log的生命周期

上一篇下一篇

猜你喜欢

热点阅读