组提交(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。组提交的基本流程如下:
- 获取 log_mutex
- 若flushed_to_disk_lsn>=lsn,表示日志已经被刷盘,跳转5
- 若 current_flush_lsn>=lsn,表示日志正在刷盘中,跳转5后进入等待状态
- 将小于LSN的日志刷盘(flush and sync)
- 退出log_mutex
备注:lsn表示事务的lsn,flushed_to_disk_lsn和current_flush_lsn分别表示已刷盘的LSN和正在刷盘的LSN。
redo log 组提交优化
我们知道,在开启binlog的情况下,prepare阶段,会对redo log进行一次刷盘操作(innodb_flush_log_at_trx_commit=1),确保对data页和undo 页的更新已经刷新到磁盘;commit阶段,会进行刷binlog操作(sync_binlog=1),并且会对事务的undo log从prepare状态设置为提交状态(可清理状态)。通过两阶段提交方式(innodb_support_xa=1),可以保证事务的binlog和redo log顺序一致。二阶段提交过程中,mysql_binlog作为协调者,各个存储引擎和mysql_binlog作为参与者。故障恢复时,扫描最后一个binlog文件(在flush阶段,判断binlog是否超过阀值,进行rotate binlog文件,rotate的binlog文件中对应的事务一定是已经提交的,处于prepared的事务的binlog还没有刷进来,因为还没进入ordered_commit函数),提取其中的xid;重做检查点以后的redo日志,读取事务的undo段信息,搜集处于prepare阶段的事务链表,将事务的xid与binlog中的xid对比,若存在,则提交,否则就回滚。
通过上述的描述可知,每个事务提交时,都会触发一次redo flush动作,由于磁盘读写比较慢,因此很影响系统的吞吐量。淘宝童鞋做了一个优化,将prepare阶段的刷redo动作移到了commit(flush-sync-commit)的flush阶段之前,保证刷binlog之前,一定会刷redo。这样就不会违背原有的故障恢复逻辑。移到commit阶段的好处是,可以不用每个事务都刷盘,而是leader线程帮助刷一批redo。如何实现,很简单,因为log_sys->lsn始终保持了当前最大的lsn,只要我们刷redo刷到当前的log_sys->lsn,就一定能保证,将要刷binlog的事务redo日志一定已经落盘。通过延迟写redo方式,实现了redo log组提交的目的,而且减少了log_sys->mutex的竞争。目前这种策略已经被官方mysql5.7.6引入。
两阶段提交
在单机情况下,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阶段的框架图供各位参考。
binlog和redo log日志提交的更多相关文章
-
必须了解的mysql三大日志-binlog、redo log和undo log
日志是 mysql 数据库的重要组成部分,记录着数据库运行期间各种状态信息.mysql日志主要包括错误日志.查询日志.慢查询日志.事务日志.二进制日志几大类.作为开发,我们重点需要关注的是二进制日志( ...
-
MySQL:binlog 和 redo log
[参考文章]:MySQL中Redo与Binlog顺序一致性问题? [参考文章]:极客时间 1. 数据更新时的日志处理流程 1.1 redo log(prepare状态) 此时SQL已经成功执行了,已经 ...
-
binlog、redo log、undo log区别
root@(none) 04:17:18>show variables like 'innodb_log_group_home_dir';+--------------------------- ...
-
redo log日志内容备忘
检查点是一串递增的数字. 在两个检查点之间,存在有一个MLOG_FILE_NAME的文件,里面记录着space和路径和MLOG_CHECKPOINT的一个检查点. MLOG_FILE_NAME总是在上 ...
-
MySQL日志系统:redo log与binlog
日志系统主要有redo log(重做日志)和binlog(归档日志).redo log是InnoDB存储引擎层的日志,binlog是MySQL Server层记录的日志, 两者都是记录了某些操作的日志 ...
-
MySQL 日志系统之 redo log 和 binlog
之前我们了解了一条查询语句的执行流程,并介绍了执行过程中涉及的处理模块.一条查询语句的执行过程一般是经过连接器.分析器.优化器.执行器等功能模块,最后到达存储引擎. 那么,一条 SQL 更新语句的执行 ...
-
数据库中的两个最重要的日志redo log和binlog
mysql整体来看其实只有两部分,一部分是server层,一部分是引擎层. 1.redo log(重做日志):当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写入redo log里面,并更新 ...
-
MySQL的两种日志类型,redo log,binlog
文章内容学习:极客时间-林晓彬老师-MySQL实战45讲 整理而得 我们知道MySQL数据库在发生意外宕机的情况下,可以将数据恢复到历史的某个时间点,能实现这个功能依靠的是日志,MySQL提供两种类型 ...
-
MySQL更新数据时,日志(redo log、binlog)执行流程
1:背景 项目需要做Es和数据库的同步,而手动在代码中进行数据同步又是Es的一些不必要的数据同步操作和业务逻辑耦合,所以使用的了读取mysql的binlog日志的方式进行同步Es的数据. 问题1:根据 ...
随机推荐
-
PHP基础知识之字符串运算符
两个字符串相加用 . 运算符(类似于+),如$a="str1" . "str2";$b=$a . "str3";=>"str ...
-
IMPLEMENTED IN PYTHON +1 | CART生成树
Introduction: 分类与回归树(classification and regression tree, CART)模型由Breiman等人在1984年提出,CART同样由特征选择.树的生成及 ...
-
Can&#39;t load IA 32-bit .dll on a AMD 64-bit platform
在myeclipse中使用的,tomcat异常:java.lang.UnsatisfiedLinkError: D:\JAVA\ApacheTomcat\bin\tcnative-1.dll: Can ...
-
windows 结束进程的详细过程
windows上如何结束进程的详细过程,下面附详细,图文说明 在cmd下,输入 netstat -ano|findstr 8080 //说明:查看占用8080端口的进程 在cmd下, ...
-
VS 2017 开发安卓环境搭建 问题总结
VS 2017可以开发安卓啦,之前一直想尝试开发安卓,但是由于时间忙, Java只学了个基础,不如C#熟练所以一直没有机会接触安卓开发.既然需要利用VS2017开发安卓,那么第一步就是了解VS2017 ...
-
常见性能优化策略的总结 good
阅读目录 代码 数据库 缓存 异步 NoSQL JVM调优 多线程与分布式 度量系统(监控.报警.服务依赖管理) 案例一:商家与控制区关系的刷新job 案例二:POI缓存设计与实现 案例三:业务运营后 ...
-
RHEL5.8安装
创建完成后新的虚拟机.使用光盘启动后,启动界面如下图. 大概介绍下显示界面内容的意思: 1.To install or upgrade in graphical mde, press the ...
-
H5 32-百度首页
32-百度首页 新 闻 网 页 贴 吧 知 道 音 乐 图 片 视 频 地 图 百科 文库 hao123 | 更多>> 百度地图带你吃喝玩乐,全心全意为人民服务 把百度设为主页 安装百度卫 ...
-
PHP百杂
PHP实时生成并下载超大数据量的EXCEL文件 PHP错误和异常 PHP异常处理机制 我所理解的php缓冲机制及嵌套级别 $nick = 'test'; //简化输出 echo $nick?:''
-
20155321 《网络攻防》 Exp1 PC平台逆向破解(5)M
20155321 <网络攻防> Exp1 PC平台逆向破解(5)M 实践目标 本次实践的对象是linux的可执行文件 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何 ...