你的位置:首页 > 数据库

[数据库]MYSQL组提交

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

redo log的组提交

     WAL(Write-Ahead-Logging)是实现事务持久性的一个常用技术,基本原理是在提交事务时,为了避免磁盘页面的随机写,只需要保证事务的redo log写入磁盘即可,这样可以通过redo log的顺序写代替页面的随机写,并且可以保证事务的持久性,提高了数据库系统的性能。虽然WAL使用顺序写替代了随机写,但是,每次事务提交,仍然需要有一次日志刷盘动作,受限于磁盘IO,这个操作仍然是事务并发的瓶颈。

      组提交思想是,将多个事务redo log的刷盘动作合并,减少磁盘顺序写。Innodb的日志系统里面,每条redo log都有一个LSN(Log Sequence Number),LSN是单调递增的。每个事务执行更新操作都会包含一条或多条redo log,各个事务将日志拷贝到log_sys_buffer时(log_sys_buffer 通过log_mutex

保护),都会获取当前最大的LSN,因此可以保证不同事务的LSN不会重复。那么假设三个事务Trx1,Trx2和Trx3的日志的最大LSN分别为LSN1,LSN2,LSN3(LSN1<LSN2<LSN3),它们同时进行提交,那么如果Trx3日志先获取到log_mutex进行落盘,它就可以顺便把[LSN1---LSN3]这段日志也刷了,这样Trx1和Trx2就不用再次请求磁盘IO。组提交的基本流程如下:

  1. 获取 log_mutex
  2. 若flushed_to_disk_lsn>=lsn,表示日志已经被刷盘,跳转5
  3. 若 current_flush_lsn>=lsn,表示日志正在刷盘中,跳转5后进入等待状态
  4. 将小于LSN的日志刷盘(flush and sync)
  5. 退出log_mutex

备注:lsn表示事务的lsn,flushed_to_disk_lsn和current_flush_lsn分别表示已刷盘的LSN和正在刷盘的LSN。 

两阶段提交

     在单机情况下,redo log组提交很好地解决了日志落盘问题,那么开启binlog后,binlog能否和redo log一样也开启组提交?首先开启binlog后,我们要解决的一个问题是,如何保证binlog和redo log的一致性。因为binlog是Master-Slave的桥梁,如果顺序不一致,意味着Master-Slave可能不一致。MYSQL通过两阶段提交很好地解决了这一问题。Prepare阶段,innodb刷redo log,并将回滚段设置为Prepared状态,binlog不作任何操作;commit阶段,innodb释放锁,释放回滚段,设置提交状态,binlog刷binlog日志。出现异常,需要故障恢复时,若发现事务处于Prepare阶段,并且binlog存在则提交,否则回滚。通过两阶段提交,保证了redo log和binlog在任何情况下的一致性。

binlog的组提交

      回到上节的问题,开启binlog后,如何在保证redo log-binlog一致的基础上,实现组提交。因为这个问题,5.6以前,mysql在开启binlog的情况下,无法实现组提交,通过一个臭名昭著的prepare_commit_mutex,将redo log和binlog刷盘串行化,串行化的目的也仅仅是为了保证redo log-Binlog一致,但这种实现方式牺牲了性能。这个情况显然是不能容忍的,因此各个mysql分支,mariadb,facebook,perconal等相继出了补丁改进这一问题,mysql官方版本5.6也终于解决了这一问题。由于各个分支版本解决方法类似,我主要通过分析5.6的实现来说明实现方法。

     binlog组提交的基本思想是,引入队列机制保证innodb commit顺序与binlog落盘顺序一致,并将事务分组,组内的binlog刷盘动作交给一个事务进行,实现组提交目的。binlog提交将提交分为了3个阶段,FLUSH阶段,SYNC阶段和COMMIT阶段。每个阶段都有一个队列,每个队列有一个mutex保护,约定进入队列第一个线程为leader,其他线程为follower,所有事情交由leader去做,leader做完所有动作后,通知follower刷盘结束。binlog组提交基本流程如下:

FLUSH 阶段

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

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

3)      将binlog buffer到I/O cache

4)      通知dump线程dump binlog

SYNC阶段

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

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

COMMIT阶段

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。

      通过上文分析,我们知道MYSQL目前的组提交方式解决了一致性和性能的问题。通过二阶段提交解决一致性,通过redo log和binlog的组提交解决磁盘IO的性能。下面我整理了Prepare阶段和Commit阶段的框架图供各位参考。

 

参考文档

http://mysqlmusings.blogspot.com/2012/06/binary-log-group-commit-in-mysql-56.html

http://www.lupaworld.com/portal.php?mod=view&aid=250169&page=all

http://www.oschina.net/question/12_89981

http://kristiannielsen.livejournal.com/12254.html

http://blog.chinaunix.net/uid-26896862-id-3432594.html


跟团去贵州旅游多少钱几月去贵州旅游最好去贵州的旅游团价格去贵州旅游必去景点去贵州旅游要多少钱深圳欢乐谷夜场_深圳欢乐谷夜场门票 太行山在哪里_太行山在哪个省_太行山在什么地方 清明上河园门票_开封清明上河园门票价格 武汉欢乐谷门票价格_武汉欢乐谷夜场票价多少钱_欢乐谷几点开门 逛世园会品味西安之美 祭寨神 五四青年节世园会青年志愿者在服务 西安世园会舵手们整装待发 潍坊水上皇宫好玩吗?潍坊富华水上皇宫简介? 潍坊水上皇宫电话?水上皇宫营业时间? 潍坊水上皇宫团购票价?潍坊富华水上皇宫小孩怎么收费? 潍坊水上皇宫门票多少钱?潍坊富华水上皇宫一日游攻略? 边吃腰子边洗澡 土耳其浴室里的那些事儿(全文) 2015广州圣诞节情侣拍拖去哪好玩?广州圣诞夜约会哪里好? 2015广州圣诞节平安夜哪里有活动?广州圣诞节圣诞夜场去哪好玩? 三亚槟榔谷班车时间?槟榔谷班车几点发车? STP11NM60N Datasheet STP11NM60N Datasheet 2SK2866(F) Datasheet 2SK2866(F) Datasheet TK10A60D(STA4,Q,M) Datasheet TK10A60D(STA4,Q,M) Datasheet 浙江出发去奥地利旅游 浙江出发去奥地利旅游 浙江出发去奥地利旅游 浙江出发去澳大利亚旅游 浙江出发去澳大利亚旅游 浙江出发去澳大利亚旅游 浙江出发去巴巴多斯旅游 浙江出发去巴巴多斯旅游 浙江出发去巴巴多斯旅游