mysql 5.6 binlog组提交实现原理

mysql 5.6 binlog组提交实现原理

http://blog.itpub.net/15480802/viewspace-1411356

Redo组提交

Redo提交流程大致如下

lock log->mutex

write redo log buffer to disk

unlock log->mutex

fsync

Fsync写磁盘耗时较长且不占用log->mutex,也就是其执行期间其他线程可以write log buffer;

假定一次fsync需要10ms,而写buffer只需要1ms,则fsync执行期间最多可以有10条redo record写入buffer,则下次调用fsync时可一次性写10条记录;

binlog组提交

Mysql 从 5.0 开始支持2PC,在代码实现时为了保证Binlog中的事务顺序和事务commit顺序一致,放弃了Group Commit。

如果Binlog顺序不一致,那么备库就无法确保和主库有一致的数据。这个问题直到 mysql 5.5 才开始部分修复,到 mysql 5.6 完全修复。

在 mysql 5.5 中,只有当 sync_binlog = 0 时,才能使用 group commit,在 mysql 5.6中都可以进行 group commit。

2PC下的事务提交流程

1. Prepare Innodb:

a) Write prepare record to Innodb‘s log buffer

b) Sync log file to disk  -- redo组提交

c) Take prepare_commit_mutex

2. "Prepare" binary log:

a) Write transaction to binary log

b) Sync binary log based on sync_binlog

3. Commit Innodb:

a) Write commit record to log

b) Release prepare_commit_mutex

c) Sync log file to disk

d) Innodb locks are released

4. "Commit" binary log:

a) Nothing necessary to do here.

不足

为保证binlog按顺序写,prepare redo阶段获取prepare_commit_mutex,直到sync redo前才释放;一次只能有一个事务可获取该mutex,阻碍了group commit;

另外,一次完整的事务提交需要调用3次fsync,效率很低;

改进

1 减少fsync

crash recovery时先查看redo log,找出prepared但没有commited或aborted的事务列表,然后检查binlog,如果binlog记录了该事务,则将其commit否则rollback;

由此可见,事务恢复时取决于binlog是否有记录,因此commit innodb时无须调用立即fsync(此时binlog已写入,就算crash也能保证事务提交);

2 细化binlog commit代码,实现组提交

在Oracle MySQL 5.6.15中,binlog group commit模块被重写,这个过程分为3个stage:flush/sync/commit;

5.6的2PC提交流程如下

1. Ask binary log (i.e. coordinator to prepare

a) Request to release locks earlier

b) Prepare Innodb (Callback to (2.a))

2. Prepare Innodb:

a) Write prepare record to Innodb log buffer

b) Sync log file to disk

3. Ask binary log (i.e. coordinator) to commit

a) Lock access to flush stage

b) Write a set of transactions to the binary log

c) Unlock access to flush stage

d) Lock access to sync stage

e) Flush the binary log to disk

f) Unlock access to sync stage

g) Lock access to commit stage

h) Commit Innodb (Callback to (4.a))

i) Unlock access to commit stage

4. Commit Innodb

a) Write a commit record to Innodb log buffer

binlog提交被细化为3个处理阶段,每一阶段都有lock保护(此时redo已经调用fsync,事务尚未提交);

这3个阶段负责批量读取binlog并调用fsync,而后以同样顺序提交事务(可选);

第一个进入处理阶段的事务担当Leader的角色,剩余的为follower,后者释放所有的latch并等待,直至leader完成commit;

leader获取所有排队等待的事务并处理,进入下一个处理阶段时,如果队列为空则仍是leader,否则降级为follower;

1. Flush Stage

leader会不断读取flush queue直到队列为空或者超时,这样允许处理过程中新加入的事务也能得到及时处理;

leader将排队的事务写入binlog buffer,当队列为空时则进入下一阶段;

超时机制避免了事务长时间等待,

2. Sync Stage

调用fsyc,一次刷新多个事务;

3. Commit Stage

提交事务,保证所有事务提交顺序同写入binlog一致(innodb hot backup); 为了提升性能,也可选择不按次序提交;

代码实现

Binlog原本实现了handlerton接口,包括commit()/rollback()等方法,5.6引入新机制

public class MYSQL_BIN_LOG: public TC_LOG

{

int open_connection(THD* thd);

int close_connection(THD* thd);

int commit(THD *thd, bool all);

int rollback(THD *thd, bool all);

int savepoint_set(THD* thd, SAVEPOINT *sv);

int savepoint_release(THD* thd, SAVEPOINT *sv);

int savepoint_rollback(THD* thd, SAVEPOINT *sv);

};

int MYSQL_BIN_LOG::commit(THD *thd, bool all)

{

/* Call batch_commit(). */

}

int MYSQL_BIN_LOG::batch_commit(THD* thd, bool all)

{

--将事务加入flush queue,第一个事务为leader,follower阻塞直至完成commit;

if (change_stage(thd, Stage_manager::FLUSH_STAGE, thd, NULL, &LOCK_log))

return finish_commit(thd->commit_error);

--将事务写入binlog

THD *flush_queue= NULL; /* Gets a pointer to the flush_queue */

error= flush_stage_queue(&wait_queue);

if (change_stage(thd, Stage_manager::SYNC_STAGE, wait_queue, &LOCK_log, &LOCK_sync))

return finish_commit(thd->commit_error);

--依据sync_binlog选项调用fsync,5.5却只能将sync_binlog=0

THD *sync_queue= NULL; /* Gets a pointer to the sync_queue */

error= sync_stage_queue(&sync_queue);

--根据opt_binlog_order_commits,可以按binlog写入顺序提交事务,也可以让线程调用handlerton->commit各自提交;

if (opt_binlog_order_commits)

{

if (change_stage(thd, Stage_manager::COMMIT_STAGE,

final_queue, &LOCK_sync, &LOCK_commit))

return finish_commit(thd);

THD *commit_queue= NULL;

error= commit_stage_queue(&commit_queue);

mysql_mutex_unlock(&LOCK_commit);

final_queue= commit_queue;

}

else

{

final_queue= sync_queue;

mysql_mutex_unlock(&LOCK_sync);

}

--通知follower,要么提交事务(opt_binlog_order_commits=false)要么通知客户端;

stage_manager.signal_done(final_queue);

return finish_commit(thd);

}

参考资料

http://dev.mysql.com/worklog/task/?id=5223

http://mysqlmusings.blogspot.co.uk/2012/06/binary-log-group-commit-in-mysql-56.html?_sm_au_=iDV88W54k66P05L7

后记:
看到淘宝分享的一篇帖子,在5.6的基础上还有优化的空间,要保证一个事务能成功恢复,只需要保证在binlog commit前将对应事务的redo entry写入磁盘即可,则redo commit/sync完全可以从redo prepare后移到binlog prepare,将其放于flush stage和commit stage之间,将原本N次的log_sys->mutex获取次数降为1次,fsync也变为1次;
问题
每个事务都要保证其Prepare的事务被write/fsync到redo log文件。尽管某个事务可能会帮助其他事务完成redo 写入,但这种行为是随机的,并且依然会产生明显的log_sys->mutex开销。
优化
从XA恢复的逻辑我们可以知道,只要保证InnoDB Prepare的redo日志在写Binlog前完成write/sync即可。因此我们对Group Commit的第一个stage的逻辑做了些许修改,大概描述如下:
Step1. InnoDB Prepare,记录当前的LSN到thd中; 
注:原本此阶段需要获取log->mutex进行的写文件取消,延迟到下一阶段;在原有fsync组提交的基础上实现写文件组提交。
Step2. 进入Group Commit的flush stage;Leader搜集队列,同时算出队列中最大的LSN。
Step3. 将InnoDB的redo log write/fsync到指定的LSN 
Step4. 写Binlog并进行随后的工作(sync Binlog, InnoDB commit , etc)
通过延迟写redo log的方式,显式的为redo log做了一次组写入,并减少了log_sys->mutex的竞争。
目前官方MySQL已经根据我们report的bug#73202锁提供的思路,对5.7.6的代码进行了优化,对应的Release Note如下:
When using InnoDB with binary logging enabled, concurrent transactions written in the InnoDB redo log are now grouped together before synchronizing to disk when innodb_flush_log_at_trx_commit is set to 1, which reduces the amount of synchronization operations. This can lead to improved performance.
简单测试了下,使用sysbench, update_non_index.lua, 100张表,每张10w行记录,innodb_flush_log_at_trx_commit=2, sync_binlog=1000,关闭Gtid
并发线程        原生                  修改后
32             25600                27000
64             30000                35000
128            33000                39000
256            29800                38000

时间: 2024-07-29 13:52:47

mysql 5.6 binlog组提交实现原理的相关文章

mysql 5.6 binlog组提交1

[MySQL 5.6] MySQL 5.6 group commit 性能测试及内部实现流程 尽管Mariadb以及Facebook在long long time ago就fix掉了这个臭名昭著的问题,但官方直到 MySQL5.6 版本才Fix掉,本文主要关注三点: 1.MySQL 5.6的性能如何 2.在5.6中Group commit的三阶段实现流程 新参数 MySQL 5.6提供了两个参数来控制binlog group commit: binlog_max_flush_queue_time

MySQL binlog 组提交与 XA(两阶段提交)

1. XA-2PC (two phase commit, 两阶段提交 ) XA是由X/Open组织提出的分布式事务的规范(X代表transaction; A代表accordant?).XA规范主要定义了(全局)事务管理器(TM: Transaction Manager)和(局部)资源管理器(RM: Resource Manager)之间的接口.XA为了实现分布式事务,将事务的提交分成了两个阶段:也就是2PC (tow phase commit),XA协议就是通过将事务的提交分为两个阶段来实现分布

MySQL binlog 组提交与 XA(分布式事务、两阶段提交)【转】

概念: XA(分布式事务)规范主要定义了(全局)事务管理器(TM: Transaction Manager)和(局部)资源管理器(RM: Resource Manager)之间的接口.XA为了实现分布式事务,将事务的提交分成了两个阶段:也就是2PC (tow phase commit),XA协议就是通过将事务的提交分为两个阶段来实现分布式事务. 两阶段: 1)prepare 阶段 事务管理器向所有涉及到的数据库服务器发出prepare"准备提交"请求,数据库收到请求后执行数据修改和日志

MySQL崩溃恢复与组提交

Ⅰ.binlog与redo的一致性(原子) 由内部分布式事务保证 我们先来了解下,当一个commit敲下后,内部会发生什么? 步骤 操作 step1 InnoDB做prepare redo log(fsync) step2 Sever层写binlog(fsync) step3 InnoDB层commit redo log(fsync) 第一步写的redo file,写入的是trxid而不是page的变化(show binlog events in 'xxx'),准确的说写在undo页上 第三步写

并发复制系列 一:binlog组提交

http://blog.itpub.net/28218939/viewspace-1975809/ 作者:沃趣科技MySQL数据库工程师  麻鹏飞 MySQL  Binary log在MySQL 5.1版本后推出主要用于主备复制的搭建,我们回顾下MySQL 在开启/关闭 Binary Log功能时是如何工作的 . MySQL没有开启Binary log的情况下: InnoDB存储引擎通过redo和undo日志可以safe crash recovery数据库,当数据crash recovery时,

MYSQL组提交

组提交(group commit)是MYSQL处理日志的一种优化方式,主要为了解决写日志时频繁刷磁盘的问题.组提交伴随着MYSQL的发展不断优化,从最初只支持redo log 组提交,到目前5.6官方版本同时支持redo log 和binlog组提交.组提交的实现大大提高了mysql的事务处理性能,下文将以innodb 存储引擎为例,详细介绍组提交在各个阶段的实现原理. redo log的组提交 WAL(Write-Ahead-Logging)是实现事务持久性的一个常用技术,基本原理是在提交事务

(转)MySQL 日志组提交

原文:https://jin-yang.github.io/post/mysql-group-commit.html 组提交 (group commit) 是为了优化写日志时的刷磁盘问题,从最初只支持 InnoDB redo log 组提交,到 5.6 官方版本同时支持 redo log 和 binlog 组提交,大大提高了 MySQL 的事务处理性能. 下面将以 InnoDB 存储引擎为例,详细介绍组提交在各个阶段的实现原理. 简介 自 5.1 之后,binlog 和 innodb 采用类似两

MySQL5.7的组提交与并行复制

从MySQL5.5版本以后,开始引入并行复制的机制,是MySQL的一个非常重要的特性. MySQL5.6开始支持以schema为维度的并行复制,即如果binlog row event操作的是不同的schema的对象,在确定没有DDL和foreign key依赖的情况下,就可以实现并行复制. 社区也有引入以表为维度或者以记录为维度的并行复制的版本,不管是schema,table或者record,都是建立在备库slave实时解析row格式的event进行判断,保证没有冲突的情况下,进行分发来实现并行

Mysql binlog应用场景与原理深度剖析

本文深入介绍Mysql Binlog的应用场景,以及如何与MQ.elasticsearch.redis等组件的保持数据最终一致.最后通过案例深入分析binlog中几乎所有event是如何产生的,作用是什么. 1 基于binlog的主从复制 Mysql 5.0以后,支持通过binary log(二进制日志)以支持主从复制.复制允许将来自一个MySQL数据库服务器(master) 的数据复制到一个或多个其他MySQL数据库服务器(slave),以实现灾难恢复.水平扩展.统计分析.远程数据分发等功能.