前言: 本小节将围绕Redo Log 、Undo Log 、Bin Log 展开,从某种程度上来说,事务的隔离性是由锁和MVCC机制实现的,原子性和持久性是由Redo Log实现的,一致性是由Undo Log实现的
Redo Log
概念
原子性和持久性是由Redo Log实现的,它确保了事务提交后,事务所设计的所有操作要么全部成功,要么全部失败。
Redo Log主要记录的是物理日志,也就是对磁盘上的数据进行修改操作。
主要包含两部分:
- 内存中的日志缓冲,易丢失,即 Redo Log Buffer
- 磁盘上的重做日志文件,不易丢失,即 Redo Log File
相关参数: show variables like ’ %innodb_log%’;
基本原理
发生故障时,尽力避免内存中的脏页数据写入数据表IBD文件中,从而使得在重启MySQL服务时,可以根据Redo Log恢复已提交事务但还未写入IBD文件中的数据,实现持久化。
刷盘规则
在MySQL的InnoDB存储引擎中,通过提交事务时强制执行写日志操作机制实现事务的持久化,会调用一次操作系统的fsync()操作,因为是Log Buffer工作在操作系统的用户空间中,所以持久化到磁盘中的过程需要经过操作系统的内核空间缓冲区 OS Buffer(没有使用O_DIRECT标识位)。
进行刷盘的几种规则:
- 开启事务,同时提交事务命令是否刷盘 ,由innodb_flush_log_at_trx_commit决定
- 每秒刷新一次。由innodb_flush_log_at_timeout的值决定,默认是1s。
- Log Buffer已使用内存过半
- 当事务中存在checkPoint。
其中第一条,innodb_flush_log_at_trx_commit变量可取的值有0、1和2,默认为1。
结论: 0 最快 其次是2,最后才是1,0与2性能很高,但存在1s的数据崩坏丢失。
写入机制
Redo Log主要记录的是物理日志,其文件内容是以顺序循环的方式写入的,一个文件写满时会写入另一个文件,最后一个文件写满时,会向第一个文件写数据,并且是覆盖写
- Wirte Pos是数据表中当前记录所在的位置,随着不断地向数据表中写数据,这个位置会向后移动
- CheckPoint是当前要擦除的位置,这个位置也是向后移动的,移动到最后一个文件的最后一个位置时
- Write Pos和CheckPoint之间存在间隔时,中间的间隔表示还可以记录新的操作。如果Write Pos移动的速度较快,追上了CheckPoint,则表示数据已经写满,不能再向Redo Log文件中写数据了
Undo Log
概念
MySQL中事务的一致性是由Undo Log实现的。可以进行事务回滚或当数据库崩溃时,对未提交的事务进行回滚操作,在恢复崩溃时先Redo Log数据恢复,后做Undo Log回滚。
Undo Log记录的是逻辑日志,会在事务开始前产生,可以直接当数据库执行一条insert语句时,Undo Log记录一条对应的delete语句。
主要作用:回滚事务和多版本并发事务(MVCC)
存储方式
- InnoDB存储引擎对于Undo Log的存储采用段的方式进行管理,在InnoDB存储引擎的数据文件中存在一种叫作rollback segment的回滚段,这个回滚段内部有1024个undo log segment段.
- Undo Log默认存放在共享数据表空间中,默认为ibdata1文件中。如果开启了innodb_file_per_table参数,就会将Undo Log存放在每张数据表的.ibd文件中
- 默认情况下,InnoDB存储引擎会将回滚段全部写在同一个文件中,也可以通过innodb_undo_tablespaces变量将回滚段平均分配到多个文件中
基本原理
- Undo Log写入磁盘时和Redo Log一样,默认情况下都需要经过内核空间的OSBuffer
- MySQL数据库事务提交之前,InnoDB存储引擎会将数据表中修改前的数据保存到Undo Log Buffer,最终Undo Log Buffer中的数据会持久化到磁盘的Undo Log文件中
MVCC实现
多版本并发控制(MVCC)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。事务提交之前,会向Undo Log保存事务当前的数据,这些旧版本数据可以作为快照供其他并发事务进行快照读。它的实现原理主要是依赖记录中的 3个隐式字段,undo日志 ,Read View 来实现的
什么是 MySQL InnoDB 下的当前读和快照读?
-
当前读
像 select lock in share mode (共享锁), select for update; update; insert; delete (排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁 -
快照读
像不加锁的 select 操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即 MVCC ,可以认为 MVCC 是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本
Undo Log的回滚段中,undo logs分为insert undo log和update undo log。
1)insert undo log:事务对插入新记录产生的Undo Log,只在事务回滚时需要,在事务提交后可以立即丢弃。
2)update undo log:事务对记录进行删除和更新操作时产生的Undo Log,不仅在事务回滚时需要,在一致性读时也需要,因此不能随便删除,只有当数据库所使用的快照不涉及该日志记录时,对应的回滚日志才会被purge线程删除
三个point的概念
- DB_TRX_ID :6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID
- DB_ROLL_PTR:7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里)
- DB_ROW_ID:6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引
对MVCC有帮助的实质是update undo log ,undo log实际上就是存在rollback segment中旧记录链,它的执行流程如下
Read View
主要就是维护了一个版本链,然后通过以下几个属性进判断是否可以读取,其中RC每次select生产一次Read View,RR整个事务只生成一次
- m_ids:还没有提交的事务
- min_trx_id: 未提交事务中最小的
- max_trx_id: 已生成的最大事务,不管提没提交
- creator_trx_id:当前生成该ReadView的事务id
判断规则:
1) trx_id == creator_trx_id :自己修改的版本,可以访问
2)trx_id < min_trx_id: 说明已经提交了,可以访问
3)trx_id > max_trx_id:说明是版本链之后的数据,不可访问
4)min_trx_id <= trx_id <= max_trx_id: 如果在trx_id 在 m_ids中则不可访问,否则则可以
总结: 根据Read View得到的版本链,从上到下,如果处于已提交或就是当前事务数据,则可访问,亦或者,它处于最大与最小trx_id之间,但不属于活跃数组中,则也可访问,其他情况不可访问
BinLog
Redo Log是InnoDB存储引擎特有的日志,MySQL也有其自身的日志,这个日志就是BinLog,即二进制日志
基本概念
BinLog是一种记录所有MySQL数据库表结构变更以及表数据变更的二进制日志。
最重要的使用场景:
1)主从复制:在主数据库上开启BinLog,主数据库把BinLog发送至从数据库,从数据库获取BinLog后通过I/O线程将日志写到中继日志,也就是Relay Log中。然后,通过SQL线程将Relay Log中的数据同步至从数据库,从而达到主从数据库数据的一致性。
2)数据恢复:当MySQL数据库发生故障或者崩溃时,可以通过BinLog进行数据恢复。例如,可以使用mysqlbinlog等工具进行数据恢复
记录模式
BinLog文件中主要有3种记录模式,分别为Row、Statement和Mixed
- Row模式下的BinLog文件会记录每一行数据被修改的情况,大批量操作会产生大量文件。
- Statement模式下的BinLog文件会记录每一条修改数据的SQL语句,比如now()等函数就会有问题了。
- Mixed模式下的BinLog是Row模式和Statement模式的混用
写入机制
binlog的写入逻辑比较简单:事务执行过程中,先把日志写到binlog cache,这个操作会调用write方法,并没有把数据持久化到磁盘,速度比较快;事务提交的时候,再把binlog cache写到binlog文件中,这步会调用fsync将数据持久化到磁盘,速度比较慢。
write和fsync的时机,是由参数sync_binlog控制的:
sync_binlog=0的时候,表示每次提交事务都只write,不fsync。
sync_binlog=1的时候,表示每次提交事务都会执行fsync。
sync_binlog=N(N>1)的时候,表示每次提交事务都write,但累积N个事务后才fsync。
在出现IO瓶颈的场景中,将sync_binlog设置成一个比较大的值,可以提升性能。实际业务场景中,通常设置为100~1000中的某个数值。这样做对应的风险是:如果主机发生一场重启,会丢失最近N个事务的binlog。
BinLog与Redo Log的区别
BinLog和Redo Log在一定程度上都能恢复数据,但是二者有着本质的区别,具体内容如下。
1)BinLog是MySQL本身就拥有的,不管使用何种存储引擎,BinLog都存在,而Redo Log是InnoDB存储引擎特有的,只有InnoDB存储引擎才会输出Redo Log。
2)BinLog是一种逻辑日志,记录的是对数据库的所有修改操作,而Redo Log是一种物理日志,记录的是每个数据页的修改。
3)Redo Log具有幂等性,多次操作的前后状态是一致的,而BinLog不具有幂等性,记录的是所有影响数据库的操作。例如插入一条数据后再将其删除,则RedoLog前后的状态未发生变化,而BinLog就会记录插入操作和删除操作。
4)BinLog开启事务时,会将每次提交的事务一次性写入内存缓冲区,如果未开启事务,则每次成功执行插入、更新和删除语句时,就会将对应的事务信息写入内存缓冲区,而Redo Log是在数据准备修改之前将数据写入缓冲区的Redo Log中,然后在缓冲区中修改数据。而且在提交事务时,先将Redo Log写入缓冲区,写入完成后再提交事务。
5)BinLog只会在事务提交时,一次性写入BinLog,其日志的记录方式与事务的提交顺序有关,并且一个事务的BinLog中间不会插入其他事务的BinLog。而RedoLog记录的是物理页的修改,最后一个提交的事务记录会覆盖之前所有未提交的事务记录,并且一个事务的Redo Log中间会插入其他事务的Redo Log。
6)BinLog是追加写入,写完一个日志文件再写下一个日志文件,不会覆盖使用,而Redo Log是循环写入,日志空间的大小是固定的,会覆盖使用。
7)BinLog一般用于主从复制和数据恢复,并且不具备崩溃自动恢复的能力,而Redo Log是在服务器发生故障后重启MySQL,用于恢复事务已提交但未写入数据表的数据。
两阶段提交
流程图
前言知识
MySQL为了提升性能,引入了BufferPool缓冲池。查询数据时,先从BufferPool中查询,查询不到则从磁盘加载在BufferPool。
每次对数据的更新,也不总是实时刷新到磁盘,而是先同步到BufferPool中,涉及到的数据页就会变成脏页。
同时会启动后台线程,异步地将脏页刷新到磁盘中,来完成BufferPool与磁盘的数据同步。
为什么要写redo log
防止MysSQL崩溃发生在写binlog后,刷脏前。在主从同步的情况下,从节点会拿到多出来的一条binlog,而主节点没有这条记录,因此binlog是不支持崩溃恢复的
为什么要写两次redo log
先写binlog,再写redo log
当前事务提交后,写入binlog成功,之后主节点崩溃。在主节点重启后,由于没有写入redo log,因此不会恢复该条数据。
而从节点依据binlog在本地回放后,会相对于主节点多出来一条数据,从而产生主从不一致。
先写redo log,再写binlog
当前事务提交后,写入redo log成功,之后主节点崩溃。在主节点重启后,主节点利用redo log进行恢复,就会相对于从节点多出来一条数据,造成主从数据不一致。
两阶段提交原理
MySQL在写入redo log时,会顺便记录XID,即当前事务id。在写入binlog时,也会写入XID。
-
如果在写入redo log之前崩溃,那么此时redo log与binlog中都没有,是一致的情况,崩溃也无所谓。
-
如果在写入redo log prepare阶段后立马崩溃,之后会在崩恢复时,由于redo log没有被标记为commit。于是拿着redo log中的XID去binlog中查找,此时肯定是找不到的,那么执行回滚操作。
-
如果在写入binlog后立马崩溃,在恢复时,由redo log中的XID可以找到对应的binlog,这个时候直接提交即可。
总的来说,在崩溃恢复后,只要redo log不是处于commit阶段,那么就拿着redo log中的XID去binlog中寻找,找得到就提交,否则就回滚。
在这样的机制下,两阶段提交能在崩溃恢复时,能够对提交中断的事务进行补偿,来确保redo log与binlog的数据一致性。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/4808.html