8288分类目录 8288分类目录 8288分类目录
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

再讲mysql 5.7的组提交&发现疑似代码缺陷

来源:本站原创 浏览:78次 时间:2022-09-21

mysql的group commit的概念以及实现很久就出来 ,组提交,即一组事务一起提交?为什么要组提交?是怎么实现组提交的? 组提交跟单个事务提交的区别是什么?当组提交的时候,某个事物要回滚了怎么办?有没有可能出现同一个组提交的事物,因为某个事务commit失败,而导致回滚,该怎么回滚?组提交,是否改变主从同步binlog的粒度? 是否主从同步也按照一个group来进行同步?

上面的诸多问题,亲是否曾在心中也有同样的疑问?下面happypig将通过核心的源码解析来告诉上面这些问题的答案(限于文章篇幅,本篇只解决部分疑问)。同时,在阅读代码的同时,对其中的一段很相当程度的疑惑,貌似处理的不够严谨,不知是否可能引发bug 。所以在文章的最后部分指出,希望大神看到后,能帮忙确认一下并指点一二。

或许很多朋友都知道group commit的核心作用,就是减少sync_binlog的次数,将一组事务的binlog一次性刷新到磁盘。这个是group commit 最最核心的作用。明白了这点,后面的解析将会变得简单。

group commit ,即组提交,所以如何分组就成了核心的内容。该怎么分?

实际上,mysql是用一个队列来进行分组的。本质上,事物提交依然是串行。

下面来讲mysql是如何进行事务分组的。

首先来看从网上找来的一张图,原来地址 “http://www.cnblogs.com/cchust/p/4439107.html“, 图形简单明了。但要了解详细细节,建议还是继续看happypig的源码解析。


mysql的group commit 概念是在binlog层来实现的,事务提交时,要写binlog,但通过MYSQL_BIN_LOG::orderde_commit的函数,可以实现组提交。

下面该函数的开头部分:



标红的两句:

  thd->get_transaction()->m_flags.pending= true; 初始设置这个要提交的事务的标志为pending .

thd->next_to_commit= NULL;  这是指向一个线程的指针,指向下一个要提交事务的线程。初始值为null.  估计亲已经猜到,这个next_to_commit的指针跟group commit 很有关系。


接着往下看:

我们知道,事物提交的第一步动作就是将线程的binlog cache  刷新到binlog  file的cache .

而下面change_stage(thd, Stage_manager::FLUSH_STAGE, thd, NULL, &LOCK_log)  函数的作用就是将该线程排队, 在flush_stage阶段排队。




真正实现排队的函数如下, 也就是上面标红的函数,(当然,下面的mysql_mutex_lock(enter_mutex)也很重要,其他线程执行到这步时,必须等待持有该锁的其他线程释放该锁,何时释放该锁咱们这次不展开,也就意味着,线程之间,在这个函数的这一步是无法并行的) 下面我们来看enroll_for函数的代码:


(上面的代码是在源码的基础上被作者剔除了非必需的部分):

第一个标红的行: bool leader= m_queue[stage].append(thd);

该行的作用是将线程加入到 m_queue[stage] 队列里面。在此步骤,就是m_queue[FLUSH_STAGE]的队列里面,并返回该线程是否是在队列的头部。 处于队列的头部的前提条件是:当该线程加入的时候,该队列已是一个空队列。 也就意味是一个新的分组,并且该线程leader这个分组。

 接着往下看:

   if ( ! leader) , 即如果该线程没有被放置在队列m_queue[stage] 的头部,则执行下面的内容:  

 while (thd->get_transaction()->m_flags.pending)

      mysql_cond_wait(&m_cond_done, &m_lock_done);

 

   在文章的开头部分,我们就已经说明要提交的事物的pending标志初始值为true. 所以该标志没有其他线程将其设置为false之前,while条件成立,然后进入mysql_cond_wait(&m_cond_done, &m_lock_done);该函数的作用就是将该线程去“睡大觉“,等待被别的线程唤醒。 但何时被唤醒------当这个分组的leader线程将它的事物提交之后,再将它唤醒。

       也就是,一个分组的事务,都是被leader线程去提交的,其他的线程都在”睡大觉”,等待leader线程来帮它执行事务提交。 我们来看看change_stage函数的源码注释吧,change_stage的函数是Stage_manager::enroll_for ()的父函数。



  - Atomically enqueueing a queue of processes (which is just one for

    the first phase).

自动将线程排队。


 - If the queue was empty, the thread is the leader for that stage

    and it should process the entire queue for that stage.

如果队列为空,则该线程就是leader , 他会处理整个队列的线程的事物。


  - If the queue was not empty, the thread is a follower and can go

    waiting for the commit to finish

如果队列不会空,则该线程就是这个队列的follower, 然后该线程可以去“睡觉”,等待leader线程将该线程的事物提交完成。


当线程排队之后,后续的步骤都按照该分组的队列顺序执行,在此不再展开。


当线程进入到flush队列之后,该线程(自己睡觉)的binlog cache后续就会被所属队列的leader线程刷新到 binlog file的cache,  也就是函数process_flush_stage_queue的作用。 该函数如下:


我们来解析一下该函数:

第一步:  设置flush_error的初始值为1

第二步:THD *first_seen= stage_manager.fetch_queue_for(Stage_manager::FLUSH_STAGE); 该函数的作用是取出FLUSH_STAGE 队列的leader线程,然后该m_queue[FLUSH_STAGE]队列清空,清空之后,第一个新进来的线程将作为新的分组的leader .

第三步: ha_flush_logs(NULL, true); 存储引擎innodb 刷新redo log,确保事务在存储引擎层物理提交。

第四步:利用for循环将分组中线程逐个取出,然后将该线程的binlog cache刷新到binlog file的cache.

 for (THD *head= first_seen ; head ; head = head->next_to_commit)

  {

    std::pair<int,my_off_t> result= flush_thread_caches(head);

    total_bytes+= result.second;

    if (flush_error == 1)

      flush_error= result.first;

  }

正是上面的代码,happypig有点疑问? 因为flush_error的初始值为1,所以第一轮循环的时候,会执行flush_error= result.first; 也就是将flush_thread_caches(head)函数返回的错误值赋值给 flush_error,如果对第一个线程执行flush_thread_caches()函数返回的结果为0, 而对第二个线程执行flush_thread_caches()返回的值是1, 但最终的flush_error 却是0 。而该函数是flush_error 作为返回值。 该值并没有代表同一个分组的所有的thread的flush 该线程binlog cache的结果。

     该段代码是否会存在问题? 如有大神看到,请大神确认与赐教。

     另外,在说一下happypig的另外一个猜想-------为什么mysql的开发者写这段代码时,只取了第一个线程的刷新结果作为整个分组的线程的flush cache的结果?原因如下:

     1。开发者认为第一个线程刷新成功,就意味着后面的线程也会刷新成功,因为不成功,则意味着mysql的线程出问题,或者binlog file的cache出问题,意味着机器宕机,所以线程也就无法继续往下走,整组事务都无法提交。

     2。其他的想法,太大胆,不说了。。。。哈哈。。。。。。。


  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net