本文主要介绍innodb重做日志(重做日志撤销日志binlog),下面一起看看innodb重做日志(重做日志撤销日志binlog)相关资讯。
binlog是mysql服务器层的日志,所有的mysql存储引擎都支持binlog。binlog可以支持主从复制和数据恢复,但对事务的acid特性支持较差。innodb存储引擎引入了redolog和undolog事务日志,以提高事务场景中的数据库性能。本文将介绍redolog和undolog。
redolog和undologchang测试数据插入数据库:
创建表user_info( id int主键,name varchar(255));插入到user_info(id,name)值(1 ;ls );查询语句的执行过程如果我们需要查询id=1的用户的信息,可以通过下面的sql语句进行查询:
select * from user_info其中id = 1;这个简单的查询语句之后mysql做了什么?如下图所示,mysql执行sql查询语句的过程包括以下步骤:
连接器:客户端与mysql服务器建立连接,验证用户名、密码等信息;查询缓存:如果sql语句是查询语句,检查查询语句是否命中缓存;分析器:分析sql语句的词法和语法,判断sql语句的类型和对应的表等信息;优化器:优化sql语句并选择适当的索引;执行器:在对应的mysql引擎上执行sql查询语句,返回查询结果;update语句的执行过程,如果我们不 t不需要查询用户信息,但是想将id=1的记录中的用户名更新为zs,我们可以通过下面的sql语句进行更新:
更新用户信息集名称= zs 其中id = 1;类似于上面文章中的查询语句,mysql会先通过connector建立数据库连接,然后通过analyzer、optimizer和executor找到需要更新数据的行,然后更新数据。
与查询过程不同,更新过程还涉及changebuffer和两个重要的日志模块:binlog和redolog。binlog和changebuffer的角色在上一篇文章中已经介绍过了。如上所述,binlog用于主从复制和数据恢复,changebuffer用于缓存数据库中数据的操作,redolog是本文介绍的主角。
changebuffer技术对于上面的update语句,如果没有redolog,innodb引擎会根据索引找到id=1的用户记录,将记录加载到内存中,然后修改内存中的数据事务,写回磁盘。如果数据库数据更新的频率很低,那么这种更新对于数据库来说是可以接受的,但是在更新非常频繁的情况下,大量的离散io会成为数据库的瓶颈,影响数据库的性能。
在频繁更新的场景下,如何降低磁盘的io,保证事务?这涉及到我们在上一篇文章中介绍的changebuffer技术。innodb不会立即将数据更改操作写入磁盘,而是将这些操作缓存在changebuffer中的数据页上,数据库会找到合适的机会将操作合并到数据库中。
通过changebuffer技术,我们可以将多个离散的数据库访问合并成一个数据库访问,并且用户 的更新线程不需要实际访问磁盘,这大大提高了数据库性能。
沃尔科技,然而,我不 t不知道大家有没有注意到changebuffer有一个很大的问题:如果innodb实例在运行过程中断电,changebuffer中的缓存就会丢失,从而造成数据库数据的不一致,影响数据库事务的原子性和一致性。
保证数据库中事务的原子性和一致性的一般方案是采用wal(预写日志记录)技术。在使用wal的系统中,所有的修改首先被写入日志,然后应用到系统状态。日志通常包含两部分信息:重做和撤消。
重做日志称为重做日志。每当有操作时,都会在数据发生变化前将操作写入redolog,这样当停电时,系统重启后还能继续运行。undolog称为undo log,在执行中途某些变更无法完成时,可以根据undo log恢复到变更之间的状态;wal技术在mysql 的innodb引擎,所以innodb存储引擎包含日志的两个部分:redolog和undolog。
如何保证提交的事务不会丢失?解决这个问题比较简单。innodb有一个logforceatcommit机制。提交事务时,与该事务相关的重做日志数据(包括提交记录)必须从日志缓冲区写入重做日志文件。只有当事务成功提交时,信号才能发送到用户进程。通过这种机制,可以保证即使这个提交事务中的changebuffer有一部分没有被写入数据文件,也会发生实例故障,在实例恢复时,可以通过redolog的信息前滚不一致的数据。
重做日志和二进制日志的比较重做日志和二进制日志不同。虽然innodb表的很多操作也记录在binlog中,并且可以实现重做的功能,但是两者有很大的区别。
binlog在存储引擎的上层生成。无论什么存储引擎,修改数据库时都会生成二进制日志。redolog由innodb引擎层生成,只记录存储引擎中表的变化;binlog是记录数据变化的逻辑语句,比如一行数据的变化或者这个变化的sql语句。redolog是物理格式的日志,记录数据库中每个页面的修改情况;binlog只写入日志 文件 每次提交事务时在缓存中保存一次(对于非事务性表操作,在每次成功执行语句后直接写入)。重做日志在数据准备修改之前写入缓存中的重做日志,然后修改缓存中的数据;而且保证了在发出事务提交指令时,先将磁盘日志写入缓存中的redolog,完成写入后才执行提交动作;binlog在提交时只写一次,所以binlog的记录和提交顺序有关,每次提交对应一条记录。重做日志是对记录的物理页面的修改。redolog文件中的同一个事务可能被记录多次,最后提交的事务记录将覆盖所有未提交的事务记录。例如,在事务t1中,可以在重做日志中记录四个操作t11、t12、t13和t1,其中t1表示最后一次提交时的日志记录,因此对应数据页的最终状态是对应于t1的操作结果。而且redolog是并发写入的,不同事务之间不同版本的记录会交替写入redolog文件。例如,redolog的记录方法可能如下:t11、t12、t21、t22、t2、t13、t1 *。事务日志记录物理页面的情况,是幂等的,所以日志记录的极其简洁。幂等性是指多次运算前后状态相同。例如,在插入新行并将其删除后,状态保持不变。二进制日志记录了所有影响数据的操作,记录的内容更多。例如,插入一行记录一次,然后再次删除该行。
重做日志重做日志由两部分组成:一部分是内存中的日志缓冲区,这部分日志是易变的;第二个是磁盘上的重做日志文件,它是持久的。
从概念上来说,innodb通过forcelogatcommit机制实现了事务的持久化,即当一个事务被提交时,该事务的所有事务日志都必须写入磁盘上的redolog文件和undolog文件中才能持久化。
为了保证每个日志都能被写入事务日志文件,每次redolog缓冲区中的日志被写入日志文件时,都会调用操作系统的fsync操作(即fsync系统调用)。因为mariadb/mysql工作在用户空间,所以mariadb/mysql的redolog缓冲区在用户空间的内存中。要写入磁盘上的重做日志缓冲区,它必须通过操作系统内核空间中的操作系统缓存。调用fsync的作用是将操作系统缓存中的日志刷到磁盘上的redolog文件中。
redolog事务日志的文件名是ib_logfilen,比如ib_logfile0和ib_logfile1。......
redolog将日志从缓存写入磁盘,如下图所示:
mysql支持用户自定义事务提交时如何将日志缓存中的日志刷入磁盘文件。它可以由变量innodb_flush_log_at_trx_commit的值来控制。该变量有三个值:0、1和2,默认值为1。但是,请注意,该变量仅控制在提交事务时是否将日志缓存刷新到磁盘。
当设置为1时,日志缓存中的日志将在提交事务时写入操作系统缓存,并将调用fsync保存到磁盘文件中。这样即使系统崩溃也不会有数据丢失,但是因为每次提交都是写到磁盘,io的性能很差。当设置为0时,日志缓存中的日志不会在提交事务时写入操作系统缓存,而是每秒写入操作系统缓存,并调用fsync保存到磁盘文件中。也就是说,设置为0时,每秒刷新一次写入磁盘,系统崩溃时会丢失1秒的数据;设置为2时,事务只在提交时写入操作系统缓存,然后每秒调用fsync将操作系统缓存中的日志持久化到磁盘文件中;有一个变量innodb_flush_log_at_timeout,值为1秒,表示日志记录的频率。很多人误以为是在innodb_flush_log_at_trx_commit的值为0和2时控制1秒的频率,其实不是。以测试时间设置频率。设置为5和1时,innodb_flush_log_at_trx_commit设置为0和2时,性能基本不变。这个频率是怎么控制的?这将在后面的 刷日志到磁盘的规则 。
保证一致性在主从复制结构中,为了保证事务的持久性和一致性,需要对日志相关的变量进行如下设置:
如果启用了binlog,则设置sync_binlog=1,即每个事务都同步写入磁盘。始终设置innodb _ flush _ log _ at _ trx _ commit = 1,即每个事务都写入磁盘。上述两个变量的设置保证了每次提交事务时,都会写入二进制日志和事务日志,提交时会刷新到磁盘。
选择模式1时,因为每个事务都提交到磁盘,所以在大量小事务的场景下,会影响数据库的性能。
redolog日志块在innodb存储引擎中,redolog是分块存储的,每个块占512字节,称为redolog日志块。日志缓存、系统缓存和磁盘中的重做日志文件以这种存储在512字节的块中。
重做日志记录数据页的更改。当需要用超过492字节的重做日志记录一个数据页的变化时,那么将使用多个重做日志日志块来记录该数据页的变化。
关于redolog日志块头的第三部分log_block_first_rec_group,因为有时候一个数据页面生成的日志量超过一个日志块,所以需要使用多个日志块来记录页面的相关日志。比如一个数据页生成一个552字节的日志卷,需要占用两个日志块,第一个日志块占用492字节,第二个日志块占用60字节,那么对于第二个日志块,其第一个日志的起始位置是73字节(60 ^ 12)。如果log_block_first_rec_group的值等于log_block_hdr_data_len,说明这个日志块中没有新开始的日志块,也就是说这个日志块是用来延续前面的日志块的。日志末尾只有一部分:log_block_trl_no,等于块头的log_block_hdr_no。
内存中的重做日志缓存和磁盘中的重做日志文件由多个日志块组成,如下图所示:
重做日志组重做日志组由多个大小相同的重做日志文件组成。组中重做日志文件的数量由变量innodb_log_files_group决定,默认值为2。也就是说,两个重做日志文件形成一个重做日志组。这个组是一个逻辑概念,没有真实的文件来表示它是一个组,但是组的目录可以用变量innodb_log_group_home_dir来定义,redolog文件会放在这个目录下(默认在datadir下)。
mysql显示全局变量,如 innodb _ log % |变量名称|值|| innodb _ log _ buffer _ size | 16777216 | | innodb _ log _ checksums | on | | innodb _ log _ compressed _ pages | on | | innodb _ log _ file _ size | 50331648 | | innodb _ log _ files _ in _ group | 2 | | innodb _ log _ group _ home _ dir |。/| | innodb _ log _ write _ ahead _ size | 8192 |集合中的7行(0.06秒)root@b48c:/var/lib/mysql# lsl ib *rwr1 mysql root 407 oct 21 09 : 36 ib _ buffer _ poolrwr1 mysql mysql 50331648 oct 26 09 : 00 ib _ log file 0rwr1m ysql mysql根据目录,有两个以ib_logfile开头的文件,是redolog日志组中的redolog文件,它们的大小完全相同,等于变量innodb_log_file_size定义的值。当innodb_file_per_table未打开时,ibdata1文件是一个共享表空间文件,对应于。打开innodb_file_per_table时的ibd文件。
当innodb将日志缓存中的redolog日志块刷入redolog文件时,会以额外写入的形式轮流写入。也就是说,在第一个重做日志文件(ib_logfile0)的末尾写入,然后写入第二个重做日志文件(ib_logfile1),直到写满为止。当第二个重做日志文件已满时,第一个重做日志文件的一部分将被清空以继续写入。
因为日志缓存中的日志被刷到了redolog文件中,所以在redolog文件中记录日志的也是redolog日志块的。redolog文件的大小对innodb的性能有很大的影响。如果设置得太大,需要很长时间恢复,如果设置得太小,会导致写redolog时循环切换redolog文件。
在每个组的第一个重做日志文件中,前2kb记录四个特定部分,2kb之后记录重做日志块。除了第一个重做日志文件,重做日志日志组中的其他重做日志文件不会记录2kb,但会为2kb腾出空间。
重做日志文件格式innodb存储引擎将数据存储在一个页面中,因此重做日志也基于页面格式进行记录。默认情况下,innodb的页面大小为16kb(由变量innodb_page_size控制),一个页面可以存储多个重做日志块(每个512字节),重做日志块记录数据页面的变化。
重做日志块的492字节部分是重做日志内容,重做日志内容的格式分为四个部分:
redo_log_type:占用1个字节,表示重做日志的日志类型;space:表空间的id。压缩后,占用的空间可能小于4字节;page_no:表示页面的偏移量,也是压缩的;redo_log_body表示每个重做日志的数据部分,还原时会调用相应的函数进行解析。redolog记录格式redolog的本质是记录事务对数据库做了哪些更改。innodb 美国设计师专注于事物为数据库的不改场景定义了多种类型的重做日志,但大多数类型的重做日志具有以下一般结构:
各部分的详细解释如下:
类型:此重做日志的类型。在这个版本的mysql 5.7.21中,innodb中有53种不同类型的重做日志,后面会详细介绍不同类型的重做日志。空间id:表空间id。页码:页码。数据:这个重做日志的具体内容。我赢了。;本文不介绍重做日志的更详细的格式。有兴趣的可以自己找文档。此时我们应该知道,如果我们使用insert语句向数据库中插入一条记录,那么redolog将记录指定的值将被设置在指定空间中指定数据页的指定地址。
当redolog磁盘擦洗策略变量innodb_flush_log_at_trx_commit的值为1时,每次提交事务时,redolog事务日志都会被擦洗到磁盘,但innodb不会只在icommit之后将日志擦洗到磁盘,这只是innodb存储引擎的规则之一。有几种情况会触发日志清理:
提交动作发出时,提交发出后是否刷日志由变量innodb_flush_log_at_trx_commit控制。每秒刷一次。日志记录的频率由变量innodb_flush_log_at_timeout的值决定,默认值为1秒。应该注意,这个日志记录频率与提交操作无关。当日志缓冲区中一半以上的内存已被使用时。当存在检查点时,检查点表示当日志在某种程度上被移动到磁盘时日志的lsn位置。dirtydata是在检查点的缓冲池中未刷到磁盘的脏数据。因为数据和日志都以页的形式存在,所以脏页表示脏数据和脏日志。最后一节介绍了日志被刷到磁盘的时间。不仅日志要刷,脏数据页也要刷。
在innodb中,数据清理只有一个规则:检查点。但是有几种情况会触发检查点。在任何情况下,触发检查点后,缓存中的脏数据页和脏日志页都将被刷到磁盘。
innodb存储引擎中有两种检查点:
sharp checkpoint:重用redolog文件时(比如切换日志文件),将redolog中记录的脏数据全部刷到磁盘上。模糊checkpoint:一次只刷一小部分日志到磁盘,而不是所有脏日志。以下情况会触发检查点:主线程检查点:由主线程控制,每秒或每10秒刷一定比例的脏页到磁盘;flush_lru_list检查点:从mysql5.6开始,可以通过innodb_page_cleaners变量指定负责清理脏页的pagecleaner线程的数量,这个线程的目的是保证lru列表有可用的空闲页;异步/同步刷新检查点:同步或异步磁盘刷。比如还有很多脏页没有刷到磁盘上(有多少,比例控制)。这时候你会选择同步刷到磁盘,但这种情况很少发生;如果脏页不多,可以选择异步刷到磁盘;如果脏页少,可以暂时不刷到磁盘;脏页过多检查点:当脏页过多时,检查点被强制触发,以确保缓存有足够的空闲空间。过多的比例由变量innodb_max_dirty_pages_pct控制,mysql 5.6的默认值是75,即当脏页占缓冲池的75%时,强制将部分脏页刷到磁盘。因为完成脏页需要一定的时间,所以每次磁盘刷完之后,都会在redolog中标记检查点的位置。mysql停止时是否将脏数据和脏日志刷到磁盘由变量innodb_fast_shutdown={ 0|1|2}控制,默认值为1,即mysql停止时只进行一部分purge,大部分的刷新操作被忽略(但至少会刷日志),剩下的在mysql下次启动时刷新,实现fastshutdown。
lsn学习lsn被称为日志序列号。在innodb存储引擎中,lsn占用8个字节,lsn的值会随着日志的写入而增加。分析lsn可以获得很多关键信息:
数据页的版本信息。写入的日志总量可以通过lsn开始编号和结束编号来计算。检查站的位置。lsn不仅存在于重做日志中,也存在于数据页中。在每个数据页的头部,有一个fil_page_lsn,记录当前页的最终lsn值。通过比较数据页中的lsn值和重做日志中的lsn值,如果页中的lsn值小于重做日志中的值,则意味着丢失了一些数据。此时可以通过redolog的记录恢复重做。日志中记录的lsn值。
重做日志的lsn信息可以通过显示引擎innodb状态来查看。mysql版的显示结果只有三条记录,没有刷新到的页面。
mysql显示引擎innodb状态...... log 日志序列号12734454日志刷新达到12734454页面刷新达到12734454最后一个检查点为1273 44450挂起日志刷新,0挂起chkp写入45日志i/o ;完成,0.00日志输入/输出 s/秒,其中
日志序列号是当前重做日志中的lsn,通常与缓存中的lsn一致,称为缓存日志lsn刷新到的日志是磁盘上重做日志文件中的lsn,通常小于日志缓存lsn,称为磁盘日志lsnpages flushed up是已经刷在磁盘数据页上的lsn,称为磁盘数据页lsn;最后一个检查站是lsn的最后一个检查站,这是所谓的lsn检查站。innodb执行修改数据库语句的过程如下:
将redolog写入redolog缓存,并将redolog中对应的lsn记录为缓存日志lsn如果目标数据页在缓存中,则修改缓存中的数据页,并将数据页中的lsn记录为缓存的数据页lsn;当日志刷回磁盘时,在redolog文件中记录对应的lsn,记为磁盘日志lsn;数据页中的lsn在检查点脏的时候缓存,记录为检查点lsn;;在checkpoint要刷的数据页很多,刷完所有的数据页需要一定的时间。每滑一半的数据页都会记录当前页所在的lsn,暂且称为磁盘数据页lsn。下图显示了交易过程中各lsn的变化情况:
12 : 00 : 00.000时间,交易开始。最初,假设每个lsn是001;12 : 00 : 00.200,执行update语句1,更新缓存日志lsn和缓存数据页lsn,分别加1。,改为001;12 : 00 : 00.400,执行update语句2,分别更新缓存日志lsn和缓存数据页lsn,加1改为002;12 : 00 : 00.600,执行update语句3,分别更新缓存日志lsn和缓存数据页lsn,加1改为003;12 : 00 : 01.000时间,检查点,将缓存中的日志和数据页刷回磁盘,将磁盘数据页和磁盘日志的lsn更新为003,将检查点的lsn更新为003;12 : 00 : 01.200,执行update语句3,分别更新缓存日志lsn和缓存数据页lsn,加1改为004;12 : 00 : 01.400,事务提交,缓存日志写入磁盘,磁盘日志lsn更新为004;12 : 00 : 02.000时间,检查点,将缓存中的日志和数据页刷回磁盘,磁盘数据页lsn更新为004,检查点lsn更新为004;innodb crashsafe在启动innodb时总是会恢复,不管它上次是正常关闭还是异常关闭。因为redolog记录的是数据页的物理变化,所以恢复起来比逻辑日志(比如binlog)要快得多。而且innodb本身也做了一定程度的优化,让恢复速度更快。
innodb重启时,checkpoint代表已经完全刷到磁盘上数据页的lsn,所以恢复时只需要恢复从checkpoint开始的日志部分。例如,当数据库的lsn在最后一个检查点为10000时,事务处于提交状态。当数据库启动时,将检查磁盘中数据页的lsn。如果数据页的lsn小于日志中的lsn,恢复将从检查点开始。
还有一种情况,停机前,在检查点刷盘过程中,数据页的刷盘进度超过了日志页。此时,当机器停机时,数据页中记录的lsn将大于日志页中的记录,这将在重启恢复过程中进行检查。这时候超出日志进度的部分就不会重做,因为这本身就意味着已经做了的事情不需要重做。
此外,事务日志是幂等的,因此多次操作后得到相同结果的行为是它在日志中只记录一次。二进制日志不是幂等的,所以会记录很多操作,恢复时会多次执行二进制日志中的记录,速度慢很多。比如一条记录中id的初始值为2,通过update设置为3,再设置为2,那么事务日志中记录的页面就不变,根本不需要恢复;二进制文件将记录两个更新操作,这两个操作也将在恢复过程中执行,这比事务日志恢复要慢。
redolog相关变量innodb _ flush _ log _ at _ trx _ commit = { 0 | 1 | 2 }:指定何时将事务日志刷到磁盘;默认值为1;0表示 日志缓冲区 将同步到 操作系统缓冲区和每秒和刷从 操作系统缓冲区和到磁盘日志文件;1表示每个事务提交都将同步日志缓冲区 致 操作系统缓冲区和从 操作系统缓冲区和到磁盘日志文件;2意味着每个事务提交都是同步的日志缓冲区 致 操作系统缓冲区和但只有来自 操作系统缓冲区和到磁盘日志文件;innodb _ log _ buffer _ size:log buffer的大小,默认值为8minnodb_log_file_size:事务日志的大小,默认值为5minnodb_log_files_group =2:事务日志组中事务日志文件的数量。默认值为2 innodb_log_group_home_dir =。/:事务日志组路径,当前目录代表数据目录innodb_mirrored_log_groups =1:指定事务日志组的镜像组数,但是镜像功能好像被强制关闭了,所以只有一个redolog组。这个变量在mysql5.7中已经被删除了,undolog的基本概念有两个功能:提供回滚和多行版本控制(mvcc)。
当数据被修改时,wal技术不仅记录重做日志,还记录相应的撤消日志。如果事务由于某种原因失败或回滚,可以在这个undolog的帮助下回滚。
undolog和redolog记录不同的物理日志,它们是逻辑日志。可以认为,当记录被删除时,相应插入记录将被记录在undolog中,反之亦然;当记录被更新时,它记录相应的相反的更新记录。
当执行回滚时,可以从undolog中的逻辑记录读取相应的内容并回滚。有时应用于行版本控制时,也是通过undolog来实现的:当读取一行时,当被其他事务锁定时,可以从undolog中分析出该行记录之前的数据是什么,从而提供该行的版本信息,让用户实现非锁定一致读取。
undolog是以段的形式记录的,每次撤销操作在记录时都占用一个undolog段。
此外,undolog还会产生redolog,因为undolog也需要实现持久保护。
undolog存储模式innodb存储引擎采用分段模式管理undo。回滚段称为回滚段,每个回滚段有1024个undolog段。
之前的老版本只支持一个回滚段,所以只能记录1024个undolog段。后来的mysql5.5可以支持128个回滚段,也就是128*1024次撤销操作,可以通过变量innodb _ undo _ logs(5.6版之前这个变量是innodb_rollback_segments)自定义多少个回滚段。默认值为128。默认情况下,undolog存储在共享表空间中。
root@b48c:/var/lib/mysql# lsl ib *rwr1 mysql root 407 oct 21 09 : 36 ib _ buffer _ poolrwr1 mysql 50331648 oct 26 09 : 00 ib _ log file 0rwr1m ysql mysql 50331648 oct 20 07 : 24 ib _ log file 1rw每个表的ibd文件。在mysql5.6中,undo的存储位置也可以由变量innodb_undo_directory定义,默认值为 。 对于datadir。
默认rollback段全部写在一个文件中,但是通过设置变量innodb_undo_tablespaces可以均匀分布多少个文件。这个变量的默认值是0,也就是说,所有的变量都被写入一个表空间文件。此变量是静态的,只能在数据库示例停止时修改,例如写入配置文件或在启动时获取相应的参数。
提交事务时,innodb不会立即删除undolog,因为以后可能会用到它。例如,当隔离级别为repeatableread时,事务在启动时读取最新提交的行版本。只要交易没有完成,就不能删除行版本,也就是不能删除undolog。
但是在提交事务时,该事务对应的undolog会被放入删除列表,以后会通过purge删除。并且在事务提交时,还会判断undolog分配的页面是否可以重用,如果可以重用,就分配给后续的事务,避免为每个独立的事务分配独立的undolog页面而浪费存储空间和性能。
删除和更新操作的结果由undolog记录,发现(插入操作不需要分析,只插入行)。
实际上删除操作并不会直接删除,只是删除对象会被标记为delete,最后的删除操作会由purge线程完成。更新分为两种情况:更新的列是否是主键列。如果不是主键列,如何更新直接记录在undolog中,即直接进行更新;如果是主键列,更新分两部分执行:首先删除行,然后插入目标行。undolog包含旧版本数据行的快照信息,存储在表空间中。
binlog和事务日志如下图所示。提交事务时,写入日志涉及三个步骤:
写入重做日志,在准备状态下写入二进制日志,并将重做日志的状态修改为提交。这里我们注意到重做日志的提交过程中引入了两阶段提交。为什么一定要有一个 两阶段提交和提交;?这是为了使两个日志之间的逻辑一致。
因为redolog和binlog是两个独立的逻辑,如果你不 如果你不需要分两个阶段提交,你可以先完成重做日志然后再写binlog,或者采用相反的顺序。让 让我们看看这两种方有什么问题,并用上面的更新示例进行假设:
先写redolog,再写binlog。假设redolog完成,binlog未完成时,mysql进程异常重启。因为已经写了redolog,系统还是可以崩溃的。把数据拿回来。但是binlog中没有这个语句的记录,所以备份日志时binlog中没有这个语句;如果您需要使用此binlog来恢复临时库,则恢复的值与原始库值不同,因为此语句的binlog已丢失。先写binlog,再写redolog。如果在binlog完成写入后关闭,则该行的值不会更新,因为redolog尚未写入,并且该事务在崩溃恢复后无效。但崩溃前的更新记录已经记录在binlog中,当binlog来恢复时,又多出了一个事务,与原库的值不同。可以看出,两阶段提交是为了防止binlog和redolog不一致。同时我们也注意到,为了崩溃恢复的一致性,引入了很多新的东西,也让系统复杂了很多,所以有得有失。在两阶段提交redolog和binlog的过程中,2pc事务的xid(事务落xid(redolog和binlog)的标识)将在两者刷新后被记录。如果数据库崩溃正在进行中,提交和回滚将在通过xid进行恢复的过程中决定。详细步骤见下一段恢复步骤 。
如果恢复步骤redolog中的事务经过了两阶段提交中的准备阶段,它将被标记为准备标志,如果它经过了提交阶段,它将被标记为提交标志(此时redolog和binlog都已关闭):
依次扫描redolog,如果redolog中的事务同时有准备和提交标记,则直接提交(将redolog磁盘中的数据页复制到磁盘数据页);如果重做日志事务只有准备标识符而没有提交标识符,则意味着当前事务在提交阶段已经崩溃,重做日志中的当前事务是否完成是未知的。此时,取redolog中当前事务的xid(落在redolog和binlog中的事务的标识符)检查binlog中是否存在此xid:如果binlog中存在当前事务的xid,则提交事务(将redolog磁盘中的数据页复制到磁盘数据页)。如果binlog中没有当前事务的xid,则回滚事务(使用undolog删除redolog中对应的事务);我们可以将mysql中redolog和binlog的两阶段提交与广义上的两阶段提交进行比较。广义来说,如果一个参与者在时限内没有收到协调器的ack通知,就会回滚,回滚逻辑要求开发者在每个参与者中记录。mysql两阶段提交通过xid恢复。回复。
为了提高性能,组提交通常将多个相关的数据修改操作放在一个事务中,这样可以避免为每个修改操作执行一个完整的持久化操作。这种可以被认为是一种人为的群体行为。除了将多个操作合并在一个事务中,记录binlog的操作也可以按照group的思想进行优化:一次刷新多个事务涉及的binlog,而不是一次刷新一个binlog。
事务提交时,不仅会记录事务日志,还会记录二进制日志,但是谁先记录它们呢?binlog是mysql的上层日志,写在存储引擎的事务日志之前。
在mysql5.6之前,事务提交时(即发出提交指令),mysql收到信号,进入提交准备阶段;进入准备阶段后,立即将binlog日志写入内存,将binlog日志写入内存后,相当于确定提交操作;然后开始在存储器中写入事务日志;最后擦洗binlog日志和事务日志,擦洗的分别由变量sync_binlog和innodb_flush_log_at_trx_commit控制。
但是为了保证binlog日志和事务日志的一致性,在提交后的准备阶段会启用一个prepare _ commit _ mutex锁,以保证它们的顺序和一致性。但是这样会导致打开binlog日志后group commmit失效,尤其是在主从复制结构中,binlog日志几乎都是打开的。在mysql5.6中改进,提交事务时,事务会放入存储引擎层上层结构的队列中。队列中的第一个事务称为领导者,其他事务称为追随者。领导者控制着追随者的行为。虽然顺序还是一样,先刷binlog,再刷事务日志,但是机制完全变了:删除了原来的prepare_commit_mutex行为,可以保证即使打开了binlog,组提交仍然有效。
mysql5.6中有三个步骤:刷新阶段、同步阶段和提交阶段:
刷新阶段:写binlog将每笔交易存入内存;同步阶段:刷内存中的binlog日志。如果队列中有多个事务,那么只有一个fsync操作完成二进制日志的磁盘清理操作。这在mysql5.6中被称为blgc(二进制日志组提交);提交阶段:领导者按顺序调用存储引擎层事务。提交,因为innodb本来就支持组提交,解决了锁定prepare_commit_mutex导致的组提交失效问题;binlog在flush阶段写入内存,但写入后并不进入sync阶段,而是需要等待一定的时间,几个事务的binlog会一起进入sync阶段。等待时间由变量binlog_max_flush_queue_time决定,默认值为0,表示不等待就进入同步阶段。将该变量设置为大于0的值的好处是组内事务较多,性能会更好,但这样会导致事务的响应时间较慢,所以建议不要修改该变量的值,除非有大量的事务并且不断被写入和更新。
进入同步阶段,binlog会从内存刷到磁盘,刷的多少由变量sync _ binlog控制,就像单个binlog刷一样。
当一组事务处于提交阶段时,其他新事务可以处于刷新阶段,它们不会互相阻塞,因此组提交将继续生效。当然,组提交的性能与队列中的事务数量有关。如果队列中一次只有一个事务,则组提交和单独提交没有区别。当队列中的事务越来越多,即提交的事务越多,组提交的效果就越明显。
我 m玉壶沈,欢迎关注我的官方账号:wzm2zsd。
参考文档mysql实战45讲br什么是walbr mysql事务日志(重做日志和撤销日志)详细分析br你说的——重做日志必须做的事情(一)br。
本文首发至官方账号。保留所有权利。禁止转载!
标签:
日志交易
了解更多innodb重做日志(重做日志撤销日志binlog)相关内容请关注本站点。