Mysql事务实现原理

Redo Log 基本概念:

Redo Log 也被叫重做日志,Mysql中事务的原子性和持久性是由Redo Log 实现的 ,主要记录的是物理日志,也就对磁盘上的数据进行的修改操作,Redo Log 通常包含两部分,一部分是内存中的日志缓冲,称作Redo LogBuffer 这部分日志容易丢失,另外一部分放在磁盘上的重做日志文件,称作Redo Log File 这部分是持久化到磁盘上的,不容易丢失。

Redo Log 基本原理:

Redo Log 能够保证事务的原子性和持久性,在MySQL发生故障时,尽力避免内存的脏页数据写入到数据表的IBD文件,在重启MySQL服务时,可以根据Redo Log恢复事务已经提交但是还未写入IBD文件中的数据,从而对事务提交的数据进行持久化操作

Mysql 提交事务时,会将数据写入到Redo Log buffer ,而Redo Log buffer中的数据会根据一定的规则写入Redo Log 文件

Redo Log 刷盘规则:

InnoDB存储引擎中,通过提交事务时强制执行写日志操作机制实现事务的持久化,为了保证事务提交时,将日志提交到事务日志文件中,默认每次将Redo Log Buffer 中的日志写入日志文件时,都调用一次操作系统的 fsync() 操作。

注意点:想将Log Buffer 中的数据持久化到磁盘的日志文件中,还需要经过操作系统的内核空间缓冲区,也就是OS Buffer

  • 开启事务,发出提交事务指令后是否刷新日志有变量 innodb_flush_log_at_trxcommit决定
  • 每秒刷新一次,刷新日志的频率由变量innodb_flush_log_at_timeout的值决定的,默认是1s,需要注意的是,刷新日志的频率和是否执行了commit操作无关
  • 当Log Buffer 中已经使用的内存超过了一半时,也会触发刷盘操作
  • 当事务中存在checkpoint(检查点)时,在一定程度上代表了刷写到磁盘时日志所处的LSN的位置,其中LSN表示日志的逻辑序列号

规则说明:

当事务提交时,需要先将事务日志写入Log Buffer,这些写入Log Buffer的日志并不是随着事务的提交立刻写入磁盘的,而是根据一定的规则将Log Buffer中的数据刷写到磁盘,从而保证了Redo Log文件中的数据的持久化,这种刷盘规则可以通过innodb_flush_log_at_trx_commit 变量控制,innodb_flush_log_at_trx_commit变量可取的值有0、1、2,默认是1

  • 变量0,提交事务时,不会将Log Buffer的日志写入OS Buffer,而是通过一个单独的线程,每秒写入OS Buffer并调用fsync() 函数写入磁盘的Redo Log文件,这种方式不是实时写磁盘的,而是每隔1s写一次日志,如果系统崩溃,可能会丢失1s的数据,插入10w条数据 2.18s
  • 变量1,每次提交事务都会将Log Buffer 中的日志写入OS Buffer,并且会调用fsync() 函数将日志数据写入磁盘的Redo Log文件中,性能相对比较差,几乎不会丢失数据,系统默认为1,插入10w条数据 9.32s
  • 变量2,每次提交事务时,都只是将数据写入OS Buffer,之后每隔1s 通过fsync() 函数将OS Buffer中的日志数据同步写入磁盘的Redo Log 文件中 ,插入10w条数据 3.05s

Redo Log 写入机制:

Redo Log 主要记录的是物理日志,其文件内容是以顺序的方式写入的,一个文件写满时会写入另外一个文件,最后一个文件写满时,会向第一个文件写数据,而且是覆盖写

  • Write Pos 是数据表中当前记录的所在位置,会向后移动,当移动到最后一个文件的最后一个位置的时候,又会重新回到第一个文件的开始位置进行写操作
  • CheckPoint 是当前要擦除的位置,也是会向后移动,当移动到最后一个文件的最后一个位置的时候,又会重新回到第一个文件的开始位置进行擦除操作

Redo Log 的LSN机制

LSN表示日志的逻辑序列号,在InnoDB存储引擎中,LSN占用8个字节,而且LSN的值是单调递增的,包含的信息主要有:

  • Redo Log 写入数据的总量
  • 检查点的位置
  • 数据页版本相关的信息

主要的参数有:

  • Log sequence number:表示当前内存缓冲区中的Redo Log 的LSN
  • Log flushed up to : 表示刷新到磁盘上的Redo Log 文件的LSN
  • Pages flushed up to : 表示已经刷新到磁盘数据页上的LSN
  • Last checkpoint at :表示上一次检查点所在的位置的LSN

Redo Log相关参数

  • innodb_log_buffer_size:表示log buffer的大小,默认8Mb
  • innodb_log_file_size:表示事务日志的大小,默认为5MB
  • innodb_log_files_group=2:表示事务日志组中的事务日志文件个数,默认为2个
  • innodb_log_group_home_dir=./:表示事物日志组所在的目录,当前目录表示Mysql数据所在的目录

Undo Log 基本概念

Undo Log 在Mysql事务实现中主要起着两方面的作用:回滚事务和多版本并发事务,也就是常说的MVCC机制,事务的一致性就是由其决定的。其主要发生在事务开始前,会存储要修改的数据到Undo Log 中,事务进行回滚或者奔溃,可以利用其进行回滚操作,保证数据一致性。事务提交后Undo Log 会放入待删除的列表,等待后台的线程进行删除操作

注意点:产生Undo Log的过程也是需要进行持久化操作,所以也会生成Redo Log,所以数据库奔溃恢复过程会先做Redo Log的数据恢复,然后做Undo Log回滚

Undo Log存储方式

Undo Log 存储方式采用的段的方式进行管理,数据文件中存在一种叫做rollback segment的回滚段,内部有1024个undo log segment段,默认存储在共享数据表空间中,默认为ibdata1文件中,可以通过开启innodb_file_per_table 参数,将Undo Log 存放在每个数据表的.ibd中

可以通过修改innodb_undo_tablespaces 变量将回滚段平均分配搭配多个文件中,默认为0

Undo Log 基本原理

Undo Log 写入磁盘时和Redo Log 一样,默认情况下都需要经过内核空间的OS Buffer,如果在打开日志文件是设置了O_DIRECT标志位,就可以不经过操作系统内核空间的OS Buffer,直接向磁盘写数据,这点跟Redo Log 是一样的

Undo Log 实现MVCC机制

Undo Log 除了实现事务的回滚操作外,另外一个重要的作业就是实现多版本并发控制,也就是MVCC机制,在事务提交之前,向Undo Log保存事务当前的数据,这些保存到Undo Log中的旧版本数据可以作为快照供其他并发事务进行快照读

Undo Log 回滚段中,分insert undo log 和 update undo log

  • insert undo log:事务对插入新纪录产生的Undo Log ,只有在事务回滚的时候需要,在事务提交就可以立即丢弃
  • update undo log:事务对记录进行删除或者更新操作时产生的Undo Log ,不仅在事务回滚时需要,在一致性读时也需要,因此不能随便删除,只有但数据库所使用的的快照不涉及该日志了,就可以删除了

MVCC机制原理

InnoDB存储引擎在数据表的每行记录后面保存了两个隐藏列,一个列保存行的创建版本,另外一个隐藏列保存行的删除版本,每次开启一个新事务,这些版本号就会递增。

在可重复读的隔离级别下,MVCC机制在增删查改操作下分别按照如下方式实现:

  • select:只会查找小于或者等于当前事务版本号的数据行,这样可以保证事务读取到的数据要么之前就已经存在了,或者是当前事务自身插入的或者修改的数据,另外行的删除版本要么未定义,要么大于当前事务的版本号,这样可以保证事务读取的行在事务开始之前没有被删除
  • insert:将当前事务的版本号保存为当前行的创建版本号
  • delete:将当前事务的版本号保存为当前行的删除的数据行的删除版本号,作为行删除标识
  • update:将待修改的行复制为新的行,将当前事务的版本号保存为新数据行的创建版本号,同时保存当前事务版本号为原来数据行的删除版本号,被赋值了删除版本号的数据并不会马上被删除,而是进入一个待删除的队列,由存储引擎开启的后台线程进行处理

MVCC机制其中涉及到3个字段:6个字节的事务ID(DB_TRX_ID)字段、7个字节的回滚指针(DB_ROLL_PTR)字段、6字节的DB_ROW_ID字段

  • DB_TRX_ID:用来标识最近一次对本行记录做修改(insert,update)的事务的标识,既最后一次修改本行记录的事务ID,如果是delete操作,内部也属于一次update操作,既更新行中的一个特殊位,将行标识为已删除,并非真正的删除
  • DB_ROLL_PTR:主要指向上一个版本的行记录,能够从最新版本的行记录逐级向上,找到要查找的行版本记录
  • DB_ROW_ID:包含一个随着新数据的插入操作而单调递增的行id

Undo Log 相关参数

  • Innodb_max_undo_log_size:表示Undo Log 控件的最大值,当超过这个阈值(默认1G),会触发truncate回收操作,回收操作后,Undo Log空间缩小10MB
  • innodb_undo_directory:表示Undo Log存储目录
  • innodb_undo_log_encrypt:Mysql8中新增的参数,表示Undo Log是否加密,OFF表示不加密,ON表示加密,默认为OFF
  • innodb_undo_log_truncate:表示是否开启在线回收Undo Log 文件操作,支持动态设置,ON表示开启,OFF表示关闭,默认为OFF
  • innodb_undo_logs:表示Undo Log 的回滚段数量,此参数的值至少大于或者等于35,默认为128
  • innodb_purge_rseg_truncate_frequency:用于控制回收Undo Log的频率,Undo Log空间在回滚段释放之前是不会回收的,要想增加释放回滚区间的频率,就要降低innodb_purge_rseg_truncate_frequency这个的值

BinLog 基本概念

BinLog是一种记录所有Mysql数据库表结构变更以及表数据变更的二进制日志,BinLog中不会记录类似select和show这类的查询操作日志,同时,BinLog是以事件形式记录相关变更操作的,主要有Query Event、Row Event、Xid Event,以及包括语句执行所耗费的时间,主要的使用场景是:

  • 主从复制:在主数据库上开启BinLog,主数据库吧BinLog发送至从数据库,从数据库获取BinLog后通过I/O线程将日志写到中继日志中,也就是Relay Log 中,然后通过SQL线程将Relay Log中的数据同步至从数据库,从而达到主从数据库的一致性
  • 数据恢复:当Mysql数据库发生故障或者崩溃时,可以通过BinLog进行数据恢复

BinLog记录模式

  • Row模式:优点:会记录每一行数据被修改的情况,完全实现主从数据库的同步跟数据的恢复,缺点:批量处理会出现大批量的二进制日志,影响主从数据库的同步性能
  • Statement模式:优点:会记录每一条数据被修改的SQL语句,由于不会记录数据的修改细节,只是记录数据表结构和数据变更的SQL语句,所以二进制日志数据量比较小,减少磁盘的I/O,提升数据库存储和恢复效率。缺点:可能导致主从数据库中数据的不一致,当使用了last_insert_id()和now(),就会导致数据的不一致
  • Mixed模式:是Row模式和Statement模式的混用,一般使用Statement模式保存BinLog,如果存在无法复制的,就会使用Row模式进行保存BInLog

BinLog写入机制

Mysql事务提交的时候,会记录事务日志和二进制日志,也就是Redo Log 和BinLog,由于Redo Log 是InnoDB存储引擎所独有的,BinLog是Mysql本身就有的上层日志,所以会优先于InnoDB的事务日志被写入,所以BinLog日志会先Redo Log日志先写入系统

Mysql在写入BinLog文件时,会按照以下的步骤进行写操作:

  1. 根据记录的模式(Row、Statement、Mixed)和操作(create、drop、alert、insert、update)触发事件生成日志事件(事件触发执行机制)
  2. 将事务执行过程中产生的日志事件写入相应的缓冲区,注意,这里是每个事务线程都有的一个缓冲区,日志事件保存在数据结构binlog_cache_mngr中,这个数据结构有2个缓冲区,stmt_cache,用于存放不支持事务的信息,trx_cache用于存放支持事务的信息
  3. 事务在Commit阶段会将产生的日志事件写入到磁盘的BinLog文件中,事务的执行是以串行的形式,所以一个事务中包含的日志事件信息在BinLog文件中是连续的,中间不会插入其他事务的日志事件

Mysql二进制日志组提交功能(BLGC)

Mysql5.6及以上提供了二进制日志组提交的功能,主要分为Flush、Sync和Commit三个阶段

  • Flush阶段:将每个事务的BinLog写入对于的内存缓存区中,正常等待一定时间,多累计几个事务的日志后一起进去下一个阶段
  • Sync阶段:将内存缓冲区中的BinLog写入磁盘的BinLog文件,如果队列中存在多个事务,此时只需要执行一次刷盘操作就可以将多个事物的BinLog刷新到磁盘的BinLog文件中,这就是BLGC操作
  • Commit阶段:Leader事务根据队列中事务的顺序调用存储引擎层事务的提交操作,此阶段不会阻塞其他阶段的执行

BinLog 与Redo Log的区别

BinLog与Redo Log 在一定程度上都能恢复数据,但是二者有着本质上的区别,具体内容如下:

  1. BinLog是Mysql本身就拥有的,不管使用何种存储引擎,BinLog都存在,而Redo Log是InnoDB存储引擎特有的,只有InnoDB存储引擎才会输出Redo Log
  2. BinLog 是一种逻辑日志,记录是对数据库的所有修改操作,而Redo Log是一种物理日志,记录是每个数据页的修改
  3. Redo Log具有幂等性,多次操作的前后状态是一致的,而BinLog不具有幂等性,记录是所有影响数据库的操作
  4. BinLog开启事务时,会将每次提交的事务一次性写入内存缓冲区,如果未开启事务,则每次成功执行、更新、和删除语句时,就会将对应的事务信息写入内存缓冲区,而Redo Log是在数据准备修改之前将数据写入缓冲区的Redo Log中,然后在缓冲区中修改数据,在提交事务时,先将Redo Log写入缓冲区,写入完成后在提交事务
  5. BinLog只会在事务提交时,一次性写入BinLog,其日志的记录方式与事务的提交顺序有关,并且一个事务的BinLog中间不会插入其他事务的BinLog,而Redo Log记录的是物理页的修改,最后一个提交的事务记录会覆盖之前所有未提交的事务记录,并且一个事务的Redo Log 中间会插入其他事务的Redo Log
  6. BinLog 是追加写入,写完一个日志文件再写入下一个日志文件,不会覆盖使用,而Redo Log是循环写入的,日志空间大小是固定的,会覆盖使用
  7. BinLog一般用于主从复制和数据恢复,并且不具备崩溃自动恢复的能力,而Redo Log在服务器发生故障后重启Mysql,用于恢复事务已提交但是未写入数据表的数据

BinLog相关参数

  • log_bin:表示开启二进制日志,未指定BinLog的目录时,会在Mysql的数据目录下生产BinLog
  • log_bin_index:设置此参数可以指定二进制索引文件的路径和名称
  • binlog_do_db:表示只记录指定数据库的二进制日志
  • binlog_ignore_db:表示不记录指定数据库的二进制日志
  • max_binlog_size:表示BinLog的最大值,默认值为1GB
  • sync_binlog:这个参数会影响Mysql的性能和数据的完整性,取的数据值影响到底提交多少个事务后才执行fsync()函数
  • max_binlog_cache_size:表示BinLog占用的最大内存
  • binlog_cache_use:表示使用BinLog缓存的事务的数量
  • binlog_cache_disk_use:表示使用BinLog缓存但超过binlog_cache_size的值,并且使用临时文件来保存SQL语句中的事务数量

注意:Mysql默认不开启BinLog日志,需要自己手动开启

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值