美文网首页
MySQL:Multi-threaded slave stati

MySQL:Multi-threaded slave stati

作者: 重庆八怪 | 来源:发表于2021-03-15 17:59 被阅读0次

    一、问题来源

    这个问题如下:


    image.png

    朋友也分析了binlog发现并没有大事务的存在,且从库压力很小很小。下面我们稍微再来分析一下。

    二、以往的说明

    • “Waiting for dependent transaction to commit”

    由于协调线程判定本事务由于last commit大于current_lwm因此不能并行回放,协调线程处于等待,大事务会加剧这种情况。

    • “Waiting for slave workers to process their queues”

    由于没有空闲的工作线程,协调线程会等待。这种情况说明理论上的并行度是理想的,但是可能是参数slave_parallel_workers设置不够。当然设置工作线程的个数应该和服务器的配置和负载相结合考虑,因为第29节我们会看到线程是CPU调度最小的单位。

    • “Waiting for Slave Worker queue”

    由于工作线程的任务队列已满,协调线程会等待。这种情况前面说过是由于一个事务包含了过多的Event并且工作线程应用Event的速度赶不上协调线程分配Event的速度,导致了积压并且超过了16384个Event。

    另外实际上还有一种等待如下:
    “Waiting for Slave Workers to free pending events”:由所谓的‘big event’造成的,什么是‘big event’呢,源码中描述为:event size is greater than slave_pending_jobs_size_max but less than slave_max_allowed_packet。我个人认为出现的可能性不大,因此没做过多考虑。可以在函数append_item_to_jobs中找到答案。

    我们下面对应日志中的输出进行详细解释,如下:

    指标 解释
    seconds elapsed 整个分配过程消耗的时间,单位秒,超过120秒会出现这个日志。
    events assigned 本工作线程分配的Event数量。
    worker queues filled over overrun level 本工作线程任务队列中Event个数大于90%的次数。当前硬编码大于14746。
    waited due a Worker queue full 本工作线程任务队列已满的次数。当前硬编码大于16384。和前面第三点对应。
    waited due the total size ‘big event’的出现的次数。
    waited at clock conflicts 由于不能并行回放,协调线程等待的时间,单位纳秒。和前面第一点对应。
    waited (count) when Workers occupied 由于没有空闲的工作线程而等待的次数。对应前面第二点。
    waited when Workers occupied 由于没有空闲的工作线程而等待的时间。对应前面第二点。

    三、特殊场景说明

    我们这里看到waited at clock conflict比较大,这是一个累计值,来自rli.mts_total_wait_overlap,单位为纳秒,但是由于是累计值可参考性并不是那么强,只能做一个整体的把控。具体的简化代码如下:

        set_timespec_nsec(&ts[0], 0);//设置开始时间
    
        thd->ENTER_COND(&rli->logical_clock_cond, &rli->mts_gaq_LOCK,
                        &stage_worker_waiting_for_commit_parent, &old_stage); 
        do
        {
          mysql_cond_wait(&rli->logical_clock_cond, &rli->mts_gaq_LOCK);
        }
        while ((!rli->info_thd->killed && !is_error) &&
               !clock_leq(last_committed_arg, estimate_lwm_timestamp()));//一直等待直到last_commit<= estimate_lwm_timestamp
        thd->EXIT_COND(&old_stage);
        set_timespec_nsec(&ts[1], 0);//设置结束时间
        my_atomic_add64(&rli->mts_total_wait_overlap, diff_timespec(&ts[1], &ts[0])); //相减得到等待市场,加入到rli->mts_total_wait_overlap中
    
    

    而超过120秒,实际上这里做了简化,更加精确的含义为,如果协调线程1024个event分配的时间大于了120秒则会出现这个警告。那么问题来了,说明时候协调线程的分配1024个event会大于120秒呢?那么显然有2种情况

    • 从库worker线程压力较大,也就是以往的说明中描述的这些情况。
    • 还有一种特殊的情况就是本来库的压力就很小,在120秒内没有1024个event生成。

    我们知道一个常规的小事务通常为 gitd event、query event、map event、dml event、xid event 5 个组成,那么1024event大概就是205个事务,换句话说如果主库压力过小,2分钟之内连205个事务都没有也会触发这个警告。

    简单看看判断标准也是非常的简单:

          if (rli->is_parallel_exec() && rli->mts_events_assigned % 1024 == 1) //这里就是进入判断的前提条件
          {
            time_t my_now= my_time(0);
    
            if ((my_now - rli->mts_last_online_stat) >=
                mts_online_stat_period)//大于2分钟
    

    这可以说是两种极端,出现这个日志报告,要么是压力太大(忙死)、要么是压力太小(闲死)。

    四、测试

    测试很简单,我们就在主库慢慢的执行200来个事务一定会超过2分钟,那么从库的MTS当每分配到1024个event的时候必然进入判定流程,日志输出如下:

    2021-03-15T08:38:23.676061Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 62849ms. The settings might not be optimal. (flushed=0, during the time.)
    2021-03-15T08:38:23.696028Z 15 [Note] Multi-threaded slave statistics for channel '': seconds elapsed = 870; events assigned = 2049; worker queues filled over overrun level = 0; waited due a Worker queue full = 0; waited due the total size = 0; waited at clock conflicts = 0 waited (count) when Workers occupied = 0 waited when Workers occupied = 0
    4872              rli->mts_last_online_stat= my_now;
    (gdb) 
    4880      set_timespec_nsec(&rli->ts_exec[1], 0);
    (gdb) c
    Continuing.
    
    Breakpoint 6, apply_event_and_update_pos (ptr_ev=0x7fffd71ac880, thd=0x7fffcc000ab0, rli=0x7fff9002ef20) at /opt/percona-server-locks-detail-5.7.22/sql/rpl_slave.cc:4850
    4850            if ((my_now - rli->mts_last_online_stat) >=
    (gdb) n
    4871                                    rli->mts_total_wait_worker_avail);
    (gdb) p my_now
    $10 = 1615799283
    (gdb) p rli->mts_last_online_stat
    $11 = 1615797440
    (gdb) n
    4864                                    (my_now - rli->mts_last_online_stat),
    (gdb) n
    4871                                    rli->mts_total_wait_worker_avail);
    (gdb) n
    4862                                    rli->get_for_channel_str(),
    (gdb) n
    4871                                    rli->mts_total_wait_worker_avail);
    (gdb) n
    2021-03-15T09:08:21.325551Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 17962ms. The settings might not be optimal. (flushed=0, during the time.)
    2021-03-15T09:08:21.327019Z 15 [Note] Multi-threaded slave statistics for channel '': seconds elapsed = 1843; events assigned = 3073; worker queues filled over overrun level = 0; waited due a Worker queue full = 0; waited due the total size = 0; waited at clock conflicts = 14903300 waited (count) when Workers occupied = 0 waited when Workers occupied = 0
    4872              rli->mts_last_online_stat= my_now;
    
    

    这个日志中我们发现有两个[Note] Multi-threaded slave statistics for channel '':的日志,而3073 - 2049也等于1024,也可以看到有一次的econds elapsed为1843,这是因为我中间去干其他活去了,主库很久都没动,这典型的属于闲死。
    可以看到我们闲死的结论得到证明。当然是闲死还是忙死,还是根据从库woker线程的压力进行判断,忙死的情况下这种日志报告还是有一定参考意义的。但是闲死的情况下就没有什么意义了忽略就是了。

    相关文章

      网友评论

          本文标题:MySQL:Multi-threaded slave stati

          本文链接:https://www.haomeiwen.com/subject/lhokcltx.html