[MySQL 5.6] MySQL 5.6 group commit 性能测试及内部实现流程

http://mysqllover.com/?p=581

尽管Mariadb以及Facebook在long long time ago就fix掉了这个臭名昭著的问题,但官方直到 MySQL5.6 版本才Fix掉,本文主要关注三点:

1.MySQL 5.6的性能如何

2.在5.6中Group commit的三阶段实现流程

binlog和innodb提交过程,内部xa事务,先写redo log再写binlog,任何一个环节失败,都会回滚事务,保证binlog和redo log一致

http://www.cnblogs.com/MYSQLZOUQI/p/5431472.html

从库比主库多数据 ,主库挂了,写binlog成功从库也应用了binlog,主库起来后回滚数据导致从库比主库多数据 ,原因就是先写redo log再写binlog

http://www.cnblogs.com/MYSQLZOUQI/p/5596590.html

新参数

MySQL 5.6提供了两个参数来控制binlog group commit:

binlog_max_flush_queue_time

单位为微妙,用于从flush队列中取事务的超时时间,这主要是防止并发事务过高,导致某些事务的RT上升。

可以阅读函数MYSQL_BIN_LOG::process_flush_stage_queue 来理解其功能

binlog_order_commits

当设置为0时,事务可能以和binlog不相同的顺序被提交,从下面的测试也可以看出,这会稍微提升点性能,但并不是特别明显.

性能测试

老规矩,先测试看看性能

sysbench, 全内存操作,5个sbtest表,每个表1000000行数据

基本配置:

innodb_flush_log_at_trx_commit=1

table_open_cache_instances=5

metadata_locks_hash_instances = 32

metadata_locks_cache_size=2048

performance_schema_instrument = ‘%=on’

performance_schema=ON

innodb_lru_scan_depth=8192

innodb_purge_threads = 4

关闭Performance Schema consumer:

mysql> update setup_consumers set ENABLED = ‘NO’;

Query OK, 4 rows affected (0.02 sec)

Rows matched: 12  Changed: 4  Warnings: 0

sysbench/sysbench –debug=off –test=sysbench/tests/db/update_index.lua  –oltp-tables-count=5  –oltp-point-selects=0 –oltp-table-size=1000000 –num-threads=1000 –max-requests=10000000000 –max-time=7200 –oltp-auto-inc=off –mysql-engine-trx=yes –mysql-table-engine=innodb  –oltp-test-mod=complex –mysql-db=test   –mysql-host=$HOST –mysql-port=3306 –mysql-user=xx run

update_index.lua

threads sync_binlog = 0 sync_binlog = 1 sync_binlog =1binlog_order_commits=0
1  900  610  620
20 13,800 7,000 7,400
60 20,000 14,500 16,000
120 25,100 21,054 23,000
200 27,900 25,400 27,800
400 33,100 30,700 31,300
600 32,800 31,500 29,326
1000 20,400 20,200 20,500

我的机器在压到1000个并发时,CPU已经几乎全部耗完。

可以看到,并发度越高,group commit的效果越好,在达到600以上并发时,设置sync_binlog=1或者0已经没有TPS的区别。

但问题是。我们的业务压力很少会达到这么高的压力,低负载下,设置sync_binlog=1依旧增加了单个线程的开销。

另外也观察到,设置binlog_max_flush_queue_time对TPS的影响并不明显。

实现原理

我们知道,binlog和innodb在5.1及以后的版本中采用类似两阶段提交的方式,关于group commit问题的前世今生,可以阅读MATS的博客,讲述的非常详细。嗯,评论也比较有意思。。。。。

以下集中在5.6中binlog如何做group commit。在5.6中,将binlog的commit阶段分为三个阶段:flush stage、sync stage以及commit stage。5.6的实现思路和Mariadb的思路类似,都是维护一个队列,第一个进入该队列的作为leader线程,否则作为follower线程。leader线程收集follower的事务,并负责做sync,follower线程等待leader通知操作完成。

这三个阶段中,每个阶段都会去维护一个队列:

Mutex_queue m_queue[STAGE_COUNTER];

不同session的THD使用the->next_to_commit来链接,实际上,在如下三个阶段,尽管维护了三个队列,但队列中所有的THD实际上都是通过next_to_commit连接起来了。

在binlog的XA_COMMIT阶段(MYSQL_BIN_LOG::commit),完成事务的最后一个xid事件后,,这时候会进入MYSQL_BIN_LOG::ordered_commit,开始3个阶段的流程:

###flush stage

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

|–>stage_manager.enroll_for(stage, queue, leave_mutex) //将当前线程加入到m_queue[FLUSH_STAGE]中,如果是队列的第一个线程,就被设置为leader,否则就是follower线程,线程会这其中睡眠,直到被leader唤醒(m_cond_done)

|–>leader线程持有LOCK_log锁,从change_state线程返回false.

flush_error= process_flush_stage_queue(&total_bytes, &do_rotate, &wait_queue); //只有leader线程才会进入这个逻辑

|–>首先读取队列,直到队列为空,或者超时(超时时间是通过参数binlog_max_flush_queue_time来控制)为止,对读到的每个线程做flush_thread_caches,将binlog刷到cache中。注意在出队列的时候,可能还有新的session被append到队列中,设置超时的目的也正在于此

|–>如果是超时,这时候队列中还有session的话,就取出整个队列的头部线程,并将原队列置空(fetch_queue_for),然后对取出的session进行flush_thread_caches

|–>判断总的写入binlog的byte数是否超过max bin log size,如果超过了,就设置rotate标记

flush_error= flush_cache_to_file(&flush_end_pos);

|–>将I/O Cache中的内容写到文件中

signal_update()  //通知dump线程有新的Binlog

###sync stage

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

|–>stage_manager.enroll_for(stage, queue, leave_mutex)  //当前线程加入到m_queue[SYNC_STAGE]队列中,释放lock_log锁;同样的如果是SYNC_STAGE队列的leader,则立刻返回,否则进行condition wait.

|–>leader线程加上Lock_sync锁

final_queue= stage_manager.fetch_queue_for(Stage_manager::SYNC_STAGE);  //从SYNC_STAGE队列中取出来,并清空队列,主要用于commit阶段

std::pair<bool, bool> result= sync_binlog_file(false);  //刷binlog 文件(如果设置了sync_binlog的话)

简单的理解就是,在flush stage阶段形成N批的组session,在SYNC阶段又会由这N批组产生出新的leader来负责做最耗时的sync操作

###commit stage

commit阶段受到参数binlog_order_commits限制

当binlog_order_commits关闭时,直接unlock LOCK_sync,由各个session自行进入Innodb commit阶段(随后调用的finish_commit(thd)),这样不会保证binlog和事务commit的顺序一致,如果你不关注innodb的ibdata中记录的binlog信息,那么可以关闭这个选项来稍微提高点性能

当打开binlog_order_commits时,才会进入commit stage,如下描述的

change_stage(thd, Stage_manager::COMMIT_STAGE,final_queue, &LOCK_sync, &LOCK_commit)

|–>进入新的COMMIT_STAGE队列,释放LOCK_sync锁,新的leader获取LOCK_commit锁,其他的session等待

THD *commit_queue= stage_manager.fetch_queue_for(Stage_manager::COMMIT_STAGE);  //取出并清空COMMIT_STAGE队列

process_commit_stage_queue(thd, commit_queue, flush_error)

|–>这里会遍历所有的线程,然后调用ha_commit_low->innobase_commit进入innodb层依次提交

完成上述步骤后,解除LOCK_commit锁

stage_manager.signal_done(final_queue);

|–>将所有Pending的线程的标记置为false(thd->transaction.flags.pending= false)并做m_cond_done广播,唤醒pending的线程

(void) finish_commit(the);  //如果binlog_order_commits设置为FALSE,就会进入这一步来提交存储引擎层事务; 另外还会更新grid信息

Innodb的group commit和mariadb的类似,都只有两次sync,即在prepare阶段sync,以及sync Binlog文件(双一配置),为了保证rotate时,所有前一个binlog的事件的redo log都被刷到磁盘,会在函数new_file_impl中调用如下代码段: if (DBUG_EVALUATE_IF(“expire_logs_always”, 0, 1) && (error= ha_flush_logs(NULL))) goto end;

ha_flush_logs 会调用存储引擎接口刷日志文件

参考文档

http://dimitrik.free.fr/blog/archives/2012/06/mysql-performance-binlog-group-commit-in-56.html

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

MySQL 5.6.10 source code

原创文章,转载请注明: 转载自Simple Life

本文链接地址: [MySQL 5.6] MySQL 5.6 group commit 性能测试及内部实现流程

[MySQL 5.6] MySQL 5.6 group commit 性能测试及内部实现流程的更多相关文章

  1. MySQL 组提交(group commit)

    目录 前言 改进 原理 实现 参数 注意 前言 操作系统使用页面缓存来填补内存和磁盘访问的差距 对磁盘文件的写入会先写入道页面缓存中 由操作系统来决定何时将修改过的脏页刷新到磁盘 确保修改已经持久化到 ...

  2. [MySQL] Group Commit理解

    简单的方法理解MySQL Group Commit原理 一个摆渡将乘客从A点传输到B点 MySQL 5.0 行为 在MySQL 5.0中,摆渡会在A点按顺序搭载乘客,并且传送到B点.A点和B点的来回行 ...

  3. MySQL组提交(group commit)

    MySQL组提交(group commit) 前提: 以下讨论的前提 是设置MySQL的crash safe相关参数为双1: sync_binlog=1 innodb_flush_log_at_trx ...

  4. mysql 数据操作 单表查询 group by 分组 目录

    mysql 数据操作 单表查询 group by 介绍 mysql 数据操作 单表查询 group by 聚合函数 mysql 数据操作 单表查询 group by 聚合函数 没有group by情况 ...

  5. mysql 数据操作 单表查询 group by 聚合函数

    强调: 如果我们用unique的字段作为分组的依据,则每一条记录自成一组,这种分组没有意义 多条记录之间的某个字段值相同,该字段通常用来作为分组的依据 如果按照每个字段都是唯一的进行分组,意味着按照这 ...

  6. Mysql 单表查询-排序-分页-group by初识

    Mysql 单表查询-排序-分页-group by初识 对于select 来说, 分组聚合(((group by; aggregation), 排序 (order by** ), 分页查询 (limi ...

  7. Mysql数据库版本高低引起的group by问题

    低版本的Mysql,group by限制性比较小,在进行group by时,select的对象可包含多个,但是换成高版本5.6以上好像,使用group by 以后,select的对象必须也已经被聚合, ...

  8. Group Commit of Binary Log

    160222 09:19:26 mysqld_safe Starting mysqld daemon with databases from /data01/mysql 2016-02-22 09:1 ...

  9. [mysql使用(2)] mysql的一些语法与Oracle的差别

    一.表空间 mysql的表空间有共享表空间和独占表空间,独占表空间,其实就是一张表一个表空间,其实也就是一张表一个数据文件,共享表空间似乎有点类似oracle的表空间,不同的表可以保存在同一个数据文件 ...

随机推荐

  1. 中间件系列三 RabbitMQ之交换机的四种类型和属性

    概述本文介绍RabbitMQ中交换机类型和属性,主要内容如下: 交换机的作用交换机的类型:Direct exchange(直连交换机).Fanout exchange(扇型交换机).Topic exc ...

  2. git怎么使用

    1_创建一个git服务器 2_开发人员小A从服务器拉取代码 3_小A提交代码 4_小c拉取代码 5_小a现在的代码 6_小c改变了小a的代码 7_小c将变更提交一下 8_小a拉取服务器的代码 9_小A ...

  3. jquery-json 插件使用方法

    var thing = { plugin: 'jquery-json', version: 2.4 }; var encoded = $.toJSON( thing ); // '{"plu ...

  4. libevent安装方法

    安装FastDFS之前,先安装libevent工具包,记录一下安装过程 1.检查:ls -al /usr/lib | grep libevent 查看是否已安装,如果已安装且版本低于1.3,则先通过: ...

  5. ldap 配置过程详解

    ldap常用名称解释 1.环境搭建 操作系统:centos6.5 x86_64关闭防火墙.selinux开启时间同步# crontab -e加入# time sync*/5 * * * * /usr/ ...

  6. UVA 1335 Beijing Guards(二分答案)

    入口: https://cn.vjudge.net/problem/UVA-1335 [题意] 有n个人为成一个圈,其中第i个人想要r[i]种不同的礼物,相邻的两个人可以聊天,炫耀自己的礼物.如果两个 ...

  7. 替换linux系统文件etc下passwd文件的字段获取真正的root权限

    sudo与root 很多人都知道使用linux可以利用sudo来执行一些root权限执行的事情,但是sudo和root还是有很大的区别的. 区别一:sudo可以执行的命令是root账户利用/etc/s ...

  8. facebook login issue

    If enable the facebook account in settings, when change account can't open the session. -(void)fbRes ...

  9. Modelsim SE 仿真 ALTERA FPGA IP

    Modelsim SE 仿真 ALTERA FPGA IP 最近,有几个朋友问过我是不是有新版本的Modelsim altera,其原因是 Qii 升级为新版本的,但是没配套的modelsim,没办法 ...

  10. angular开发控制器之间的通信

    一.指令与控制器之间通信,无非是以下几种方法: 基于scope继承的方式 基于event传播的方式 service的方式(单例模式) 二.基于scope继承的方式: 最简单的让控制器之间进行通信的方法 ...