澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

澳门新浦京娱乐场网站:MySQL并发复制系列一,

前些天在查看关于innodb_flush_log_at_trx_commit的官网解释时产生了一些疑问,关于innodb_flush_log_at_trx_commit参数的详细解释参见官网:

原文:

原文链接

MySQL  Binary log在MySQL 5.1版本后推出主要用于主备复制的搭建,我们回顾下MySQL 在开启/关闭 Binary Log功能时是如何工作的 。

MySQL没有开启Binary log的情况下:

InnoDB存储引擎通过redo和undo日志可以safe crash recovery数据库,当数据crash recovery时,通过redo日志将所有已经在存储引擎内部提交的事务应用redo log恢复,所有已经prepared但是没有commit的transactions将会应用undo log做roll back。然后客户端连接时就能看到已经提交的数据存在数据库内,未提交被回滚地数据需要重新执行。

MySQL开启Binary log 的情况下:

为了保证存储引擎和MySQL数据库上层的二进制日志保持一致(因为备库通过二进制日志重放主库提交的事务,假设主库存储引擎已经提交而二进制日志没有保持一致,则会使备库数据丢失造成主备数据不一致),引入二阶段提交(two phase commit or 2pc)

澳门新浦京娱乐场网站 1

图1 二阶段提交

MySQL二阶段提交流程:

Storage Engine(InnoDB) transaction prepare阶段:即sql语句已经成功执行并生成redo和undo的内存日志

Binary log日志提提交

write()将binary log内存日志数据写入文件系统缓存

fsync()将binary log 文件系统缓存日志数据永久写入磁盘

Storage Engine(InnoDB)内部提交

commit阶段在存储引擎内提交( innodb_flush_log_at_trx_commit控制)使undo和redo永久写入磁盘

开启Binary log的MySQL在crash recovery时:

当事务在prepare阶段crash,数据库recovery的时候该事务未写入Binary log并且存储引擎未提交,将该事务roll back。

当事务在Binary log日志已经fsync()永久写入二进制日志时crash,但是存储引擎未来得及commit,此时MySQL数据库recovery的时候将会从二进制日志的Xid(MySQL数据库内部分布式事务XA)中获取提交的信息重新将该事务重做并commit使存储引擎和二进制日志始终保持一致。

以上提到单个事务的二阶段提交过程,能够保证存储引擎和binary log日志保持一致,但是在并发的情况下怎么保证存储引擎和Binary Log提交的顺序一致?当多个事务并发提交的情况,如果Binary Log和存储引擎顺序不一致会造成什么影响?

澳门新浦京娱乐场网站 2

图2 InnoDB存储引擎提交的顺序与MySQL上层的二进制日志顺序不同

如上图:事务按照T1、T2、T3顺序开始执行,将二进制日志(按照T1、T2、T3顺序)写入日志文件系统缓存,调用fsync()进行一次group commit将日志文件永久写入磁盘,但是存储引擎提交的顺序为T2、T3、T1。当T2、T3提交事务之后做了一个On-line的backup程序新建一个slave来做replication,那么事务T1在slave机器restore MySQL数据库的时候发现未在存储引擎内提交,T1事务被roll back,此时主备数据不一致(搭建Slave时,change master to的日志偏移量记录T3在事务位置之后)。

结论:MySQL数据库上层二进制日志的写入顺序和存储引擎InnoDB层的事务提交顺序一致,用于备份及恢复需要,如xtrabackup和innobackpex工具。

为了解决以上问题,在早期的MySQL版本,通过prepare_commit_mutex 锁保证MySQ数据库上层二进制日志和Innodb存储引擎层的事务提交顺序一致。

澳门新浦京娱乐场网站 3

图3 通过prepare_commit_mutex保证存储引擎和二进制日志顺序提交顺序一致

图3可以看出在prepare_commit_mutex,只有当上一个事务commit后释放锁,下一个事务才可以进行prepara操作,并且在每个transaction过程中Binary log没有fsync()的调用。由于内存数据写入磁盘的开销很大,如果频繁fsync()把日志数据永久写入磁盘数据库的性能将会急剧下降。此时MySQL 数据库提供sync_binlog参数来设置多少个binlog日志产生的时候调用一次fsync()把二进制日志刷入磁盘来提高整体性能,该参数的设置作用:

sync_binlog=0,二进制日志fsync()的操作基于操作系统。

sync_binlog=1,每一个transaction commit都会调用一次fsync(),此时能保证数据最安全但是性能影响较大。

sync_binlog=N,当数据库crash的时候至少会丢失N-1个transactions。

图3 所示MySQL开启Binary log时使用prepare_commit_mutex和sync_log保证二进制日志和存储引擎顺序保持一致(通过sync_binlog来控制日志的刷新频率),prepare_commit_mutex的锁机制造成高并发提交事务的时候性能非常差而且二进制日志也无法group commit。

那么如何保证MySQL开启Binary Log日志后使二进制日志写入顺序和存储引擎提交顺序保持一致并且能够进行二进制日志的Group Commit?

MySQL 5.6 引入BLGC(Binary Log Group Commit),二进制日志的提交过程分成三个阶段,Flush stage、Sync stage、Commit stage。

那么事务提交过程简化为:

存储引擎(InnoDB) Prepare    ---->    数据库上层(Binary Log)   Flush Stage    ---->    Sync Stage    ---->    调存储引擎(InnoDB)Commit stage.

每个stage阶段都有各自的队列,使每个session的事务进行排队。当一个线程注册了一个空队列,该线程就视为该队列的leader,后注册到该队列的线程为follower,leader控制队列中follower的行为。leader同时带领当前队列的所有follower到下一个stage去执行,当遇到下一个stage并非空队列,此时leader可以变成follower到此队列中(注:follower的线程不可能变成leader)

澳门新浦京娱乐场网站 4

图4: 二进制日志三阶段提交过程

在 Flush stage:所有已经注册线程都将写入binary log缓存

在Sync stage :binary log缓存的数据将会sync到磁盘,当sync_binlog=1时所有该队列事务的二进制日志缓存永久写入磁盘

在 Commit stage:leader根据顺序调用存储引擎提交事务。

当一组事务在进行Commit阶段时,其他新的事务可以进行Flush阶段,从而使group commit不断生效。那么为了提高group commit中一组队列的事务数量,MySQL用binlog_max_flush_queue_澳门新浦京娱乐场网站,time来控制在Flush stage中的等待时间,让Flush队列在此阶段多等待一些时间来增加这一组事务队列的数量使该队列到Sync阶段可以一次fysn()更多的事务。

MySQL 5.7 Parallel replication实现主备多线程复制基于主库Binary Log Group Commit, 并在Binary log日志中标识同一组事务的last_commited=N和该组事务内所有的事务提交顺序。为了增加一组事务内的事务数量提高备库组提交时的并发量引入了binlog_group_commit_sync_delay=N 和binlog_group_commit_sync_no_delay_count=N (注:binlog_max_flush_queue_time 在MySQL的5.7.9及之后版本不再生效)参数,MySQL等待binlog_group_commit_sync_delay毫秒直到达到binlog_group_commit_sync_no_delay_count事务个数时,将进行一次组提交。

https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit

组提交 (group commit) 是为了优化写日志时的刷磁盘问题,从最初只支持 InnoDB redo log 组提交,到 5.6 官方版本同时支持 redo log 和 binlog 组提交,大大提高了 MySQL 的事务处理性能。

原文链接

澳门新浦京娱乐场网站 5

其中有一段是这么写的:

下面将以 InnoDB 存储引擎为例,详细介绍组提交在各个阶段的实现原理。

With a value of 2, the contents of the InnoDB log buffer are written to the log file after each transaction commit and the log file is flushed to disk approximately once per second.

简介

自 5.1 之后,binlog 和 innodb 采用类似两阶段提交的方式,不过不支持 group commit;在 5.6 中,将 binlog 的 commit 阶段分为三个阶段:flush stage、sync stage 以及 commit stage。

这三个阶段中,每个阶段都会去维护一个队列,各个列表的定义如下。

Mutex_queue m_queue[STAGE_COUNTER];

如上,每个阶段都在维护一个队列,第一个进入该队列的作为 leader 线程,否则作为 follower 线程;leader 线程会收集 follower 的事务,并负责做 sync,follower 线程等待 leader 通知操作完成。

尽管维护了三个队列,但队列中所有的 THD 实际上都是通过 next_to_commit 连接起来。binlog 在事务提交阶段,也就是在 MYSQL_BIN_LOG::ordered_commit() 函数中,开始 3 个阶段的流程。

接下来,看看 MySQL 中事务是如何提交的。

意思是:如果innodb_flush_log_at_trx_commit的值设为2,那么log buffer里的内容会在每次提交时被写入redo log file,然后redo log file每秒被flush到disk。

事务提交

接下来,看看 InnoDB 和 binlog 提交的流程。

由于innodb的redo log file据我所知是在硬盘上的ib_logfile,所以对于这里的log file被flush到disk很疑惑,难道log buffer和disk之间还存在了一层可以缓存log file的结构?

二阶段提交

详细介绍下二阶段提交的过程。

 

未开启binlog时

InnoDB 通过 redo 和 undo 日志来恢复数据库 (safe crash recovery),当数据恢复时,通过 redo 日志将所有已经在存储引擎内部提交的事务应用 redo log 恢复,所有已经 prepared 但是没有 commit 的事务则会通过 undo log 做回滚。

然后客户端连接时就能看到已经提交的数据存在数据库内,未提交被回滚地数据需要重新执行。

在查阅了大量中英文资料后,总算有了初步的了解,暂总结于此。

开启binlog时

为了保证存储引擎和 MySQL 的 binlog 保持一致,引入二阶段提交 (two phase commit, 2pc) 。

因为备库通过 binlog 重放主库提交的事务,假设主库存储引擎已经提交而 binlog 没有保持一致,则会使备库数据丢失造成主备数据不一致。

 

二阶段提交

如下是二阶段提交流程。

澳门新浦京娱乐场网站 6

详细执行流程为:

  1. InnoDB 的事务 Prepare 阶段,即 SQL 已经成功执行并生成 redo 和 undo 的内存日志;

  2. binlog 提交,通过 write() 将 binlog 内存日志数据写入文件系统缓存;

  3. fsync() 将 binlog 文件系统缓存日志数据永久写入磁盘;

  4. InnoDB 内部提交,commit 阶段在存储引擎内提交,通过 innodb_flush_log_at_trx_commit 参数控制,使 undo 和 redo 永久写入磁盘。

开启 binlog 的 MySQL 在崩溃恢复 (crash recovery) 时:

  • 在 prepare 阶段崩溃,恢复时该事务未写入 binlog 且 InnoDB 未提交,该事务直接回滚;

  • 在 binlog 已经 fsync() 永久写入 binlog,但 InnoDB 未来得及 commit 时崩溃;恢复时,将会从 binlog 中获取提交的信息,重做该事务并提交,使 InnoDB 和 binlog 始终保持一致。

以上提到单个事务的二阶段提交过程,能够保证 InnoDB 和 binlog 保持一致,但是在并发的情况下怎么保证存储引擎和 binlog 提交的顺序一致?当并发提交的时,如果两者不一致会造成什么影响?

一、名词解释

组提交异常

首先看看,对于上述的问题,当并发提交的时,如果两者不一致会造成什么影响?

澳门新浦京娱乐场网站 7

如上所示,事务按照 T1、T2、T3 顺序开始执行,并依相同次序按照写入 binlog 日志文件系统缓存,调用 fsync() 进行一次组提交,将日志文件永久写入磁盘。

但是存储引擎提交的顺序为 T2、T3、T1,当 T2、T3 提交事务之后做了一个 On-line 的备份程序新建一个 slave 来做复制;而搭建备库时,CHANGE MASTER TO 的日志偏移量在 T3 事务之后。

那么事务 T1 在备机恢复 MySQL 数据库时,发现 T1 未在存储引擎内提交,那么在恢复时,T1 事务就会被回滚,此时就会导致主备数据不一致。

结论:需要保证 binlog 的写入顺序和 InnoDB 事务提交顺序一致,用于 xtrabackup 备份恢复。

在innodb存储引擎中,有一种独有的log file,即redo log file,因此对于innodb存储引擎来说,就存在两种logfile:redo log和binlog.

早期解决方案

早期,使用 prepare_commit_mutex 保证顺序,只有当上一个事务 commit 后释放锁,下个事务才可以进行 prepara 操作,并且在每个事务过程中 binlog 没有 fsync() 的调用。

澳门新浦京娱乐场网站 8

由于内存数据写入磁盘的开销很大,如果频繁 fsync() 把日志数据永久写入磁盘,数据库的性能将会急剧下降。为此提供 sync_binlog 参数来设置多少个 binlog 日志产生的时候调用一次 fsync() 把二进制日志刷入磁盘来提高整体性能,该参数的设置作用为:

  • sync_binlog=0,二进制日志 fsync() 的操作基于系统自动执行。

  • sync_binlog=1,每次事务提交都会调用 fsync(),最大限度保证数据安全,但影响性能。

  • sync_binlog=N,当数据库崩溃时,可能会丢失 N-1 个事务。

prepare_commit_澳门新浦京娱乐场网站:MySQL并发复制系列一,innodb二阶段日志提交机制和组提交解析。mutex 的锁机制会严重影响高并发时的性能,而且 binlog 也无法执行组提交。

redo log:即data目录下的ib_logfile0,ib_logfile1(个数由innodb_log_files_in_group控制),innodb存储引擎特有,在内存中有相应的redo log buffer。

改进方案

接下来,看看如何保证 binlog 写入顺序和存储引擎提交顺序是一致的,并且能够进行 binlog 的组提交?5.6 引入了组提交,并将提交过程分成 Flush stage、Sync stage、Commit stage 三个阶段。

这样,事务提交时分为了如下的阶段:

InnoDB, Prepare
    SQL已经成功执行并生成了相应的redo和undo内存日志;
Binlog, Flush Stage
    所有已经注册线程都将写入binlog缓存;
Binlog, Sync Stage
    binlog缓存将sync到磁盘,sync_binlog=1时该队列中所有事务的binlog将永久写入磁盘;
InnoDB, Commit stage
    leader根据顺序调用存储引擎提交事务;

每个 Stage 阶段都有各自的队列,从而使每个会话的事务进行排队,提高并发性能。

如果当一个线程注册到一个空队列时,该线程就做为该队列的 leader,后注册到该队列的线程均为 follower,后续的操作,都由 leader 控制队列中 follower 行为。

leader 同时会带领当前队列的所有 follower 到下一个 stage 去执行,当遇到下一个 stage 为非空队列时,leader 会变成 follower 注册到此队列中;注意:follower 线程绝不可能变成 leader 。

因此写redo时的3层结构为:redo log buffer--->文件系统缓存中的redo logfile--->disk上的redo log file

配置参数

与 binlog 组提交相关的参数主要包括了如下两个参数。

binlog:默认在data目录下,也可以通过log_bin参数直接指定路径,文件名为默认为<hostname>-bin前缀的文件,在内存中没有log buffer。

binlog_max_flush_queue_time

单位为微妙,用于从 flush 队列中取事务的超时时间,这主要是防止并发事务过高,导致某些事务的 RT 上升,详细的内容可以查看函数 MYSQL_BIN_LOG::process_flush_stage_queue() 。

注意:该参数在 5.7 之后已经取消了。

因此写binlog时的2层结构为:文件系统缓存中的binlog--->disk上的binlog

binlog_order_commits

当设置为 0 时,事务可能以和 binlog 不同的顺序提交,其性能会有稍微提升,但并不是特别明显.

好尴尬,Oracle通常是绕过文件系统缓存来直接写入磁盘的,对Mysql的这种机制还不太了解。

源码解析

binlog 的组提交是通过 Stage_manager 管理,其中比较核心内容如下。

class Stage_manager {
  public:
    enum StageID {         // binlog的组提交包括了三个阶段
      FLUSH_STAGE,
      SYNC_STAGE,
      COMMIT_STAGE,
      STAGE_COUNTER
    };
  private:
    Mutex_queue m_queue[STAGE_COUNTER];
};

组提交 (Group Commit) 三阶段流程,详细实现如下。

MYSQL_BIN_LOG::ordered_commit()           ← 执行事务顺序提交,binlog group commit的主流程
 |
 |-#########>>>>>>>>>                     ← 进入Stage_manager::FLUSH_STAGE阶段
 |-change_stage(..., &LOCK_log)
 | |-stage_manager.enroll_for()           ← 将当前线程加入到m_queue[FLUSH_STAGE]中
 | |
 | |                                      ← (follower)返回true
 | |-mysql_mutex_lock()                   ← (leader)对LOCK_log加锁,并返回false
 |
 |-finish_commit()                        ← (follower)对于follower则直接返回
 | |-ha_commit_low()
 |
 |-process_flush_stage_queue()            ← (leader)对于follower则直接返回
 | |-fetch_queue_for()                    ← 通过stage_manager获取队列中的成员
 | | |-fetch_and_empty()                  ← 获取元素并清空队列
 | |-ha_flush_log()
 | |-flush_thread_caches()                ← 对于每个线程做该操作
 | |-my_b_tell()                          ← 判断是否超过了max_bin_log_size,如果是则切换binlog文件
 |
 |-flush_cache_to_file()                  ← (follower)将I/O Cache中的内容写到文件中
 |-RUN_HOOK()                             ← 调用HOOK函数,也就是binlog_storage->after_flush()
 |
 |-#########>>>>>>>>>                     ← 进入Stage_manager::SYNC_STAGE阶段
 |-change_stage()
 |-sync_binlog_file()
 | |-mysql_file_sync()
 |   |-my_sync()
 |     |-fdatasync()                      ← 调用系统API写入磁盘,也可以是fsync()
 |
 |-#########>>>>>>>>>                     ← 进入Stage_manager::COMMIT_STAGE阶段
 |-change_stage()                         ← 该阶段会受到binlog_order_commits参数限制
 |-process_commit_stage_queue()           ← 会遍厉所有线程,然后调用如下存储引擎接口
 | |-ha_commit_low()
 |   |-ht->commit()                       ← 调用存储引擎handlerton->commit()
 |   |                                    ← ### 注意,实际调用如下的两个函数
 |   |-binlog_commit()
 |   |-innobase_commit()
 |-process_after_commit_stage_queue()     ← 提交之后的后续处理,例如semisync
 | |-RUN_HOOK()                           ← 调用transaction->after_commit
 |
 |-stage_manager.signal_done()            ← 通知其它线程事务已经提交
 |
 |-finish_commit()

在 enroll_for() 函数中,刚添加的线程如果是队列的第一个线程,就将其设置为 leader 线程;否则就是 follower 线程,此时线程会睡眠,直到被 leader 唤醒 (m_cond_done) 。

注意,binlog_max_flush_queue_time 参数已经取消。

 

commit stage

如上所述,commit 阶段会受到参数 binlog_order_commits 的影响,当该参数关闭时,会直接释放 LOCK_sync ,各个 session 自行进入 InnoDB commit 阶段,这样不会保证 binlog 和事务 commit 的顺序一致。

当然,如果你不关注两者的一致性,那么可以关闭这个选项来稍微提高点性能;当打开了上述的参数,才会进入 commit stage 。

二、二阶段日志写的流程

原图来自: (个人认为此站作者对于这幅图的理解有误,以下为查阅资料后的个人解释)

澳门新浦京娱乐场网站 9

当开启binlog后,如果会话发出了commit的请求,那么在committed之前,一系列的流程为:

1.prepare阶段:

此阶段负责将log buffer的redo日志和undo写入文件系统缓存中的redo log和undo以及写入disk上的redo log和undo,写入机制取决于innodb_flush_log_at_trx_commit参数。

innodb_flush_log_at_trx_commit:(默认值为1)

  • 此值为0表示:redo log buffer的内容每秒会被写入文件系统缓存的redo log里,同时被flush(固化)到disk上的redo log file中。

  • 此值为1表示:redo log buffer的内容会在事务commit时被写入文件系统缓存的redo log里,同时被flush(固化)到disk上的redo log file中。

  • 此值为2表示:redo log buffer的内容会在事务commit时被写入文件系统缓存的redo log里,而文件系统缓存的redo log每秒一次被flush(固化)到disk上的redo log file中。

注意log buffer和undo buffer(也叫undo page)是在事务执行过程中就即时生成的(undo的disk文件位置默认在系统表空间中,5.6以后也可以自己指定独立的表空间),

2.写binlog阶段:

此阶段调用两个方法write()和fsync(),前者负责写文件系统缓存中的binlog,后者负责将文件系统缓存中的binlog写入disk上的bin log,前者在整个事务执行过程中都会被一直调用,后者的调用机制由sync_binlog参数控制。

关于sync_binlog参数:

  • sync_binlog=0:表示fsync()的调用完全交给操作系统,即文件系统缓存中的binlog是否刷新到disk完全由操作系统控制。

  • sync_binlog=1:表示在事务提交时,binlog一定会被固化到disk

  • sync_binlog=N(N>1):数据库崩溃时,可能会丢失N-1个事务,具体原理也详见https://jin-yang.github.io/post/mysql-group-commit.html

3.innodb引擎内部提交阶段:

Innodb完成事务提交,清除undo信息,将事务设置为TRX_NOT_STARTED状态。

Innodb进行crash recovery时是根据binlog来进行前滚回滚的。只有记录了binlog才会根据redo log前滚或回滚事务。

 

三、故障恢复解析

1.如果在一阶段后崩溃,binlog未写,innodb引擎层直接回滚事务。

2.如果在二阶段后崩溃,binlog已写,那么server告诉innodb重做事务,事务不丢失。

在主从复制的情况下如果innodb_flush_log_at_trx_commit不为1则有可能出现binlog已写但是redo log未写的情况,此时主库崩溃后在事务前滚时会出现找不到redo的情况导致前滚失败,而从库已经应用binlog,导致主从不一致。

而sync_binlog不为1则可能出现主库直接丢失事务的情况。

因此,为保证主从完全一致且事务不丢失,主库的innodb_flush_log_at_trx_commit和sync_binlog都必须设置为1。

 

四、Binlog Group Commit

以上提到单个事务的二阶段提交过程,设置正确的innodb_flush_log_at_trx_commit参数值可以保证 InnoDB 和 binlog的一致性,但是在并发的情况下可能对于主从复制需要考虑如下的BUG:

假设有3个顺序执行的事务T1、T2、T3,Innodb层事务按照 T2、T3、T1 顺序提交,但Server层的binlog写入顺序为是T1、T2、T3(binlog不遵循WAL机制,只能猜测也是顺序写的),当 T2、T3在提交事务之后做了一个xtrabackup备份用于新建一个slave来做主从复制,那么搭建备库时由于T3事务已经完成,因此从T3之后开始同步,但是此时有可能丢失T1的binlog,造成主从不一致。

PS:个人感觉网站流传的T1、T2、T3组提交异常的那副图是错的,因此不建议引用。

结论:需要保证 binlog 的写入顺序和 InnoDB 事务提交顺序一致,用于 xtrabackup 备份恢复。

早期解决方案:

早期,使用 prepare_commit_mutex 保证顺序,只有当上一个事务 commit 后释放锁,下个事务才可以进行 prepare 操作,并且在每个事务过程中binlog 没有fsync() 的调用。

由于内存数据写入磁盘的开销很大,如果频繁 fsync() 把日志数据永久写入磁盘,数据库的性能将会急剧下降。为此提供 sync_binlog 参数来设置多少个 binlog 日志产生的时候调用一次 fsync() 把二进制日志刷入磁盘来提高整体性能,prepare_commit_mutex 的锁机制会严重影响高并发时的性能,而且 binlog 也无法执行组提交。

改进方案:

Mysql5.6 引入了组提交,并将提交过程分成 Flush stage、Sync stage、Commit stage 三个阶段。其实简单的说就是加入队列机制使得binlog写入顺序与事务执行顺序一致,加入队列的最大好处就是可以不获取prepare_commit_mutex锁也能实现不降低性能的日志顺序写。

澳门新浦京娱乐场网站 10

Binlog组提交的基本思想是,引入队列机制保证Innodb commit顺序与binlog落盘顺序一致,并将事务分组,组内的binlog刷盘动作交给一个事务进行,实现组提交目的。在MySQL数据库上层进行提交时首先按顺序将其放入一个队列中,队列中的第一个事务称为leader,其他事务称为follow,leader控制着follow的行为。

  • Flush Stage

1) 持有Lock_log mutex [leader持有,follower等待]。

2) 获取队列中的一组binlog(队列中的所有事务)。

3) 将binlog buffer到I/O cache。

4) 通知dump线程dump binlog。

  • Sync Stage

1) 释放Lock_log mutex,持有Lock_sync mutex[leader持有,follower等待]。

2) 将一组binlog 落盘(sync动作,最耗时,假设sync_binlog为1)。

  • Commit Stage

1) 释放Lock_sync mutex,持有Lock_commit mutex[leader持有,follower等待]。

2) 遍历队列中的事务,逐一进行innodb commit。

3) 释放Lock_commit mutex。

4) 唤醒队列中等待的线程。

说明:由于有多个队列,每个队列各自有mutex保护,队列之间是顺序的,约定进入队列的一个线程为leader,因此FLUSH阶段的leader可能是SYNC阶段的follower,但是follower永远是follower。当有一组事务在进行commit阶段时,其他新事物可以进行Flush阶段,从而使group commit不断生效。当然group commit的效果由队列中事务的数量决定,若每次队列中仅有一个事务,那么可能效果和之前差不多,甚至会更差。但当提交的事务越多时,group commit的效果越明显,数据库性能的提升也就越大。

与 binlog 组提交相关的参数主要包括了如下两个:

  • binlog_max_flush_queue_time

单位为微秒,用于从 flush 队列中取事务的超时时间,这主要是防止并发事务过高,导致某些事务的 RT 上升,详细内容可以查看函数MYSQL_BIN_LOG::process_flush_stage_queue() 。

注意:该参数在 5.7 之后已经取消了。

  • binlog_order_commits

当设置为 0 时,事务可能以和 binlog 不同的顺序提交,其性能会有稍微提升,但并不是特别明显.

本文由澳门新浦京娱乐场网站发布于数据库,转载请注明出处:澳门新浦京娱乐场网站:MySQL并发复制系列一,